Geant4 10.7.0
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;
279 G4PhysicalVolumeStore* PVStore = nullptr;
280 G4String theRequiredVolumeName = VolName;
282 G4int i = 0;
283 G4bool found = false;
284 if(verbosityLevel == 2) { G4cout << PVStore->size() << G4endl; }
285
286 while (!found && i<G4int(PVStore->size()))
287 {
288 tempPV = (*PVStore)[i];
289 found = tempPV->GetName() == theRequiredVolumeName;
290 if(verbosityLevel == 2)
291 {
292 G4cout << i << " " << " " << tempPV->GetName()
293 << " " << theRequiredVolumeName << " " << found << G4endl;
294 }
295 if (!found) { ++i; }
296 }
297
298 // found = true then the volume exists else it doesn't
299 //
300 if(found == true)
301 {
302 if(verbosityLevel >= 1)
303 {
304 G4cout << "Volume " << VolName << " exists" << G4endl;
305 }
306 Confine = true;
307 }
308 else
309 {
310 G4cout << " **** Error: Volume <" << VolName << "> does not exist **** " << G4endl;
311 G4cout << " Ignoring confine condition" << G4endl;
312 Confine = false;
313 VolName = "NULL";
314 }
315}
316
317void G4SPSPosDistribution::GeneratePointSource(G4ThreeVector& pos)
318{
319 // Generates Points given the point source
320
321 if(SourcePosType == "Point")
322 {
323 pos = CentreCoords;
324 }
325 else
326 {
327 if(verbosityLevel >= 1)
328 {
329 G4cerr << "Error SourcePosType is not set to Point" << G4endl;
330 }
331 }
332}
333
334void G4SPSPosDistribution::GeneratePointsInBeam(G4ThreeVector& pos)
335{
336 G4double x, y, z;
337
338 G4ThreeVector RandPos;
339 G4double tempx, tempy, tempz;
340 z = 0.;
341
342 // Private Method to create points in a plane
343 //
344 if(Shape == "Circle")
345 {
346 x = Radius + 100.;
347 y = Radius + 100.;
348 while(std::sqrt((x*x) + (y*y)) > Radius)
349 {
350 x = PosRndm->GenRandX();
351 y = PosRndm->GenRandY();
352
353 x = (x*2.*Radius) - Radius;
354 y = (y*2.*Radius) - Radius;
355 }
356 x += G4RandGauss::shoot(0.0,SX) ;
357 y += G4RandGauss::shoot(0.0,SY) ;
358 }
359 else
360 {
361 // All other cases default to Rectangle case
362 //
363 x = PosRndm->GenRandX();
364 y = PosRndm->GenRandY();
365 x = (x*2.*halfx) - halfx;
366 y = (y*2.*halfy) - halfy;
367 x += G4RandGauss::shoot(0.0,SX);
368 y += G4RandGauss::shoot(0.0,SY);
369 }
370
371 // Apply Rotation Matrix
372 // x * Rotx, y * Roty and z * Rotz
373 //
374 if(verbosityLevel >= 2)
375 {
376 G4cout << "Raw position " << x << "," << y << "," << z << G4endl;
377 }
378 tempx = (x * Rotx.x()) + (y * Roty.x()) + (z * Rotz.x());
379 tempy = (x * Rotx.y()) + (y * Roty.y()) + (z * Rotz.y());
380 tempz = (x * Rotx.z()) + (y * Roty.z()) + (z * Rotz.z());
381
382 RandPos.setX(tempx);
383 RandPos.setY(tempy);
384 RandPos.setZ(tempz);
385
386 // Translate
387 //
388 pos = CentreCoords + RandPos;
389 if(verbosityLevel >= 1)
390 {
391 if(verbosityLevel >= 2)
392 {
393 G4cout << "Rotated Position " << RandPos << G4endl;
394 }
395 G4cout << "Rotated and Translated position " << pos << G4endl;
396 }
397}
398
399void G4SPSPosDistribution::GeneratePointsInPlane(G4ThreeVector& pos)
400{
401 G4double x, y, z;
402 G4double expression;
403 G4ThreeVector RandPos;
404 G4double tempx, tempy, tempz;
405 x = y = z = 0.;
406 thread_data_t& td = ThreadData.Get();
407
408 if(SourcePosType != "Plane" && verbosityLevel >= 1)
409 {
410 G4cerr << "Error: SourcePosType is not Plane" << G4endl;
411 }
412
413 // Private Method to create points in a plane
414 //
415 if(Shape == "Circle")
416 {
417 x = Radius + 100.;
418 y = Radius + 100.;
419 while(std::sqrt((x*x) + (y*y)) > Radius)
420 {
421 x = PosRndm->GenRandX();
422 y = PosRndm->GenRandY();
423
424 x = (x*2.*Radius) - Radius;
425 y = (y*2.*Radius) - Radius;
426 }
427 }
428 else if(Shape == "Annulus")
429 {
430 x = Radius + 100.;
431 y = Radius + 100.;
432 while(std::sqrt((x*x) + (y*y)) > Radius
433 || std::sqrt((x*x) + (y*y)) < Radius0 )
434 {
435 x = PosRndm->GenRandX();
436 y = PosRndm->GenRandY();
437
438 x = (x*2.*Radius) - Radius;
439 y = (y*2.*Radius) - Radius;
440 }
441 }
442 else if(Shape == "Ellipse")
443 {
444 expression = 20.;
445 while(expression > 1.)
446 {
447 x = PosRndm->GenRandX();
448 y = PosRndm->GenRandY();
449
450 x = (x*2.*halfx) - halfx;
451 y = (y*2.*halfy) - halfy;
452
453 expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
454 }
455 }
456 else if(Shape == "Square")
457 {
458 x = PosRndm->GenRandX();
459 y = PosRndm->GenRandY();
460 x = (x*2.*halfx) - halfx;
461 y = (y*2.*halfy) - halfy;
462 }
463 else if(Shape == "Rectangle")
464 {
465 x = PosRndm->GenRandX();
466 y = PosRndm->GenRandY();
467 x = (x*2.*halfx) - halfx;
468 y = (y*2.*halfy) - halfy;
469 }
470 else
471 {
472 G4cout << "Shape not one of the plane types" << G4endl;
473 }
474
475 // Apply Rotation Matrix
476 // x * Rotx, y * Roty and z * Rotz
477 //
478 if(verbosityLevel == 2)
479 {
480 G4cout << "Raw position " << x << "," << y << "," << z << G4endl;
481 }
482 tempx = (x * Rotx.x()) + (y * Roty.x()) + (z * Rotz.x());
483 tempy = (x * Rotx.y()) + (y * Roty.y()) + (z * Rotz.y());
484 tempz = (x * Rotx.z()) + (y * Roty.z()) + (z * Rotz.z());
485
486 RandPos.setX(tempx);
487 RandPos.setY(tempy);
488 RandPos.setZ(tempz);
489
490 // Translate
491 //
492 pos = CentreCoords + RandPos;
493 if(verbosityLevel >= 1)
494 {
495 if(verbosityLevel == 2)
496 {
497 G4cout << "Rotated Position " << RandPos << G4endl;
498 }
499 G4cout << "Rotated and Translated position " << pos << G4endl;
500 }
501
502 // For Cosine-Law make SideRefVecs = to Rotation matrix vectors
503 // Note: these need to be thread-local, use G4Cache
504 //
505 td.CSideRefVec1 = Rotx;
506 td.CSideRefVec2 = Roty;
507 td.CSideRefVec3 = Rotz;
508
509 // If rotation matrix z' point to origin then invert the matrix
510 // So that SideRefVecs point away
511 //
512 if((CentreCoords.x() > 0. && Rotz.x() < 0.)
513 || (CentreCoords.x() < 0. && Rotz.x() > 0.)
514 || (CentreCoords.y() > 0. && Rotz.y() < 0.)
515 || (CentreCoords.y() < 0. && Rotz.y() > 0.)
516 || (CentreCoords.z() > 0. && Rotz.z() < 0.)
517 || (CentreCoords.z() < 0. && Rotz.z() > 0.))
518 {
519 // Invert y and z
520 //
521 td.CSideRefVec2 = - td.CSideRefVec2;
522 td.CSideRefVec3 = - td.CSideRefVec3;
523 }
524 if(verbosityLevel == 2)
525 {
526 G4cout << "Reference vectors for cosine-law "
527 << td.CSideRefVec1<< " " << td.CSideRefVec2
528 << " " << td.CSideRefVec3 << G4endl;
529 }
530}
531
532void G4SPSPosDistribution::GeneratePointsOnSurface(G4ThreeVector& pos)
533{
534 // Private method to create points on a surface
535 //
536 G4double theta, phi;
537 G4double x, y, z;
538 x = y = z = 0.;
539 G4double expression;
540 G4ThreeVector RandPos;
541
542 thread_data_t& td = ThreadData.Get();
543 if(SourcePosType != "Surface" && verbosityLevel >= 1)
544 {
545 G4cout << "Error SourcePosType not Surface" << G4endl;
546 }
547
548 if(Shape == "Sphere")
549 {
550 theta = PosRndm->GenRandPosTheta();
551 phi = PosRndm->GenRandPosPhi();
552 theta = std::acos(1. - 2.*theta); // theta isotropic
553 phi = phi * 2. * pi;
554
555 x = Radius * std::sin(theta) * std::cos(phi);
556 y = Radius * std::sin(theta) * std::sin(phi);
557 z = Radius * std::cos(theta);
558
559 RandPos.setX(x);
560 RandPos.setY(y);
561 RandPos.setZ(z);
562
563 // Cosine-law (not a good idea to use this here)
564 //
565 G4ThreeVector zdash(x,y,z);
566 zdash = zdash.unit();
567 G4ThreeVector xdash = Rotz.cross(zdash);
568 G4ThreeVector ydash = xdash.cross(zdash);
569 td.CSideRefVec1 = xdash.unit();
570 td.CSideRefVec2 = ydash.unit();
571 td.CSideRefVec3 = zdash.unit();
572 }
573 else if(Shape == "Ellipsoid")
574 {
575 G4double minphi, maxphi, middlephi;
576 G4double answer, constant;
577
578 constant = pi/(halfx*halfx) + pi/(halfy*halfy) + twopi/(halfz*halfz);
579
580 // Simplified approach
581 //
582 theta = PosRndm->GenRandPosTheta();
583 phi = PosRndm->GenRandPosPhi();
584
585 theta = std::acos(1. - 2.*theta);
586 minphi = 0.;
587 maxphi = twopi;
588 while(maxphi-minphi > 0.)
589 {
590 middlephi = (maxphi+minphi)/2.;
591 answer = (1./(halfx*halfx))*(middlephi/2. + std::sin(2*middlephi)/4.)
592 + (1./(halfy*halfy))*(middlephi/2. - std::sin(2*middlephi)/4.)
593 + middlephi/(halfz*halfz);
594 answer = answer/constant;
595 if(answer > phi) maxphi = middlephi;
596 if(answer < phi) minphi = middlephi;
597 if(std::fabs(answer-phi) <= 0.00001)
598 {
599 minphi = maxphi +1;
600 phi = middlephi;
601 }
602 }
603
604 // x,y and z form a unit vector. Put this onto the ellipse.
605 //
606 x = std::sin(theta)*std::cos(phi);
607 y = std::sin(theta)*std::sin(phi);
608 z = std::cos(theta);
609
610 G4double lhs;
611
612 // Solve for x
613 //
614 G4double numYinX = y/x;
615 G4double numZinX = z/x;
616 G4double tempxvar;
617 tempxvar = 1./(halfx*halfx)+(numYinX*numYinX)/(halfy*halfy)
618 + (numZinX*numZinX)/(halfz*halfz);
619 tempxvar = 1./tempxvar;
620 G4double coordx = std::sqrt(tempxvar);
621
622 // Solve for y
623 //
624 G4double numXinY = x/y;
625 G4double numZinY = z/y;
626 G4double tempyvar;
627 tempyvar = (numXinY*numXinY)/(halfx*halfx)+1./(halfy*halfy)
628 + (numZinY*numZinY)/(halfz*halfz);
629 tempyvar = 1./tempyvar;
630 G4double coordy = std::sqrt(tempyvar);
631
632 // Solve for z
633 //
634 G4double numXinZ = x/z;
635 G4double numYinZ = y/z;
636 G4double tempzvar;
637 tempzvar = (numXinZ*numXinZ)/(halfx*halfx)
638 + (numYinZ*numYinZ)/(halfy*halfy)+1./(halfz*halfz);
639 tempzvar = 1./tempzvar;
640 G4double coordz = std::sqrt(tempzvar);
641
642 lhs = std::sqrt((coordx*coordx)/(halfx*halfx) +
643 (coordy*coordy)/(halfy*halfy) +
644 (coordz*coordz)/(halfz*halfz));
645
646 if(std::fabs(lhs-1.) > 0.001 && verbosityLevel >= 1)
647 {
648 G4cout << "Error: theta, phi not really on ellipsoid" << G4endl;
649 }
650
651 // coordx, coordy and coordz are all positive
652 //
653 G4double TestRandVar = G4UniformRand();
654 if(TestRandVar > 0.5)
655 {
656 coordx = -coordx;
657 }
658 TestRandVar = G4UniformRand();
659 if(TestRandVar > 0.5)
660 {
661 coordy = -coordy;
662 }
663 TestRandVar = G4UniformRand();
664 if(TestRandVar > 0.5)
665 {
666 coordz = -coordz;
667 }
668
669 RandPos.setX(coordx);
670 RandPos.setY(coordy);
671 RandPos.setZ(coordz);
672
673 // Cosine-law (not a good idea to use this here)
674 //
675 G4ThreeVector zdash(coordx,coordy,coordz);
676 zdash = zdash.unit();
677 G4ThreeVector xdash = Rotz.cross(zdash);
678 G4ThreeVector ydash = xdash.cross(zdash);
679 td.CSideRefVec1 = xdash.unit();
680 td.CSideRefVec2 = ydash.unit();
681 td.CSideRefVec3 = zdash.unit();
682 }
683 else if(Shape == "Cylinder")
684 {
685 G4double AreaTop, AreaBot, AreaLat;
686 G4double AreaTotal, prob1, prob2, prob3;
687 G4double testrand;
688
689 // User giver Radius and z-half length
690 // Calculate surface areas, maybe move this to
691 // a different method
692
693 AreaTop = pi * Radius * Radius;
694 AreaBot = AreaTop;
695 AreaLat = 2. * pi * Radius * 2. * halfz;
696 AreaTotal = AreaTop + AreaBot + AreaLat;
697
698 prob1 = AreaTop / AreaTotal;
699 prob2 = AreaBot / AreaTotal;
700 prob3 = 1.00 - prob1 - prob2;
701 if(std::fabs(prob3 - (AreaLat/AreaTotal)) >= 0.001)
702 {
703 if(verbosityLevel >= 1)
704 {
705 G4cout << AreaLat/AreaTotal << " " << prob3 << G4endl;
706 }
707 G4cout << "Error in prob3" << G4endl;
708 }
709
710 // Decide surface to calculate point on.
711
712 testrand = G4UniformRand();
713 if(testrand <= prob1) // Point on Top surface
714 {
715 z = halfz;
716 x = Radius + 100.;
717 y = Radius + 100.;
718 while(((x*x)+(y*y)) > (Radius*Radius))
719 {
720 x = PosRndm->GenRandX();
721 y = PosRndm->GenRandY();
722
723 x = x * 2. * Radius;
724 y = y * 2. * Radius;
725 x = x - Radius;
726 y = y - Radius;
727 }
728 // Cosine law
729 //
730 td.CSideRefVec1 = Rotx;
731 td.CSideRefVec2 = Roty;
732 td.CSideRefVec3 = Rotz;
733 }
734 else if((testrand > prob1) && (testrand <= (prob1 + prob2)))
735 { // Point on Bottom surface
736 z = -halfz;
737 x = Radius + 100.;
738 y = Radius + 100.;
739 while(((x*x)+(y*y)) > (Radius*Radius))
740 {
741 x = PosRndm->GenRandX();
742 y = PosRndm->GenRandY();
743
744 x = x * 2. * Radius;
745 y = y * 2. * Radius;
746 x = x - Radius;
747 y = y - Radius;
748 }
749 // Cosine law
750 //
751 td.CSideRefVec1 = Rotx;
752 td.CSideRefVec2 = -Roty;
753 td.CSideRefVec3 = -Rotz;
754 }
755 else if(testrand > (prob1+prob2)) // Point on Lateral Surface
756 {
757 G4double rand;
758
759 rand = PosRndm->GenRandPosPhi();
760 rand = rand * 2. * pi;
761
762 x = Radius * std::cos(rand);
763 y = Radius * std::sin(rand);
764
765 z = PosRndm->GenRandZ();
766
767 z = z * 2. *halfz;
768 z = z - halfz;
769
770 // Cosine law
771 //
772 G4ThreeVector zdash(x,y,0.);
773 zdash = zdash.unit();
774 G4ThreeVector xdash = Rotz.cross(zdash);
775 G4ThreeVector ydash = xdash.cross(zdash);
776 td.CSideRefVec1 = xdash.unit();
777 td.CSideRefVec2 = ydash.unit();
778 td.CSideRefVec3 = zdash.unit();
779 }
780 else
781 {
782 G4cout << "Error: testrand " << testrand << G4endl;
783 }
784
785 RandPos.setX(x);
786 RandPos.setY(y);
787 RandPos.setZ(z);
788 }
789 else if(Shape == "EllipticCylinder")
790 {
791 G4double AreaTop, AreaBot, AreaLat, AreaTotal;
792 G4double h;
793 G4double prob1, prob2, prob3;
794 G4double testrand;
795
796 // User giver x, y and z-half length
797 // Calculate surface areas, maybe move this to
798 // a different method
799
800 AreaTop = pi * halfx * halfy;
801 AreaBot = AreaTop;
802
803 // Using circumference approximation by Ramanujan (order h^3)
804 // AreaLat = 2*halfz * pi*( 3*(halfx + halfy)
805 // - std::sqrt((3*halfx + halfy) * (halfx + 3*halfy)) );
806 // Using circumference approximation by Ramanujan (order h^5)
807 //
808 h = ((halfx - halfy)*(halfx - halfy)) / ((halfx + halfy)*(halfx + halfy));
809 AreaLat = 2*halfz * pi*(halfx + halfy)
810 * (1 + (3*h)/(10 + std::sqrt(4 - 3*h)));
811 AreaTotal = AreaTop + AreaBot + AreaLat;
812
813 prob1 = AreaTop / AreaTotal;
814 prob2 = AreaBot / AreaTotal;
815 prob3 = 1.00 - prob1 - prob2;
816 if(std::fabs(prob3 - (AreaLat/AreaTotal)) >= 0.001)
817 {
818 if(verbosityLevel >= 1)
819 {
820 G4cout << AreaLat/AreaTotal << " " << prob3 << G4endl;
821 }
822 G4cout << "Error in prob3" << G4endl;
823 }
824
825 // Decide surface to calculate point on
826
827 testrand = G4UniformRand();
828 if(testrand <= prob1) // Point on Top surface
829 {
830 z = halfz;
831 expression = 20.;
832 while(expression > 1.)
833 {
834 x = PosRndm->GenRandX();
835 y = PosRndm->GenRandY();
836
837 x = (x * 2. * halfx) - halfx;
838 y = (y * 2. * halfy) - halfy;
839
840 expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
841 }
842 }
843 else if((testrand > prob1) && (testrand <= (prob1 + prob2)))
844 { // Point on Bottom surface
845 z = -halfz;
846 expression = 20.;
847 while(expression > 1.)
848 {
849 x = PosRndm->GenRandX();
850 y = PosRndm->GenRandY();
851
852 x = (x * 2. * halfx) - halfx;
853 y = (y * 2. * halfy) - halfy;
854
855 expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
856 }
857 }
858 else if(testrand > (prob1+prob2)) // Point on Lateral Surface
859 {
860 G4double rand;
861
862 rand = PosRndm->GenRandPosPhi();
863 rand = rand * 2. * pi;
864
865 x = halfx * std::cos(rand);
866 y = halfy * std::sin(rand);
867
868 z = PosRndm->GenRandZ();
869
870 z = (z * 2. * halfz) - halfz;
871 }
872 else
873 {
874 G4cout << "Error: testrand " << testrand << G4endl;
875 }
876
877 RandPos.setX(x);
878 RandPos.setY(y);
879 RandPos.setZ(z);
880
881 // Cosine law
882 //
883 G4ThreeVector zdash(x,y,z);
884 zdash = zdash.unit();
885 G4ThreeVector xdash = Rotz.cross(zdash);
886 G4ThreeVector ydash = xdash.cross(zdash);
887 td.CSideRefVec1 = xdash.unit();
888 td.CSideRefVec2 = ydash.unit();
889 td.CSideRefVec3 = zdash.unit();
890 }
891 else if(Shape == "Para")
892 {
893 // Right Parallelepiped.
894 // User gives x,y,z half lengths and ParAlpha
895 // ParTheta and ParPhi
896 // +x = <1, -x >1 & <2, +y >2 & <3, -y >3 &<4
897 // +z >4 & < 5, -z >5 &<6
898
899 G4double testrand = G4UniformRand();
900 G4double AreaX = halfy * halfz * 4.;
901 G4double AreaY = halfx * halfz * 4.;
902 G4double AreaZ = halfx * halfy * 4.;
903 G4double AreaTotal = 2*(AreaX + AreaY + AreaZ);
904 G4double Probs[6];
905 Probs[0] = AreaX/AreaTotal;
906 Probs[1] = Probs[0] + AreaX/AreaTotal;
907 Probs[2] = Probs[1] + AreaY/AreaTotal;
908 Probs[3] = Probs[2] + AreaY/AreaTotal;
909 Probs[4] = Probs[3] + AreaZ/AreaTotal;
910 Probs[5] = Probs[4] + AreaZ/AreaTotal;
911
912 x = PosRndm->GenRandX();
913 y = PosRndm->GenRandY();
914 z = PosRndm->GenRandZ();
915
916 x = x * halfx * 2.;
917 x = x - halfx;
918 y = y * halfy * 2.;
919 y = y - halfy;
920 z = z * halfz * 2.;
921 z = z - halfz;
922
923 // Pick a side first
924 //
925 if(testrand < Probs[0])
926 {
927 // side is +x
928
929 x = halfx + z*std::tan(ParTheta)*std::cos(ParPhi) + y*std::tan(ParAlpha);
930 y = y + z*std::tan(ParTheta)*std::sin(ParPhi);
931 // z = z;
932
933 // Cosine-law
934 //
935 G4ThreeVector xdash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
936 halfz*std::tan(ParTheta)*std::sin(ParPhi),
937 halfz/std::cos(ParPhi));
938 G4ThreeVector ydash(halfy*std::tan(ParAlpha), -halfy, 0.0);
939 xdash = xdash.unit();
940 ydash = ydash.unit();
941 G4ThreeVector zdash = xdash.cross(ydash);
942 td.CSideRefVec1 = xdash.unit();
943 td.CSideRefVec2 = ydash.unit();
944 td.CSideRefVec3 = zdash.unit();
945 }
946 else if(testrand >= Probs[0] && testrand < Probs[1])
947 {
948 // side is -x
949
950 x = -halfx + z*std::tan(ParTheta)*std::cos(ParPhi) + y*std::tan(ParAlpha);
951 y = y + z*std::tan(ParTheta)*std::sin(ParPhi);
952 // z = z;
953
954 // Cosine-law
955 //
956 G4ThreeVector xdash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
957 halfz*std::tan(ParTheta)*std::sin(ParPhi),
958 halfz/std::cos(ParPhi));
959 G4ThreeVector ydash(halfy*std::tan(ParAlpha), halfy, 0.0);
960 xdash = xdash.unit();
961 ydash = ydash.unit();
962 G4ThreeVector zdash = xdash.cross(ydash);
963 td.CSideRefVec1 = xdash.unit();
964 td.CSideRefVec2 = ydash.unit();
965 td.CSideRefVec3 = zdash.unit();
966 }
967 else if(testrand >= Probs[1] && testrand < Probs[2])
968 {
969 // side is +y
970
971 x = x + z*std::tan(ParTheta)*std::cos(ParPhi) + halfy*std::tan(ParAlpha);
972 y = halfy + z*std::tan(ParTheta)*std::sin(ParPhi);
973 // z = z;
974
975 // Cosine-law
976 //
977 G4ThreeVector ydash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
978 halfz*std::tan(ParTheta)*std::sin(ParPhi),
979 halfz/std::cos(ParPhi));
980 ydash = ydash.unit();
981 G4ThreeVector xdash = Roty.cross(ydash);
982 G4ThreeVector zdash = xdash.cross(ydash);
983 td.CSideRefVec1 = xdash.unit();
984 td.CSideRefVec2 = -ydash.unit();
985 td.CSideRefVec3 = -zdash.unit();
986 }
987 else if(testrand >= Probs[2] && testrand < Probs[3])
988 {
989 // side is -y
990
991 x = x + z*std::tan(ParTheta)*std::cos(ParPhi) - halfy*std::tan(ParAlpha);
992 y = -halfy + z*std::tan(ParTheta)*std::sin(ParPhi);
993 // z = z;
994
995 // Cosine-law
996 //
997 G4ThreeVector ydash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
998 halfz*std::tan(ParTheta)*std::sin(ParPhi),
999 halfz/std::cos(ParPhi));
1000 ydash = ydash.unit();
1001 G4ThreeVector xdash = Roty.cross(ydash);
1002 G4ThreeVector zdash = xdash.cross(ydash);
1003 td.CSideRefVec1 = xdash.unit();
1004 td.CSideRefVec2 = ydash.unit();
1005 td.CSideRefVec3 = zdash.unit();
1006 }
1007 else if(testrand >= Probs[3] && testrand < Probs[4])
1008 {
1009 // side is +z
1010
1011 z = halfz;
1012 y = y + halfz*std::sin(ParPhi)*std::tan(ParTheta);
1013 x = x + halfz*std::cos(ParPhi)*std::tan(ParTheta) + y*std::tan(ParAlpha);
1014
1015 // Cosine-law
1016 //
1017 td.CSideRefVec1 = Rotx;
1018 td.CSideRefVec2 = Roty;
1019 td.CSideRefVec3 = Rotz;
1020 }
1021 else if(testrand >= Probs[4] && testrand < Probs[5])
1022 {
1023 // side is -z
1024
1025 z = -halfz;
1026 y = y - halfz*std::sin(ParPhi)*std::tan(ParTheta);
1027 x = x - halfz*std::cos(ParPhi)*std::tan(ParTheta) + y*std::tan(ParAlpha);
1028
1029 // Cosine-law
1030 //
1031 td.CSideRefVec1 = Rotx;
1032 td.CSideRefVec2 = -Roty;
1033 td.CSideRefVec3 = -Rotz;
1034 }
1035 else
1036 {
1037 G4cout << "Error: testrand out of range" << G4endl;
1038 if(verbosityLevel >= 1)
1039 {
1040 G4cout << "testrand=" << testrand << " Probs[5]=" << Probs[5] <<G4endl;
1041 }
1042 }
1043
1044 RandPos.setX(x);
1045 RandPos.setY(y);
1046 RandPos.setZ(z);
1047 }
1048
1049 // Apply Rotation Matrix
1050 // x * Rotx, y * Roty and z * Rotz
1051 //
1052 if(verbosityLevel == 2)
1053 {
1054 G4cout << "Raw position " << RandPos << G4endl;
1055 }
1056 x=(RandPos.x()*Rotx.x())+(RandPos.y()*Roty.x())+(RandPos.z()*Rotz.x());
1057 y=(RandPos.x()*Rotx.y())+(RandPos.y()*Roty.y())+(RandPos.z()*Rotz.y());
1058 z=(RandPos.x()*Rotx.z())+(RandPos.y()*Roty.z())+(RandPos.z()*Rotz.z());
1059
1060 RandPos.setX(x);
1061 RandPos.setY(y);
1062 RandPos.setZ(z);
1063
1064 // Translate
1065 //
1066 pos = CentreCoords + RandPos;
1067
1068 if(verbosityLevel >= 1)
1069 {
1070 if(verbosityLevel == 2)
1071 {
1072 G4cout << "Rotated position " << RandPos << G4endl;
1073 }
1074 G4cout << "Rotated and translated position " << pos << G4endl;
1075 }
1076 if(verbosityLevel == 2)
1077 {
1078 G4cout << "Reference vectors for cosine-law " << td.CSideRefVec1
1079 << " " << td.CSideRefVec2 << " " << td.CSideRefVec3 << G4endl;
1080 }
1081}
1082
1083void G4SPSPosDistribution::GeneratePointsInVolume(G4ThreeVector& pos)
1084{
1085 G4ThreeVector RandPos;
1086 G4double tempx, tempy, tempz;
1087 G4double x, y, z;
1088 G4double expression;
1089 x = y = z = 0.;
1090
1091 if(SourcePosType != "Volume" && verbosityLevel >= 1)
1092 {
1093 G4cout << "Error SourcePosType not Volume" << G4endl;
1094 }
1095
1096 // Private method to create points in a volume
1097 //
1098 if(Shape == "Sphere")
1099 {
1100 x = Radius*2.;
1101 y = Radius*2.;
1102 z = Radius*2.;
1103 while(((x*x)+(y*y)+(z*z)) > (Radius*Radius))
1104 {
1105 x = PosRndm->GenRandX();
1106 y = PosRndm->GenRandY();
1107 z = PosRndm->GenRandZ();
1108
1109 x = (x*2.*Radius) - Radius;
1110 y = (y*2.*Radius) - Radius;
1111 z = (z*2.*Radius) - Radius;
1112 }
1113 }
1114 else if(Shape == "Ellipsoid")
1115 {
1116 G4double temp;
1117 temp = 100.;
1118 while(temp > 1.)
1119 {
1120 x = PosRndm->GenRandX();
1121 y = PosRndm->GenRandY();
1122 z = PosRndm->GenRandZ();
1123
1124 x = (x*2.*halfx) - halfx;
1125 y = (y*2.*halfy) - halfy;
1126 z = (z*2.*halfz) - halfz;
1127
1128 temp = ((x*x)/(halfx*halfx))+((y*y)/(halfy*halfy))+((z*z)/(halfz*halfz));
1129 }
1130 }
1131 else if(Shape == "Cylinder")
1132 {
1133 x = Radius*2.;
1134 y = Radius*2.;
1135 while(((x*x)+(y*y)) > (Radius*Radius))
1136 {
1137 x = PosRndm->GenRandX();
1138 y = PosRndm->GenRandY();
1139 z = PosRndm->GenRandZ();
1140
1141 x = (x*2.*Radius) - Radius;
1142 y = (y*2.*Radius) - Radius;
1143 z = (z*2.*halfz) - halfz;
1144 }
1145 }
1146 else if(Shape == "EllipticCylinder")
1147 {
1148 expression = 20.;
1149 while(expression > 1.)
1150 {
1151 x = PosRndm->GenRandX();
1152 y = PosRndm->GenRandY();
1153 z = PosRndm->GenRandZ();
1154
1155 x = (x*2.*halfx) - halfx;
1156 y = (y*2.*halfy) - halfy;
1157 z = (z*2.*halfz) - halfz;
1158
1159 expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
1160 }
1161 }
1162 else if(Shape == "Para")
1163 {
1164 x = PosRndm->GenRandX();
1165 y = PosRndm->GenRandY();
1166 z = PosRndm->GenRandZ();
1167 x = (x*2.*halfx) - halfx;
1168 y = (y*2.*halfy) - halfy;
1169 z = (z*2.*halfz) - halfz;
1170 x = x + z*std::tan(ParTheta)*std::cos(ParPhi) + y*std::tan(ParAlpha);
1171 y = y + z*std::tan(ParTheta)*std::sin(ParPhi);
1172 // z = z;
1173 }
1174 else
1175 {
1176 G4cout << "Error: Volume Shape does not exist" << G4endl;
1177 }
1178
1179 RandPos.setX(x);
1180 RandPos.setY(y);
1181 RandPos.setZ(z);
1182
1183 // Apply Rotation Matrix
1184 // x * Rotx, y * Roty and z * Rotz
1185 //
1186 tempx = (x * Rotx.x()) + (y * Roty.x()) + (z * Rotz.x());
1187 tempy = (x * Rotx.y()) + (y * Roty.y()) + (z * Rotz.y());
1188 tempz = (x * Rotx.z()) + (y * Roty.z()) + (z * Rotz.z());
1189
1190 RandPos.setX(tempx);
1191 RandPos.setY(tempy);
1192 RandPos.setZ(tempz);
1193
1194 // Translate
1195 //
1196 pos = CentreCoords + RandPos;
1197
1198 if(verbosityLevel == 2)
1199 {
1200 G4cout << "Raw position " << x << "," << y << "," << z << G4endl;
1201 G4cout << "Rotated position " << RandPos << G4endl;
1202 }
1203 if(verbosityLevel >= 1)
1204 {
1205 G4cout << "Rotated and translated position " << pos << G4endl;
1206 }
1207
1208 // Cosine-law (not a good idea to use this here)
1209 //
1210 G4ThreeVector zdash(tempx,tempy,tempz);
1211 zdash = zdash.unit();
1212 G4ThreeVector xdash = Rotz.cross(zdash);
1213 G4ThreeVector ydash = xdash.cross(zdash);
1214 thread_data_t& td = ThreadData.Get();
1215 td.CSideRefVec1 = xdash.unit();
1216 td.CSideRefVec2 = ydash.unit();
1217 td.CSideRefVec3 = zdash.unit();
1218 if(verbosityLevel == 2)
1219 {
1220 G4cout << "Reference vectors for cosine-law " << td.CSideRefVec1
1221 << " " << td.CSideRefVec2 << " " << td.CSideRefVec3 << G4endl;
1222 }
1223}
1224
1225G4bool G4SPSPosDistribution::IsSourceConfined(G4ThreeVector& pos)
1226{
1227 // Method to check point is within the volume specified
1228
1229 if(Confine == false)
1230 {
1231 G4cout << "Error: Confine is false" << G4endl;
1232 }
1233 G4ThreeVector null(0.,0.,0.);
1234 G4ThreeVector* ptr = &null;
1235
1236 // Check position is within VolName, if so true, else false
1237 //
1238 G4VPhysicalVolume* theVolume;
1241 theVolume = gNavigator->LocateGlobalPointAndSetup(pos,ptr,true);
1242 if(theVolume == nullptr) { return false; }
1243 G4String theVolName = theVolume->GetName();
1244
1245 if(theVolName == VolName)
1246 {
1247 if(verbosityLevel >= 1)
1248 {
1249 G4cout << "Particle is in volume " << VolName << G4endl;
1250 }
1251 return true;
1252 }
1253 else
1254 {
1255 return false;
1256 }
1257}
1258
1260{
1261 G4ThreeVector localP;
1262 G4bool srcconf = false;
1263 G4int LoopCount = 0;
1264 while(srcconf == false)
1265 {
1266 if(SourcePosType == "Point")
1267 GeneratePointSource(localP);
1268 else if(SourcePosType == "Beam")
1269 GeneratePointsInBeam(localP);
1270 else if(SourcePosType == "Plane")
1271 GeneratePointsInPlane(localP);
1272 else if(SourcePosType == "Surface")
1273 GeneratePointsOnSurface(localP);
1274 else if(SourcePosType == "Volume")
1275 GeneratePointsInVolume(localP);
1276 else
1277 {
1279 msg << "Error: SourcePosType undefined\n";
1280 msg << "Generating point source\n";
1281 G4Exception("G4SPSPosDistribution::GenerateOne()",
1282 "G4GPS001", JustWarning, msg);
1283 GeneratePointSource(localP);
1284 }
1285 if(Confine == true)
1286 {
1287 srcconf = IsSourceConfined(localP);
1288 // if source in confined srcconf = true terminating the loop
1289 // if source isnt confined srcconf = false and loop continues
1290 }
1291 else if(Confine == false)
1292 {
1293 srcconf = true; // terminate loop
1294 }
1295 ++LoopCount;
1296 if(LoopCount == 100000)
1297 {
1299 msg << "LoopCount = 100000\n";
1300 msg << "Either the source distribution >> confinement\n";
1301 msg << "or any confining volume may not overlap with\n";
1302 msg << "the source distribution or any confining volumes\n";
1303 msg << "may not exist\n"<< G4endl;
1304 msg << "If you have set confine then this will be ignored\n";
1305 msg << "for this event.\n" << G4endl;
1306 G4Exception("G4SPSPosDistribution::GenerateOne()",
1307 "G4GPS001", JustWarning, msg);
1308 srcconf = true; // Avoids an infinite loop
1309 }
1310 }
1311 ThreadData.Get().CParticlePos = localP;
1312 return localP;
1313}
1314
@ JustWarning
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:35
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:126
static G4PhysicalVolumeStore * GetInstance()
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