Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4SPSPosDistribution.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// G4SPSPosDistribution class implementation
27//
28// Author: Fan Lei, QinetiQ ltd. - 05/02/2004
29// Customer: ESA/ESTEC
30// Revisions: Andrea Dotti, John Allison, Makoto Asai, Maxime Chauvin
31// --------------------------------------------------------------------
32
34
36#include "Randomize.hh"
38#include "G4VPhysicalVolume.hh"
40#include "G4AutoLock.hh"
41#include "G4AutoDelete.hh"
42
43G4SPSPosDistribution::thread_data_t::thread_data_t()
44{
45 CSideRefVec1 = G4ThreeVector(CLHEP::HepXHat);
46 CSideRefVec2 = G4ThreeVector(CLHEP::HepYHat);
47 CSideRefVec3 = G4ThreeVector(CLHEP::HepZHat);
48 CParticlePos = G4ThreeVector(0,0,0);
49}
50
52{
53 SourcePosType = "Point";
54 Shape = "NULL";
55 CentreCoords = G4ThreeVector(0,0,0);
56 Rotx = CLHEP::HepXHat;
57 Roty = CLHEP::HepYHat;
58 Rotz = CLHEP::HepZHat;
59 halfx = 0.;
60 halfy = 0.;
61 halfz = 0.;
62 Radius = 0.;
63 Radius0 = 0.;
64 SR = 0.;
65 SX = 0.;
66 SY = 0.;
67 ParAlpha = 0.;
68 ParTheta = 0.;
69 ParPhi = 0.;
70 VolName = "NULL";
71 verbosityLevel = 0 ;
72 G4MUTEXINIT(a_mutex);
73}
74
76{
77 G4MUTEXDESTROY(a_mutex);
78}
79
81{
82 SourcePosType = PosType;
83}
84
86{
87 Shape = shapeType;
88}
89
91{
92 CentreCoords = coordsOfCentre;
93}
94
96{
97 // This should be x'
98
99 Rotx = posrot1;
100 if(verbosityLevel == 2)
101 {
102 G4cout << "Vector x' " << Rotx << G4endl;
103 }
104 GenerateRotationMatrices();
105}
106
108{
109 // This is a vector in the plane x'y' but need not be y'
110
111 Roty = posrot2;
112 if(verbosityLevel == 2)
113 {
114 G4cout << "The vector in the x'-y' plane " << Roty << G4endl;
115 }
116 GenerateRotationMatrices();
117}
118
120{
121 halfx = xhalf;
122}
123
125{
126 halfy = yhalf;
127}
128
130{
131 halfz = zhalf;
132}
133
135{
136 Radius = rds;
137}
138
140{
141 Radius0 = rds;
142}
143
145{
146 SX = SY = r;
147 SR = r;
148}
149
151{
152 SX = r;
153}
154
156{
157 SY = r;
158}
159
161{
162 ParAlpha = paralp;
163}
164
166{
167 ParTheta = parthe;
168}
169
171{
172 ParPhi = parphi;
173}
174
176{
177 return SourcePosType;
178}
179
181{
182 return Shape;
183}
184
186{
187 return CentreCoords;
188}
189
191{
192 return halfx;
193}
194
196{
197 return halfy;
198}
199
201{
202 return halfz;
203}
204
206{
207 return Radius;
208}
209
211{
212 G4AutoLock l(&a_mutex);
213 PosRndm = a;
214}
215
217{
218 verbosityLevel = a;
219}
220
222{
223 return SourcePosType;
224}
225
227{
228 return ThreadData.Get().CParticlePos;
229}
230
232{
233 return ThreadData.Get().CSideRefVec1;
234}
235
237{
238 return ThreadData.Get().CSideRefVec2;
239}
240
242{
243 return ThreadData.Get().CSideRefVec3;
244}
245
246void G4SPSPosDistribution::GenerateRotationMatrices()
247{
248 // This takes in 2 vectors, x' and one in the plane x'-y',
249 // and from these takes a cross product to calculate z'.
250 // Then a cross product is taken between x' and z' to give y'
251
252 Rotx = Rotx.unit(); // x'
253 Roty = Roty.unit(); // vector in x'y' plane
254 Rotz = Rotx.cross(Roty); // z'
255 Rotz = Rotz.unit();
256 Roty =Rotz.cross(Rotx); // y'
257 Roty =Roty.unit();
258 if(verbosityLevel == 2)
259 {
260 G4cout << "The new axes, x', y', z' "
261 << Rotx << " " << Roty << " " << Rotz << G4endl;
262 }
263}
264
266{
267 VolName = Vname;
268 if(verbosityLevel == 2) { G4cout << VolName << G4endl; }
269
270 if(VolName=="NULL")
271 {
272 if(verbosityLevel >= 1)
273 { G4cout << "Volume confinement is set off." << G4endl; }
274 Confine = false;
275 return;
276 }
277
278 G4VPhysicalVolume* tempPV = nullptr;
280 if(verbosityLevel == 2) { G4cout << PVStore->size() << G4endl; }
281
282 tempPV = PVStore->GetVolume(VolName);
283
284 // the volume exists else it doesn't
285 //
286 if (tempPV != nullptr)
287 {
288 if(verbosityLevel >= 1)
289 {
290 G4cout << "Volume " << VolName << " exists" << G4endl;
291 }
292 Confine = true;
293 }
294 else
295 {
296 G4cout << " **** Error: Volume <" << VolName
297 << "> does not exist **** " << G4endl;
298 G4cout << " Ignoring confine condition" << G4endl;
299 Confine = false;
300 VolName = "NULL";
301 }
302}
303
304void G4SPSPosDistribution::GeneratePointSource(G4ThreeVector& pos)
305{
306 // Generates Points given the point source
307
308 if(SourcePosType == "Point")
309 {
310 pos = CentreCoords;
311 }
312 else
313 {
314 if(verbosityLevel >= 1)
315 {
316 G4cerr << "Error SourcePosType is not set to Point" << G4endl;
317 }
318 }
319}
320
321void G4SPSPosDistribution::GeneratePointsInBeam(G4ThreeVector& pos)
322{
323 G4double x, y, z;
324
325 G4ThreeVector RandPos;
326 G4double tempx, tempy, tempz;
327 z = 0.;
328
329 // Private Method to create points in a plane
330 //
331 if(Shape == "Circle")
332 {
333 x = Radius + 100.;
334 y = Radius + 100.;
335 while(std::sqrt((x*x) + (y*y)) > Radius)
336 {
337 x = PosRndm->GenRandX();
338 y = PosRndm->GenRandY();
339
340 x = (x*2.*Radius) - Radius;
341 y = (y*2.*Radius) - Radius;
342 }
343 x += G4RandGauss::shoot(0.0,SX) ;
344 y += G4RandGauss::shoot(0.0,SY) ;
345 }
346 else
347 {
348 // All other cases default to Rectangle case
349 //
350 x = PosRndm->GenRandX();
351 y = PosRndm->GenRandY();
352 x = (x*2.*halfx) - halfx;
353 y = (y*2.*halfy) - halfy;
354 x += G4RandGauss::shoot(0.0,SX);
355 y += G4RandGauss::shoot(0.0,SY);
356 }
357
358 // Apply Rotation Matrix
359 // x * Rotx, y * Roty and z * Rotz
360 //
361 if(verbosityLevel >= 2)
362 {
363 G4cout << "Raw position " << x << "," << y << "," << z << G4endl;
364 }
365 tempx = (x * Rotx.x()) + (y * Roty.x()) + (z * Rotz.x());
366 tempy = (x * Rotx.y()) + (y * Roty.y()) + (z * Rotz.y());
367 tempz = (x * Rotx.z()) + (y * Roty.z()) + (z * Rotz.z());
368
369 RandPos.setX(tempx);
370 RandPos.setY(tempy);
371 RandPos.setZ(tempz);
372
373 // Translate
374 //
375 pos = CentreCoords + RandPos;
376 if(verbosityLevel >= 1)
377 {
378 if(verbosityLevel >= 2)
379 {
380 G4cout << "Rotated Position " << RandPos << G4endl;
381 }
382 G4cout << "Rotated and Translated position " << pos << G4endl;
383 }
384}
385
386void G4SPSPosDistribution::GeneratePointsInPlane(G4ThreeVector& pos)
387{
388 G4double x, y, z;
389 G4double expression;
390 G4ThreeVector RandPos;
391 G4double tempx, tempy, tempz;
392 x = y = z = 0.;
393 thread_data_t& td = ThreadData.Get();
394
395 if(SourcePosType != "Plane" && verbosityLevel >= 1)
396 {
397 G4cerr << "Error: SourcePosType is not Plane" << G4endl;
398 }
399
400 // Private Method to create points in a plane
401 //
402 if(Shape == "Circle")
403 {
404 x = Radius + 100.;
405 y = Radius + 100.;
406 while(std::sqrt((x*x) + (y*y)) > Radius)
407 {
408 x = PosRndm->GenRandX();
409 y = PosRndm->GenRandY();
410
411 x = (x*2.*Radius) - Radius;
412 y = (y*2.*Radius) - Radius;
413 }
414 }
415 else if(Shape == "Annulus")
416 {
417 x = Radius + 100.;
418 y = Radius + 100.;
419 while(std::sqrt((x*x) + (y*y)) > Radius
420 || std::sqrt((x*x) + (y*y)) < Radius0 )
421 {
422 x = PosRndm->GenRandX();
423 y = PosRndm->GenRandY();
424
425 x = (x*2.*Radius) - Radius;
426 y = (y*2.*Radius) - Radius;
427 }
428 }
429 else if(Shape == "Ellipse")
430 {
431 expression = 20.;
432 while(expression > 1.)
433 {
434 x = PosRndm->GenRandX();
435 y = PosRndm->GenRandY();
436
437 x = (x*2.*halfx) - halfx;
438 y = (y*2.*halfy) - halfy;
439
440 expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
441 }
442 }
443 else if(Shape == "Square")
444 {
445 x = PosRndm->GenRandX();
446 y = PosRndm->GenRandY();
447 x = (x*2.*halfx) - halfx;
448 y = (y*2.*halfy) - halfy;
449 }
450 else if(Shape == "Rectangle")
451 {
452 x = PosRndm->GenRandX();
453 y = PosRndm->GenRandY();
454 x = (x*2.*halfx) - halfx;
455 y = (y*2.*halfy) - halfy;
456 }
457 else
458 {
459 G4cout << "Shape not one of the plane types" << G4endl;
460 }
461
462 // Apply Rotation Matrix
463 // x * Rotx, y * Roty and z * Rotz
464 //
465 if(verbosityLevel == 2)
466 {
467 G4cout << "Raw position " << x << "," << y << "," << z << G4endl;
468 }
469 tempx = (x * Rotx.x()) + (y * Roty.x()) + (z * Rotz.x());
470 tempy = (x * Rotx.y()) + (y * Roty.y()) + (z * Rotz.y());
471 tempz = (x * Rotx.z()) + (y * Roty.z()) + (z * Rotz.z());
472
473 RandPos.setX(tempx);
474 RandPos.setY(tempy);
475 RandPos.setZ(tempz);
476
477 // Translate
478 //
479 pos = CentreCoords + RandPos;
480 if(verbosityLevel >= 1)
481 {
482 if(verbosityLevel == 2)
483 {
484 G4cout << "Rotated Position " << RandPos << G4endl;
485 }
486 G4cout << "Rotated and Translated position " << pos << G4endl;
487 }
488
489 // For Cosine-Law make SideRefVecs = to Rotation matrix vectors
490 // Note: these need to be thread-local, use G4Cache
491 //
492 td.CSideRefVec1 = Rotx;
493 td.CSideRefVec2 = Roty;
494 td.CSideRefVec3 = Rotz;
495
496 // If rotation matrix z' point to origin then invert the matrix
497 // So that SideRefVecs point away
498 //
499 if((CentreCoords.x() > 0. && Rotz.x() < 0.)
500 || (CentreCoords.x() < 0. && Rotz.x() > 0.)
501 || (CentreCoords.y() > 0. && Rotz.y() < 0.)
502 || (CentreCoords.y() < 0. && Rotz.y() > 0.)
503 || (CentreCoords.z() > 0. && Rotz.z() < 0.)
504 || (CentreCoords.z() < 0. && Rotz.z() > 0.))
505 {
506 // Invert y and z
507 //
508 td.CSideRefVec2 = - td.CSideRefVec2;
509 td.CSideRefVec3 = - td.CSideRefVec3;
510 }
511 if(verbosityLevel == 2)
512 {
513 G4cout << "Reference vectors for cosine-law "
514 << td.CSideRefVec1<< " " << td.CSideRefVec2
515 << " " << td.CSideRefVec3 << G4endl;
516 }
517}
518
519void G4SPSPosDistribution::GeneratePointsOnSurface(G4ThreeVector& pos)
520{
521 // Private method to create points on a surface
522 //
523 G4double theta, phi;
524 G4double x, y, z;
525 x = y = z = 0.;
526 G4double expression;
527 G4ThreeVector RandPos;
528
529 thread_data_t& td = ThreadData.Get();
530 if(SourcePosType != "Surface" && verbosityLevel >= 1)
531 {
532 G4cout << "Error SourcePosType not Surface" << G4endl;
533 }
534
535 if(Shape == "Sphere")
536 {
537 theta = PosRndm->GenRandPosTheta();
538 phi = PosRndm->GenRandPosPhi();
539 theta = std::acos(1. - 2.*theta); // theta isotropic
540 phi = phi * 2. * pi;
541
542 x = Radius * std::sin(theta) * std::cos(phi);
543 y = Radius * std::sin(theta) * std::sin(phi);
544 z = Radius * std::cos(theta);
545
546 RandPos.setX(x);
547 RandPos.setY(y);
548 RandPos.setZ(z);
549
550 // Cosine-law (not a good idea to use this here)
551 //
552 G4ThreeVector zdash(x,y,z);
553 zdash = zdash.unit();
554 G4ThreeVector xdash = Rotz.cross(zdash);
555 G4ThreeVector ydash = xdash.cross(zdash);
556 td.CSideRefVec1 = xdash.unit();
557 td.CSideRefVec2 = ydash.unit();
558 td.CSideRefVec3 = zdash.unit();
559 }
560 else if(Shape == "Ellipsoid")
561 {
562 G4double minphi, maxphi, middlephi;
563 G4double answer, constant;
564
565 constant = pi/(halfx*halfx) + pi/(halfy*halfy) + twopi/(halfz*halfz);
566
567 // Simplified approach
568 //
569 theta = PosRndm->GenRandPosTheta();
570 phi = PosRndm->GenRandPosPhi();
571
572 theta = std::acos(1. - 2.*theta);
573 minphi = 0.;
574 maxphi = twopi;
575 while(maxphi-minphi > 0.)
576 {
577 middlephi = (maxphi+minphi)/2.;
578 answer = (1./(halfx*halfx))*(middlephi/2. + std::sin(2*middlephi)/4.)
579 + (1./(halfy*halfy))*(middlephi/2. - std::sin(2*middlephi)/4.)
580 + middlephi/(halfz*halfz);
581 answer = answer/constant;
582 if(answer > phi) maxphi = middlephi;
583 if(answer < phi) minphi = middlephi;
584 if(std::fabs(answer-phi) <= 0.00001)
585 {
586 minphi = maxphi +1;
587 phi = middlephi;
588 }
589 }
590
591 // x,y and z form a unit vector. Put this onto the ellipse.
592 //
593 x = std::sin(theta)*std::cos(phi);
594 y = std::sin(theta)*std::sin(phi);
595 z = std::cos(theta);
596
597 G4double lhs;
598
599 // Solve for x
600 //
601 G4double numYinX = y/x;
602 G4double numZinX = z/x;
603 G4double tempxvar;
604 tempxvar = 1./(halfx*halfx)+(numYinX*numYinX)/(halfy*halfy)
605 + (numZinX*numZinX)/(halfz*halfz);
606 tempxvar = 1./tempxvar;
607 G4double coordx = std::sqrt(tempxvar);
608
609 // Solve for y
610 //
611 G4double numXinY = x/y;
612 G4double numZinY = z/y;
613 G4double tempyvar;
614 tempyvar = (numXinY*numXinY)/(halfx*halfx)+1./(halfy*halfy)
615 + (numZinY*numZinY)/(halfz*halfz);
616 tempyvar = 1./tempyvar;
617 G4double coordy = std::sqrt(tempyvar);
618
619 // Solve for z
620 //
621 G4double numXinZ = x/z;
622 G4double numYinZ = y/z;
623 G4double tempzvar;
624 tempzvar = (numXinZ*numXinZ)/(halfx*halfx)
625 + (numYinZ*numYinZ)/(halfy*halfy)+1./(halfz*halfz);
626 tempzvar = 1./tempzvar;
627 G4double coordz = std::sqrt(tempzvar);
628
629 lhs = std::sqrt((coordx*coordx)/(halfx*halfx) +
630 (coordy*coordy)/(halfy*halfy) +
631 (coordz*coordz)/(halfz*halfz));
632
633 if(std::fabs(lhs-1.) > 0.001 && verbosityLevel >= 1)
634 {
635 G4cout << "Error: theta, phi not really on ellipsoid" << G4endl;
636 }
637
638 // coordx, coordy and coordz are all positive
639 //
640 G4double TestRandVar = G4UniformRand();
641 if(TestRandVar > 0.5)
642 {
643 coordx = -coordx;
644 }
645 TestRandVar = G4UniformRand();
646 if(TestRandVar > 0.5)
647 {
648 coordy = -coordy;
649 }
650 TestRandVar = G4UniformRand();
651 if(TestRandVar > 0.5)
652 {
653 coordz = -coordz;
654 }
655
656 RandPos.setX(coordx);
657 RandPos.setY(coordy);
658 RandPos.setZ(coordz);
659
660 // Cosine-law (not a good idea to use this here)
661 //
662 G4ThreeVector zdash(coordx,coordy,coordz);
663 zdash = zdash.unit();
664 G4ThreeVector xdash = Rotz.cross(zdash);
665 G4ThreeVector ydash = xdash.cross(zdash);
666 td.CSideRefVec1 = xdash.unit();
667 td.CSideRefVec2 = ydash.unit();
668 td.CSideRefVec3 = zdash.unit();
669 }
670 else if(Shape == "Cylinder")
671 {
672 G4double AreaTop, AreaBot, AreaLat;
673 G4double AreaTotal, prob1, prob2, prob3;
674 G4double testrand;
675
676 // User giver Radius and z-half length
677 // Calculate surface areas, maybe move this to
678 // a different method
679
680 AreaTop = pi * Radius * Radius;
681 AreaBot = AreaTop;
682 AreaLat = 2. * pi * Radius * 2. * halfz;
683 AreaTotal = AreaTop + AreaBot + AreaLat;
684
685 prob1 = AreaTop / AreaTotal;
686 prob2 = AreaBot / AreaTotal;
687 prob3 = 1.00 - prob1 - prob2;
688 if(std::fabs(prob3 - (AreaLat/AreaTotal)) >= 0.001)
689 {
690 if(verbosityLevel >= 1)
691 {
692 G4cout << AreaLat/AreaTotal << " " << prob3 << G4endl;
693 }
694 G4cout << "Error in prob3" << G4endl;
695 }
696
697 // Decide surface to calculate point on.
698
699 testrand = G4UniformRand();
700 if(testrand <= prob1) // Point on Top surface
701 {
702 z = halfz;
703 x = Radius + 100.;
704 y = Radius + 100.;
705 while(((x*x)+(y*y)) > (Radius*Radius))
706 {
707 x = PosRndm->GenRandX();
708 y = PosRndm->GenRandY();
709
710 x = x * 2. * Radius;
711 y = y * 2. * Radius;
712 x = x - Radius;
713 y = y - Radius;
714 }
715 // Cosine law
716 //
717 td.CSideRefVec1 = Rotx;
718 td.CSideRefVec2 = Roty;
719 td.CSideRefVec3 = Rotz;
720 }
721 else if((testrand > prob1) && (testrand <= (prob1 + prob2)))
722 { // Point on Bottom surface
723 z = -halfz;
724 x = Radius + 100.;
725 y = Radius + 100.;
726 while(((x*x)+(y*y)) > (Radius*Radius))
727 {
728 x = PosRndm->GenRandX();
729 y = PosRndm->GenRandY();
730
731 x = x * 2. * Radius;
732 y = y * 2. * Radius;
733 x = x - Radius;
734 y = y - Radius;
735 }
736 // Cosine law
737 //
738 td.CSideRefVec1 = Rotx;
739 td.CSideRefVec2 = -Roty;
740 td.CSideRefVec3 = -Rotz;
741 }
742 else if(testrand > (prob1+prob2)) // Point on Lateral Surface
743 {
744 G4double rand;
745
746 rand = PosRndm->GenRandPosPhi();
747 rand = rand * 2. * pi;
748
749 x = Radius * std::cos(rand);
750 y = Radius * std::sin(rand);
751
752 z = PosRndm->GenRandZ();
753
754 z = z * 2. *halfz;
755 z = z - halfz;
756
757 // Cosine law
758 //
759 G4ThreeVector zdash(x,y,0.);
760 zdash = zdash.unit();
761 G4ThreeVector xdash = Rotz.cross(zdash);
762 G4ThreeVector ydash = xdash.cross(zdash);
763 td.CSideRefVec1 = xdash.unit();
764 td.CSideRefVec2 = ydash.unit();
765 td.CSideRefVec3 = zdash.unit();
766 }
767 else
768 {
769 G4cout << "Error: testrand " << testrand << G4endl;
770 }
771
772 RandPos.setX(x);
773 RandPos.setY(y);
774 RandPos.setZ(z);
775 }
776 else if(Shape == "EllipticCylinder")
777 {
778 G4double AreaTop, AreaBot, AreaLat, AreaTotal;
779 G4double h;
780 G4double prob1, prob2, prob3;
781 G4double testrand;
782
783 // User giver x, y and z-half length
784 // Calculate surface areas, maybe move this to
785 // a different method
786
787 AreaTop = pi * halfx * halfy;
788 AreaBot = AreaTop;
789
790 // Using circumference approximation by Ramanujan (order h^3)
791 // AreaLat = 2*halfz * pi*( 3*(halfx + halfy)
792 // - std::sqrt((3*halfx + halfy) * (halfx + 3*halfy)) );
793 // Using circumference approximation by Ramanujan (order h^5)
794 //
795 h = ((halfx - halfy)*(halfx - halfy)) / ((halfx + halfy)*(halfx + halfy));
796 AreaLat = 2*halfz * pi*(halfx + halfy)
797 * (1 + (3*h)/(10 + std::sqrt(4 - 3*h)));
798 AreaTotal = AreaTop + AreaBot + AreaLat;
799
800 prob1 = AreaTop / AreaTotal;
801 prob2 = AreaBot / AreaTotal;
802 prob3 = 1.00 - prob1 - prob2;
803 if(std::fabs(prob3 - (AreaLat/AreaTotal)) >= 0.001)
804 {
805 if(verbosityLevel >= 1)
806 {
807 G4cout << AreaLat/AreaTotal << " " << prob3 << G4endl;
808 }
809 G4cout << "Error in prob3" << G4endl;
810 }
811
812 // Decide surface to calculate point on
813
814 testrand = G4UniformRand();
815 if(testrand <= prob1) // Point on Top surface
816 {
817 z = halfz;
818 expression = 20.;
819 while(expression > 1.)
820 {
821 x = PosRndm->GenRandX();
822 y = PosRndm->GenRandY();
823
824 x = (x * 2. * halfx) - halfx;
825 y = (y * 2. * halfy) - halfy;
826
827 expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
828 }
829 }
830 else if((testrand > prob1) && (testrand <= (prob1 + prob2)))
831 { // Point on Bottom surface
832 z = -halfz;
833 expression = 20.;
834 while(expression > 1.)
835 {
836 x = PosRndm->GenRandX();
837 y = PosRndm->GenRandY();
838
839 x = (x * 2. * halfx) - halfx;
840 y = (y * 2. * halfy) - halfy;
841
842 expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
843 }
844 }
845 else if(testrand > (prob1+prob2)) // Point on Lateral Surface
846 {
847 G4double rand;
848
849 rand = PosRndm->GenRandPosPhi();
850 rand = rand * 2. * pi;
851
852 x = halfx * std::cos(rand);
853 y = halfy * std::sin(rand);
854
855 z = PosRndm->GenRandZ();
856
857 z = (z * 2. * halfz) - halfz;
858 }
859 else
860 {
861 G4cout << "Error: testrand " << testrand << G4endl;
862 }
863
864 RandPos.setX(x);
865 RandPos.setY(y);
866 RandPos.setZ(z);
867
868 // Cosine law
869 //
870 G4ThreeVector zdash(x,y,z);
871 zdash = zdash.unit();
872 G4ThreeVector xdash = Rotz.cross(zdash);
873 G4ThreeVector ydash = xdash.cross(zdash);
874 td.CSideRefVec1 = xdash.unit();
875 td.CSideRefVec2 = ydash.unit();
876 td.CSideRefVec3 = zdash.unit();
877 }
878 else if(Shape == "Para")
879 {
880 // Right Parallelepiped.
881 // User gives x,y,z half lengths and ParAlpha
882 // ParTheta and ParPhi
883 // +x = <1, -x >1 & <2, +y >2 & <3, -y >3 &<4
884 // +z >4 & < 5, -z >5 &<6
885
886 G4double testrand = G4UniformRand();
887 G4double AreaX = halfy * halfz * 4.;
888 G4double AreaY = halfx * halfz * 4.;
889 G4double AreaZ = halfx * halfy * 4.;
890 G4double AreaTotal = 2*(AreaX + AreaY + AreaZ);
891 G4double Probs[6];
892 Probs[0] = AreaX/AreaTotal;
893 Probs[1] = Probs[0] + AreaX/AreaTotal;
894 Probs[2] = Probs[1] + AreaY/AreaTotal;
895 Probs[3] = Probs[2] + AreaY/AreaTotal;
896 Probs[4] = Probs[3] + AreaZ/AreaTotal;
897 Probs[5] = Probs[4] + AreaZ/AreaTotal;
898
899 x = PosRndm->GenRandX();
900 y = PosRndm->GenRandY();
901 z = PosRndm->GenRandZ();
902
903 x = x * halfx * 2.;
904 x = x - halfx;
905 y = y * halfy * 2.;
906 y = y - halfy;
907 z = z * halfz * 2.;
908 z = z - halfz;
909
910 // Pick a side first
911 //
912 if(testrand < Probs[0])
913 {
914 // side is +x
915
916 x = halfx + z*std::tan(ParTheta)*std::cos(ParPhi) + y*std::tan(ParAlpha);
917 y = y + z*std::tan(ParTheta)*std::sin(ParPhi);
918 // z = z;
919
920 // Cosine-law
921 //
922 G4ThreeVector xdash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
923 halfz*std::tan(ParTheta)*std::sin(ParPhi),
924 halfz/std::cos(ParPhi));
925 G4ThreeVector ydash(halfy*std::tan(ParAlpha), -halfy, 0.0);
926 xdash = xdash.unit();
927 ydash = ydash.unit();
928 G4ThreeVector zdash = xdash.cross(ydash);
929 td.CSideRefVec1 = xdash.unit();
930 td.CSideRefVec2 = ydash.unit();
931 td.CSideRefVec3 = zdash.unit();
932 }
933 else if(testrand >= Probs[0] && testrand < Probs[1])
934 {
935 // side is -x
936
937 x = -halfx + z*std::tan(ParTheta)*std::cos(ParPhi) + y*std::tan(ParAlpha);
938 y = y + z*std::tan(ParTheta)*std::sin(ParPhi);
939 // z = z;
940
941 // Cosine-law
942 //
943 G4ThreeVector xdash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
944 halfz*std::tan(ParTheta)*std::sin(ParPhi),
945 halfz/std::cos(ParPhi));
946 G4ThreeVector ydash(halfy*std::tan(ParAlpha), halfy, 0.0);
947 xdash = xdash.unit();
948 ydash = ydash.unit();
949 G4ThreeVector zdash = xdash.cross(ydash);
950 td.CSideRefVec1 = xdash.unit();
951 td.CSideRefVec2 = ydash.unit();
952 td.CSideRefVec3 = zdash.unit();
953 }
954 else if(testrand >= Probs[1] && testrand < Probs[2])
955 {
956 // side is +y
957
958 x = x + z*std::tan(ParTheta)*std::cos(ParPhi) + halfy*std::tan(ParAlpha);
959 y = halfy + z*std::tan(ParTheta)*std::sin(ParPhi);
960 // z = z;
961
962 // Cosine-law
963 //
964 G4ThreeVector ydash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
965 halfz*std::tan(ParTheta)*std::sin(ParPhi),
966 halfz/std::cos(ParPhi));
967 ydash = ydash.unit();
968 G4ThreeVector xdash = Roty.cross(ydash);
969 G4ThreeVector zdash = xdash.cross(ydash);
970 td.CSideRefVec1 = xdash.unit();
971 td.CSideRefVec2 = -ydash.unit();
972 td.CSideRefVec3 = -zdash.unit();
973 }
974 else if(testrand >= Probs[2] && testrand < Probs[3])
975 {
976 // side is -y
977
978 x = x + z*std::tan(ParTheta)*std::cos(ParPhi) - halfy*std::tan(ParAlpha);
979 y = -halfy + z*std::tan(ParTheta)*std::sin(ParPhi);
980 // z = z;
981
982 // Cosine-law
983 //
984 G4ThreeVector ydash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
985 halfz*std::tan(ParTheta)*std::sin(ParPhi),
986 halfz/std::cos(ParPhi));
987 ydash = ydash.unit();
988 G4ThreeVector xdash = Roty.cross(ydash);
989 G4ThreeVector zdash = xdash.cross(ydash);
990 td.CSideRefVec1 = xdash.unit();
991 td.CSideRefVec2 = ydash.unit();
992 td.CSideRefVec3 = zdash.unit();
993 }
994 else if(testrand >= Probs[3] && testrand < Probs[4])
995 {
996 // side is +z
997
998 z = halfz;
999 y = y + halfz*std::sin(ParPhi)*std::tan(ParTheta);
1000 x = x + halfz*std::cos(ParPhi)*std::tan(ParTheta) + y*std::tan(ParAlpha);
1001
1002 // Cosine-law
1003 //
1004 td.CSideRefVec1 = Rotx;
1005 td.CSideRefVec2 = Roty;
1006 td.CSideRefVec3 = Rotz;
1007 }
1008 else if(testrand >= Probs[4] && testrand < Probs[5])
1009 {
1010 // side is -z
1011
1012 z = -halfz;
1013 y = y - halfz*std::sin(ParPhi)*std::tan(ParTheta);
1014 x = x - halfz*std::cos(ParPhi)*std::tan(ParTheta) + y*std::tan(ParAlpha);
1015
1016 // Cosine-law
1017 //
1018 td.CSideRefVec1 = Rotx;
1019 td.CSideRefVec2 = -Roty;
1020 td.CSideRefVec3 = -Rotz;
1021 }
1022 else
1023 {
1024 G4cout << "Error: testrand out of range" << G4endl;
1025 if(verbosityLevel >= 1)
1026 {
1027 G4cout << "testrand=" << testrand << " Probs[5]=" << Probs[5] <<G4endl;
1028 }
1029 }
1030
1031 RandPos.setX(x);
1032 RandPos.setY(y);
1033 RandPos.setZ(z);
1034 }
1035
1036 // Apply Rotation Matrix
1037 // x * Rotx, y * Roty and z * Rotz
1038 //
1039 if(verbosityLevel == 2)
1040 {
1041 G4cout << "Raw position " << RandPos << G4endl;
1042 }
1043 x=(RandPos.x()*Rotx.x())+(RandPos.y()*Roty.x())+(RandPos.z()*Rotz.x());
1044 y=(RandPos.x()*Rotx.y())+(RandPos.y()*Roty.y())+(RandPos.z()*Rotz.y());
1045 z=(RandPos.x()*Rotx.z())+(RandPos.y()*Roty.z())+(RandPos.z()*Rotz.z());
1046
1047 RandPos.setX(x);
1048 RandPos.setY(y);
1049 RandPos.setZ(z);
1050
1051 // Translate
1052 //
1053 pos = CentreCoords + RandPos;
1054
1055 if(verbosityLevel >= 1)
1056 {
1057 if(verbosityLevel == 2)
1058 {
1059 G4cout << "Rotated position " << RandPos << G4endl;
1060 }
1061 G4cout << "Rotated and translated position " << pos << G4endl;
1062 }
1063 if(verbosityLevel == 2)
1064 {
1065 G4cout << "Reference vectors for cosine-law " << td.CSideRefVec1
1066 << " " << td.CSideRefVec2 << " " << td.CSideRefVec3 << G4endl;
1067 }
1068}
1069
1070void G4SPSPosDistribution::GeneratePointsInVolume(G4ThreeVector& pos)
1071{
1072 G4ThreeVector RandPos;
1073 G4double tempx, tempy, tempz;
1074 G4double x, y, z;
1075 G4double expression;
1076 x = y = z = 0.;
1077
1078 if(SourcePosType != "Volume" && verbosityLevel >= 1)
1079 {
1080 G4cout << "Error SourcePosType not Volume" << G4endl;
1081 }
1082
1083 // Private method to create points in a volume
1084 //
1085 if(Shape == "Sphere")
1086 {
1087 x = Radius*2.;
1088 y = Radius*2.;
1089 z = Radius*2.;
1090 while(((x*x)+(y*y)+(z*z)) > (Radius*Radius))
1091 {
1092 x = PosRndm->GenRandX();
1093 y = PosRndm->GenRandY();
1094 z = PosRndm->GenRandZ();
1095
1096 x = (x*2.*Radius) - Radius;
1097 y = (y*2.*Radius) - Radius;
1098 z = (z*2.*Radius) - Radius;
1099 }
1100 }
1101 else if(Shape == "Ellipsoid")
1102 {
1103 G4double temp;
1104 temp = 100.;
1105 while(temp > 1.)
1106 {
1107 x = PosRndm->GenRandX();
1108 y = PosRndm->GenRandY();
1109 z = PosRndm->GenRandZ();
1110
1111 x = (x*2.*halfx) - halfx;
1112 y = (y*2.*halfy) - halfy;
1113 z = (z*2.*halfz) - halfz;
1114
1115 temp = ((x*x)/(halfx*halfx))+((y*y)/(halfy*halfy))+((z*z)/(halfz*halfz));
1116 }
1117 }
1118 else if(Shape == "Cylinder")
1119 {
1120 x = Radius*2.;
1121 y = Radius*2.;
1122 while(((x*x)+(y*y)) > (Radius*Radius))
1123 {
1124 x = PosRndm->GenRandX();
1125 y = PosRndm->GenRandY();
1126 z = PosRndm->GenRandZ();
1127
1128 x = (x*2.*Radius) - Radius;
1129 y = (y*2.*Radius) - Radius;
1130 z = (z*2.*halfz) - halfz;
1131 }
1132 }
1133 else if(Shape == "EllipticCylinder")
1134 {
1135 expression = 20.;
1136 while(expression > 1.)
1137 {
1138 x = PosRndm->GenRandX();
1139 y = PosRndm->GenRandY();
1140 z = PosRndm->GenRandZ();
1141
1142 x = (x*2.*halfx) - halfx;
1143 y = (y*2.*halfy) - halfy;
1144 z = (z*2.*halfz) - halfz;
1145
1146 expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
1147 }
1148 }
1149 else if(Shape == "Para")
1150 {
1151 x = PosRndm->GenRandX();
1152 y = PosRndm->GenRandY();
1153 z = PosRndm->GenRandZ();
1154 x = (x*2.*halfx) - halfx;
1155 y = (y*2.*halfy) - halfy;
1156 z = (z*2.*halfz) - halfz;
1157 x = x + z*std::tan(ParTheta)*std::cos(ParPhi) + y*std::tan(ParAlpha);
1158 y = y + z*std::tan(ParTheta)*std::sin(ParPhi);
1159 // z = z;
1160 }
1161 else
1162 {
1163 G4cout << "Error: Volume Shape does not exist" << G4endl;
1164 }
1165
1166 RandPos.setX(x);
1167 RandPos.setY(y);
1168 RandPos.setZ(z);
1169
1170 // Apply Rotation Matrix
1171 // x * Rotx, y * Roty and z * Rotz
1172 //
1173 tempx = (x * Rotx.x()) + (y * Roty.x()) + (z * Rotz.x());
1174 tempy = (x * Rotx.y()) + (y * Roty.y()) + (z * Rotz.y());
1175 tempz = (x * Rotx.z()) + (y * Roty.z()) + (z * Rotz.z());
1176
1177 RandPos.setX(tempx);
1178 RandPos.setY(tempy);
1179 RandPos.setZ(tempz);
1180
1181 // Translate
1182 //
1183 pos = CentreCoords + RandPos;
1184
1185 if(verbosityLevel == 2)
1186 {
1187 G4cout << "Raw position " << x << "," << y << "," << z << G4endl;
1188 G4cout << "Rotated position " << RandPos << G4endl;
1189 }
1190 if(verbosityLevel >= 1)
1191 {
1192 G4cout << "Rotated and translated position " << pos << G4endl;
1193 }
1194
1195 // Cosine-law (not a good idea to use this here)
1196 //
1197 G4ThreeVector zdash(tempx,tempy,tempz);
1198 zdash = zdash.unit();
1199 G4ThreeVector xdash = Rotz.cross(zdash);
1200 G4ThreeVector ydash = xdash.cross(zdash);
1201 thread_data_t& td = ThreadData.Get();
1202 td.CSideRefVec1 = xdash.unit();
1203 td.CSideRefVec2 = ydash.unit();
1204 td.CSideRefVec3 = zdash.unit();
1205 if(verbosityLevel == 2)
1206 {
1207 G4cout << "Reference vectors for cosine-law " << td.CSideRefVec1
1208 << " " << td.CSideRefVec2 << " " << td.CSideRefVec3 << G4endl;
1209 }
1210}
1211
1212G4bool G4SPSPosDistribution::IsSourceConfined(G4ThreeVector& pos)
1213{
1214 // Method to check point is within the volume specified
1215
1216 if(!Confine)
1217 {
1218 G4cout << "Error: Confine is false" << G4endl;
1219 }
1220 G4ThreeVector null(0.,0.,0.);
1221 G4ThreeVector* ptr = &null;
1222
1223 // Check position is within VolName, if so true, else false
1224 //
1225 G4VPhysicalVolume* theVolume;
1228 theVolume = gNavigator->LocateGlobalPointAndSetup(pos,ptr,true);
1229 if(theVolume == nullptr) { return false; }
1230 G4String theVolName = theVolume->GetName();
1231
1232 if(theVolName == VolName)
1233 {
1234 if(verbosityLevel >= 1)
1235 {
1236 G4cout << "Particle is in volume " << VolName << G4endl;
1237 }
1238 return true;
1239 }
1240
1241 return false;
1242
1243}
1244
1246{
1247 G4ThreeVector localP;
1248 G4bool srcconf = false;
1249 G4int LoopCount = 0;
1250 while(!srcconf)
1251 {
1252 if(SourcePosType == "Point")
1253 GeneratePointSource(localP);
1254 else if(SourcePosType == "Beam")
1255 GeneratePointsInBeam(localP);
1256 else if(SourcePosType == "Plane")
1257 GeneratePointsInPlane(localP);
1258 else if(SourcePosType == "Surface")
1259 GeneratePointsOnSurface(localP);
1260 else if(SourcePosType == "Volume")
1261 GeneratePointsInVolume(localP);
1262 else
1263 {
1265 msg << "Error: SourcePosType undefined\n";
1266 msg << "Generating point source\n";
1267 G4Exception("G4SPSPosDistribution::GenerateOne()",
1268 "G4GPS001", JustWarning, msg);
1269 GeneratePointSource(localP);
1270 }
1271 if(Confine)
1272 {
1273 srcconf = IsSourceConfined(localP);
1274 // if source in confined srcconf = true terminating the loop
1275 // if source isnt confined srcconf = false and loop continues
1276 }
1277 else if(!Confine)
1278 {
1279 srcconf = true; // terminate loop
1280 }
1281 ++LoopCount;
1282 if(LoopCount == 100000)
1283 {
1285 msg << "LoopCount = 100000\n";
1286 msg << "Either the source distribution >> confinement\n";
1287 msg << "or any confining volume may not overlap with\n";
1288 msg << "the source distribution or any confining volumes\n";
1289 msg << "may not exist\n"<< G4endl;
1290 msg << "If you have set confine then this will be ignored\n";
1291 msg << "for this event.\n" << G4endl;
1292 G4Exception("G4SPSPosDistribution::GenerateOne()",
1293 "G4GPS001", JustWarning, msg);
1294 srcconf = true; // Avoids an infinite loop
1295 }
1296 }
1297 ThreadData.Get().CParticlePos = localP;
1298 return localP;
1299}
1300
@ JustWarning
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
std::ostringstream G4ExceptionDescription
Definition: G4Exception.hh:40
#define G4MUTEXDESTROY(mutex)
Definition: G4Threading.hh:90
#define G4MUTEXINIT(mutex)
Definition: G4Threading.hh:87
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
double z() const
Hep3Vector unit() const
double x() const
void setY(double)
double y() const
Hep3Vector cross(const Hep3Vector &) const
void setZ(double)
void setX(double)
value_type & Get() const
Definition: G4Cache.hh:315
virtual G4VPhysicalVolume * LocateGlobalPointAndSetup(const G4ThreeVector &point, const G4ThreeVector *direction=nullptr, const G4bool pRelativeSearch=true, const G4bool ignoreDirection=true)
Definition: G4Navigator.cc:132
static G4PhysicalVolumeStore * GetInstance()
G4VPhysicalVolume * GetVolume(const G4String &name, G4bool verbose=true, G4bool reverseSearch=false) const
const G4ThreeVector & GetCentreCoords() const
void SetPosRot2(const G4ThreeVector &)
void ConfineSourceToVolume(const G4String &)
void SetBiasRndm(G4SPSRandomGenerator *a)
const G4String & GetPosDisType() const
void SetPosDisShape(const G4String &)
const G4ThreeVector & GetParticlePos() const
void SetCentreCoords(const G4ThreeVector &)
const G4String & GetSourcePosType() const
const G4ThreeVector & GetSideRefVec2() const
const G4String & GetPosDisShape() const
const G4ThreeVector & GetSideRefVec3() const
const G4ThreeVector & GetSideRefVec1() const
void SetPosRot1(const G4ThreeVector &)
void SetPosDisType(const G4String &)
static G4TransportationManager * GetTransportationManager()
G4Navigator * GetNavigatorForTracking() const
const G4String & GetName() const
DLL_API const Hep3Vector HepZHat
Definition: ThreeVector.h:419
DLL_API const Hep3Vector HepXHat
DLL_API const Hep3Vector HepYHat
Definition: ThreeVector.h:419
const G4double pi