ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4SPSPosDistribution.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4SPSPosDistribution.cc
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 //
27 //
28 // MODULE: G4SPSPosDistribution.cc
29 //
30 // Version: 1.0
31 // Date: 5/02/04
32 // Author: Fan Lei
33 // Organisation: QinetiQ ltd.
34 // Customer: ESA/ESTEC
35 //
37 //
38 // CHANGE HISTORY
39 // --------------
40 //
41 //
42 // Version 1.0, 05/02/2004, Fan Lei, Created.
43 // Based on the G4GeneralParticleSource class in Geant4 v6.0
44 //
45 // Version 1.1, 13/02/2017, Maxime Chauvin
46 // Added surface and volume shape "EllipticCylinder"
47 //
49 //
50 #include "G4SPSPosDistribution.hh"
51 
52 #include "G4PhysicalConstants.hh"
53 #include "Randomize.hh"
55 #include "G4VPhysicalVolume.hh"
56 #include "G4PhysicalVolumeStore.hh"
57 #include "G4AutoLock.hh"
58 #include "G4AutoDelete.hh"
59 
60 
62 {
66  CParticlePos = G4ThreeVector(0,0,0);
67 }
68 
70 {
71  SourcePosType = "Point";
72  Shape = "NULL";
73  CentreCoords = G4ThreeVector(0,0,0);
77  halfx = 0.;
78  halfy = 0.;
79  halfz = 0.;
80  Radius = 0.;
81  Radius0 = 0.;
82  SR = 0.;
83  SX = 0.;
84  SY = 0.;
85  ParAlpha = 0.;
86  ParTheta = 0.;
87  ParPhi = 0.;
88  Confine = false; //If true confines source distribution to VolName
89  VolName = "NULL";
90  verbosityLevel = 0 ;
92 }
93 
95 {
97 }
98 
100 {
101  SourcePosType = PosType;
102 }
103 
105 {
106  Shape = shapeType;
107 }
108 
110 {
111  CentreCoords = coordsOfCentre;
112 }
113 
115 {
116  // This should be x'
117  Rotx = posrot1;
118  if(verbosityLevel == 2)
119  {
120  G4cout << "Vector x' " << Rotx << G4endl;
121  }
123 }
124 
126 {
127  // This is a vector in the plane x'y' but need not
128  // be y'
129  Roty = posrot2;
130  if(verbosityLevel == 2)
131  {
132  G4cout << "The vector in the x'-y' plane " << Roty << G4endl;
133  }
135 }
136 
138 {
139  halfx = xhalf;
140 }
141 
143 {
144  halfy = yhalf;
145 }
146 
148 {
149  halfz = zhalf;
150 }
151 
153 {
154  Radius = rds;
155 }
156 
158 {
159  Radius0 = rds;
160 }
161 
163 {
164  SX = SY = r;
165  SR = r;
166 }
167 
169 {
170  SX = r;
171 }
172 
174 {
175  SY = r;
176 }
177 
179 {
180  ParAlpha = paralp;
181 }
182 
184 {
185  ParTheta = parthe;
186 }
187 
189 {
190  ParPhi = parphi;
191 }
192 
194 {
195  return SourcePosType;
196 }
197 
199 {
200  return Shape;
201 }
202 
204 {
205  return CentreCoords;
206 }
207 
209 {
210  return halfx;
211 }
212 
214 {
215  return halfy;
216 }
217 
219 {
220  return halfz;
221 }
222 
224 {
225  return Radius;
226 }
227 
229 {
230  G4AutoLock l(&a_mutex);
231  PosRndm = a ;
232 }
233 
235 {
236  verbosityLevel = a;
237 }
238 
240  return SourcePosType;
241 }
242 
244  return ThreadData.Get().CParticlePos;
245 }
246 
248  return ThreadData.Get().CSideRefVec1;
249 }
250 
252  return ThreadData.Get().CSideRefVec2;
253 }
254 
256  return ThreadData.Get().CSideRefVec3;
257 }
258 
260 {
261  // This takes in 2 vectors, x' and one in the plane x'-y',
262  // and from these takes a cross product to calculate z'.
263  // Then a cross product is taken between x' and z' to give
264  // y'.
265  Rotx = Rotx.unit(); // x'
266  Roty = Roty.unit(); // vector in x'y' plane
267  Rotz = Rotx.cross(Roty); // z'
268  Rotz = Rotz.unit();
269  Roty =Rotz.cross(Rotx); // y'
270  Roty =Roty.unit();
271  if(verbosityLevel == 2)
272  {
273  G4cout << "The new axes, x', y', z' " << Rotx << " " << Roty << " " << Rotz << G4endl;
274  }
275 }
276 
278 {
279  VolName = Vname;
280  if(verbosityLevel == 2)
281  G4cout << VolName << G4endl;
282 
283  if(VolName=="NULL")
284  {
285  if(verbosityLevel >= 1)
286  { G4cout << "Volume confinement is set off." << G4endl; }
287  Confine = false;
288  return;
289  }
290 
291  G4VPhysicalVolume *tempPV = NULL;
292  G4PhysicalVolumeStore *PVStore = 0;
293  G4String theRequiredVolumeName = VolName;
295  G4int i = 0;
296  G4bool found = false;
297  if(verbosityLevel == 2)
298  G4cout << PVStore->size() << G4endl;
299  while (!found && i<G4int(PVStore->size())) {
300  tempPV = (*PVStore)[i];
301  found = tempPV->GetName() == theRequiredVolumeName;
302  if(verbosityLevel == 2)
303  G4cout << i << " " << " " << tempPV->GetName() << " " << theRequiredVolumeName << " " << found << G4endl;
304  if (!found)
305  {i++;}
306  }
307  // found = true then the volume exists else it doesnt.
308  if(found == true)
309  {
310  if(verbosityLevel >= 1)
311  G4cout << "Volume " << VolName << " exists" << G4endl;
312  Confine = true;
313  }
314  else
315  {
316  G4cout << " **** Error: Volume <" << VolName << "> does not exist **** " << G4endl;
317  G4cout << " Ignoring confine condition" << G4endl;
318  Confine = false;
319  VolName = "NULL";
320  }
321 
322 }
323 
325 {
326  // Generates Points given the point source.
327  if(SourcePosType == "Point")
328  pos = CentreCoords;
329  else
330  if(verbosityLevel >= 1)
331  G4cerr << "Error SourcePosType is not set to Point" << G4endl;
332 }
333 
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  if(Shape == "Circle")
344  {
345  x = Radius + 100.;
346  y = Radius + 100.;
347  while(std::sqrt((x*x) + (y*y)) > Radius)
348  {
349  x = PosRndm->GenRandX();
350  y = PosRndm->GenRandY();
351 
352  x = (x*2.*Radius) - Radius;
353  y = (y*2.*Radius) - Radius;
354  }
355  x += G4RandGauss::shoot(0.0,SX) ;
356  y += G4RandGauss::shoot(0.0,SY) ;
357  }
358  else
359  {
360  // all other cases default to Rectangle case
361  x = PosRndm->GenRandX();
362  y = PosRndm->GenRandY();
363  x = (x*2.*halfx) - halfx;
364  y = (y*2.*halfy) - halfy;
365  x += G4RandGauss::shoot(0.0,SX);
366  y += G4RandGauss::shoot(0.0,SY);
367  }
368  // Apply Rotation Matrix
369  // x * Rotx, y * Roty and z * Rotz
370  if(verbosityLevel >= 2)
371  {
372  G4cout << "Raw position " << x << "," << y << "," << z << G4endl;
373  }
374  tempx = (x * Rotx.x()) + (y * Roty.x()) + (z * Rotz.x());
375  tempy = (x * Rotx.y()) + (y * Roty.y()) + (z * Rotz.y());
376  tempz = (x * Rotx.z()) + (y * Roty.z()) + (z * Rotz.z());
377 
378  RandPos.setX(tempx);
379  RandPos.setY(tempy);
380  RandPos.setZ(tempz);
381 
382  // Translate
383  pos = CentreCoords + RandPos;
384  if(verbosityLevel >= 1)
385  {
386  if(verbosityLevel >= 2)
387  {
388  G4cout << "Rotated Position " << RandPos << G4endl;
389  }
390  G4cout << "Rotated and Translated position " << pos << G4endl;
391  }
392 }
393 
395 {
396  G4double x, y, z;
397  G4double expression;
398  G4ThreeVector RandPos;
399  G4double tempx, tempy, tempz;
400  x = y = z = 0.;
401  thread_data_t& td = ThreadData.Get();
402  if(SourcePosType != "Plane" && verbosityLevel >= 1)
403  G4cerr << "Error: SourcePosType is not Plane" << G4endl;
404 
405  // Private Method to create points in a plane
406  if(Shape == "Circle")
407  {
408  x = Radius + 100.;
409  y = Radius + 100.;
410  while(std::sqrt((x*x) + (y*y)) > Radius)
411  {
412  x = PosRndm->GenRandX();
413  y = PosRndm->GenRandY();
414 
415  x = (x*2.*Radius) - Radius;
416  y = (y*2.*Radius) - Radius;
417  }
418  }
419  else if(Shape == "Annulus")
420  {
421  x = Radius + 100.;
422  y = Radius + 100.;
423  while(std::sqrt((x*x) + (y*y)) > Radius || std::sqrt((x*x) + (y*y)) < Radius0 )
424  {
425  x = PosRndm->GenRandX();
426  y = PosRndm->GenRandY();
427 
428  x = (x*2.*Radius) - Radius;
429  y = (y*2.*Radius) - Radius;
430  }
431  }
432  else if(Shape == "Ellipse")
433  {
434  expression = 20.;
435  while(expression > 1.)
436  {
437  x = PosRndm->GenRandX();
438  y = PosRndm->GenRandY();
439 
440  x = (x*2.*halfx) - halfx;
441  y = (y*2.*halfy) - halfy;
442 
443  expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
444  }
445  }
446  else if(Shape == "Square")
447  {
448  x = PosRndm->GenRandX();
449  y = PosRndm->GenRandY();
450  x = (x*2.*halfx) - halfx;
451  y = (y*2.*halfy) - halfy;
452  }
453  else if(Shape == "Rectangle")
454  {
455  x = PosRndm->GenRandX();
456  y = PosRndm->GenRandY();
457  x = (x*2.*halfx) - halfx;
458  y = (y*2.*halfy) - halfy;
459  }
460  else
461  G4cout << "Shape not one of the plane types" << G4endl;
462 
463  // Apply Rotation Matrix
464  // x * Rotx, y * Roty and z * Rotz
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  pos = CentreCoords + RandPos;
479  if(verbosityLevel >= 1)
480  {
481  if(verbosityLevel == 2)
482  {
483  G4cout << "Rotated Position " << RandPos << G4endl;
484  }
485  G4cout << "Rotated and Translated position " << pos << G4endl;
486  }
487 
488  // For Cosine-Law make SideRefVecs = to Rotation matrix vectors
489  //Note: these need to be thread-local, use G4Cache
490  td.CSideRefVec1 = Rotx;
491  td.CSideRefVec2 = Roty;
492  td.CSideRefVec3 = Rotz;
493  //HandleThreadLocalCache(Rotx,Roty,Rotz);
494  // If rotation matrix z' point to origin then invert the matrix
495  // So that SideRefVecs point away.
496  if((CentreCoords.x() > 0. && Rotz.x() < 0.)
497  || (CentreCoords.x() < 0. && Rotz.x() > 0.)
498  || (CentreCoords.y() > 0. && Rotz.y() < 0.)
499  || (CentreCoords.y() < 0. && Rotz.y() > 0.)
500  || (CentreCoords.z() > 0. && Rotz.z() < 0.)
501  || (CentreCoords.z() < 0. && Rotz.z() > 0.))
502  {
503  // Invert y and z.
504  td.CSideRefVec2 = - td.CSideRefVec2;
505  td.CSideRefVec3 = - td.CSideRefVec3;
506  //HandleThreadLocalCache(*CSideRefVec1.Get(),-(*CSideRefVec2.Get()),-(*CSideRefVec3.Get()));
507  }
508  if(verbosityLevel == 2)
509  {
510  G4cout << "Reference vectors for cosine-law " << td.CSideRefVec1<< " " << td.CSideRefVec2<< " " << td.CSideRefVec3<< G4endl;
511  }
512 }
513 
515 {
516  //Private method to create points on a surface
517  G4double theta, phi;
518  G4double x, y, z;
519  x = y = z = 0.;
520  G4double expression;
521  G4ThreeVector RandPos;
522  // G4double tempx, tempy, tempz;
523  thread_data_t& td = ThreadData.Get();
524  if(SourcePosType != "Surface" && verbosityLevel >= 1)
525  G4cout << "Error SourcePosType not Surface" << G4endl;
526 
527  if(Shape == "Sphere")
528  {
529  // G4double tantheta;
530  theta = PosRndm->GenRandPosTheta();
531  phi = PosRndm->GenRandPosPhi();
532  theta = std::acos(1. - 2.*theta); // theta isotropic
533  phi = phi * 2. * pi;
534  // tantheta = std::tan(theta);
535 
536  x = Radius * std::sin(theta) * std::cos(phi);
537  y = Radius * std::sin(theta) * std::sin(phi);
538  z = Radius * std::cos(theta);
539 
540  RandPos.setX(x);
541  RandPos.setY(y);
542  RandPos.setZ(z);
543 
544  // Cosine-law (not a good idea to use this here)
545  G4ThreeVector zdash(x,y,z);
546  zdash = zdash.unit();
547  G4ThreeVector xdash = Rotz.cross(zdash);
548  G4ThreeVector ydash = xdash.cross(zdash);
549  td.CSideRefVec1 = xdash.unit();
550  td.CSideRefVec2 = ydash.unit();
551  td.CSideRefVec3 = zdash.unit();
552  //HandleThreadLocalCache(xdash.unit(),ydash.unit(),zdash.unit());
553  }
554  else if(Shape == "Ellipsoid")
555  {
556  G4double minphi, maxphi, middlephi;
557  G4double answer, constant;
558 
559  constant = pi/(halfx*halfx) + pi/(halfy*halfy) +
560  twopi/(halfz*halfz);
561 
562  // simplified approach
563  theta = PosRndm->GenRandPosTheta();
564  phi = PosRndm->GenRandPosPhi();
565 
566  theta = std::acos(1. - 2.*theta);
567  minphi = 0.;
568  maxphi = twopi;
569  while(maxphi-minphi > 0.)
570  {
571  middlephi = (maxphi+minphi)/2.;
572  answer = (1./(halfx*halfx))*(middlephi/2. + std::sin(2*middlephi)/4.)
573  + (1./(halfy*halfy))*(middlephi/2. - std::sin(2*middlephi)/4.)
574  + middlephi/(halfz*halfz);
575  answer = answer/constant;
576  if(answer > phi) maxphi = middlephi;
577  if(answer < phi) minphi = middlephi;
578  if(std::fabs(answer-phi) <= 0.00001)
579  {
580  minphi = maxphi +1;
581  phi = middlephi;
582  }
583  }
584 
585  x = std::sin(theta)*std::cos(phi);
586  y = std::sin(theta)*std::sin(phi);
587  z = std::cos(theta);
588  // x,y and z form a unit vector. Put this onto the ellipse.
589  G4double lhs;
590  // solve for x
591  G4double numYinX = y/x;
592  G4double numZinX = z/x;
593  G4double tempxvar;
594  tempxvar= 1./(halfx*halfx)+(numYinX*numYinX)/(halfy*halfy)
595  + (numZinX*numZinX)/(halfz*halfz);
596 
597  tempxvar = 1./tempxvar;
598  G4double coordx = std::sqrt(tempxvar);
599 
600  //solve for y
601  G4double numXinY = x/y;
602  G4double numZinY = z/y;
603  G4double tempyvar;
604  tempyvar=(numXinY*numXinY)/(halfx*halfx)+1./(halfy*halfy)
605  +(numZinY*numZinY)/(halfz*halfz);
606  tempyvar = 1./tempyvar;
607  G4double coordy = std::sqrt(tempyvar);
608 
609  //solve for z
610  G4double numXinZ = x/z;
611  G4double numYinZ = y/z;
612  G4double tempzvar;
613  tempzvar=(numXinZ*numXinZ)/(halfx*halfx)
614  +(numYinZ*numYinZ)/(halfy*halfy)+1./(halfz*halfz);
615  tempzvar = 1./tempzvar;
616  G4double coordz = std::sqrt(tempzvar);
617 
618  lhs = std::sqrt((coordx*coordx)/(halfx*halfx) +
619  (coordy*coordy)/(halfy*halfy) +
620  (coordz*coordz)/(halfz*halfz));
621 
622  if(std::fabs(lhs-1.) > 0.001 && verbosityLevel >= 1)
623  G4cout << "Error: theta, phi not really on ellipsoid" << G4endl;
624 
625  // coordx, coordy and coordz are all positive
626  G4double TestRandVar = G4UniformRand();
627  if(TestRandVar > 0.5)
628  {
629  coordx = -coordx;
630  }
631  TestRandVar = G4UniformRand();
632  if(TestRandVar > 0.5)
633  {
634  coordy = -coordy;
635  }
636  TestRandVar = G4UniformRand();
637  if(TestRandVar > 0.5)
638  {
639  coordz = -coordz;
640  }
641 
642  RandPos.setX(coordx);
643  RandPos.setY(coordy);
644  RandPos.setZ(coordz);
645 
646  // Cosine-law (not a good idea to use this here)
647  G4ThreeVector zdash(coordx,coordy,coordz);
648  zdash = zdash.unit();
649  G4ThreeVector xdash = Rotz.cross(zdash);
650  G4ThreeVector ydash = xdash.cross(zdash);
651  td.CSideRefVec1 = xdash.unit();
652  td.CSideRefVec2 = ydash.unit();
653  td.CSideRefVec3 = zdash.unit();
654  }
655  else if(Shape == "Cylinder")
656  {
657  G4double AreaTop, AreaBot, AreaLat;
658  G4double AreaTotal, prob1, prob2, prob3;
659  G4double testrand;
660 
661  // User giver Radius and z-half length
662  // Calculate surface areas, maybe move this to
663  // a different routine.
664 
665  AreaTop = pi * Radius * Radius;
666  AreaBot = AreaTop;
667  AreaLat = 2. * pi * Radius * 2. * halfz;
668  AreaTotal = AreaTop + AreaBot + AreaLat;
669 
670  prob1 = AreaTop / AreaTotal;
671  prob2 = AreaBot / AreaTotal;
672  prob3 = 1.00 - prob1 - prob2;
673  if(std::fabs(prob3 - (AreaLat/AreaTotal)) >= 0.001)
674  {
675  if(verbosityLevel >= 1)
676  G4cout << AreaLat/AreaTotal << " " << prob3<<G4endl;
677  G4cout << "Error in prob3" << G4endl;
678  }
679 
680  // Decide surface to calculate point on.
681 
682  testrand = G4UniformRand();
683  if(testrand <= prob1)
684  {
685  //Point on Top surface
686  z = halfz;
687  x = Radius + 100.;
688  y = Radius + 100.;
689  while(((x*x)+(y*y)) > (Radius*Radius))
690  {
691  x = PosRndm->GenRandX();
692  y = PosRndm->GenRandY();
693 
694  x = x * 2. * Radius;
695  y = y * 2. * Radius;
696  x = x - Radius;
697  y = y - Radius;
698  }
699  // Cosine law
700  td.CSideRefVec1 = Rotx;
701  td.CSideRefVec2 = Roty;
702  td.CSideRefVec3 = Rotz;
703  }
704  else if((testrand > prob1) && (testrand <= (prob1 + prob2)))
705  {
706  //Point on Bottom surface
707  z = -halfz;
708  x = Radius + 100.;
709  y = Radius + 100.;
710  while(((x*x)+(y*y)) > (Radius*Radius))
711  {
712  x = PosRndm->GenRandX();
713  y = PosRndm->GenRandY();
714 
715  x = x * 2. * Radius;
716  y = y * 2. * Radius;
717  x = x - Radius;
718  y = y - Radius;
719  }
720  // Cosine law
721  td.CSideRefVec1 = Rotx;
722  td.CSideRefVec2 = -Roty;
723  td.CSideRefVec3 = -Rotz;
724  }
725  else if(testrand > (prob1+prob2))
726  {
727  G4double rand;
728  //Point on Lateral Surface
729 
730  rand = PosRndm->GenRandPosPhi();
731  rand = rand * 2. * pi;
732 
733  x = Radius * std::cos(rand);
734  y = Radius * std::sin(rand);
735 
736  z = PosRndm->GenRandZ();
737 
738  z = z * 2. *halfz;
739  z = z - halfz;
740 
741  // Cosine law
742  G4ThreeVector zdash(x,y,0.);
743  zdash = zdash.unit();
744  G4ThreeVector xdash = Rotz.cross(zdash);
745  G4ThreeVector ydash = xdash.cross(zdash);
746  td.CSideRefVec1 = xdash.unit();
747  td.CSideRefVec2 = ydash.unit();
748  td.CSideRefVec3 = zdash.unit();
749  }
750  else
751  G4cout << "Error: testrand " << testrand << G4endl;
752 
753  RandPos.setX(x);
754  RandPos.setY(y);
755  RandPos.setZ(z);
756 
757  }
758  else if(Shape == "EllipticCylinder")
759  {
760  G4double AreaTop, AreaBot, AreaLat, AreaTotal;
761  G4double h;
762  G4double prob1, prob2, prob3;
763  G4double testrand;
764 
765  // User giver x, y and z-half length
766  // Calculate surface areas, maybe move this to
767  // a different routine.
768 
769  AreaTop = pi * halfx * halfy;
770  AreaBot = AreaTop;
771  // Using circumference approximation by Ramanujan (order h^3)
772  //AreaLat = 2*halfz * pi*( 3*(halfx + halfy) - std::sqrt((3*halfx + halfy) * (halfx + 3*halfy)) );
773  // Using circumference approximation by Ramanujan (order h^5)
774  h = ((halfx - halfy)*(halfx - halfy)) / ((halfx + halfy)*(halfx + halfy));
775  AreaLat = 2*halfz * pi*(halfx + halfy)*(1 + (3*h)/(10 + std::sqrt(4 - 3*h)));
776  AreaTotal = AreaTop + AreaBot + AreaLat;
777 
778  prob1 = AreaTop / AreaTotal;
779  prob2 = AreaBot / AreaTotal;
780  prob3 = 1.00 - prob1 - prob2;
781  if(std::fabs(prob3 - (AreaLat/AreaTotal)) >= 0.001)
782  {
783  if(verbosityLevel >= 1)
784  G4cout << AreaLat/AreaTotal << " " << prob3<<G4endl;
785  G4cout << "Error in prob3" << G4endl;
786  }
787 
788  // Decide surface to calculate point on.
789 
790  testrand = G4UniformRand();
791  if(testrand <= prob1)
792  {
793  //Point on Top surface
794  z = halfz;
795  expression = 20.;
796  while(expression > 1.)
797  {
798  x = PosRndm->GenRandX();
799  y = PosRndm->GenRandY();
800 
801  x = (x * 2. * halfx) - halfx;
802  y = (y * 2. * halfy) - halfy;
803 
804  expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
805  }
806  }
807  else if((testrand > prob1) && (testrand <= (prob1 + prob2)))
808  {
809  //Point on Bottom surface
810  z = -halfz;
811  expression = 20.;
812  while(expression > 1.)
813  {
814  x = PosRndm->GenRandX();
815  y = PosRndm->GenRandY();
816 
817  x = (x * 2. * halfx) - halfx;
818  y = (y * 2. * halfy) - halfy;
819 
820  expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
821  }
822  }
823  else if(testrand > (prob1+prob2))
824  {
825  G4double rand;
826  //Point on Lateral Surface
827  rand = PosRndm->GenRandPosPhi();
828  rand = rand * 2. * pi;
829 
830  x = halfx * std::cos(rand);
831  y = halfy * std::sin(rand);
832 
833  z = PosRndm->GenRandZ();
834 
835  z = (z * 2. * halfz) - halfz;
836  }
837  else
838  G4cout << "Error: testrand " << testrand << G4endl;
839 
840  RandPos.setX(x);
841  RandPos.setY(y);
842  RandPos.setZ(z);
843 
844  // Cosine law
845  G4ThreeVector zdash(x,y,z);
846  zdash = zdash.unit();
847  G4ThreeVector xdash = Rotz.cross(zdash);
848  G4ThreeVector ydash = xdash.cross(zdash);
849  td.CSideRefVec1 = xdash.unit();
850  td.CSideRefVec2 = ydash.unit();
851  td.CSideRefVec3 = zdash.unit();
852  }
853  else if(Shape == "Para")
854  {
855  G4double testrand;
856  //Right Parallelepiped.
857  // User gives x,y,z half lengths and ParAlpha
858  // ParTheta and ParPhi
859  // +x = <1, -x >1 & <2, +y >2 & <3, -y >3 &<4
860  // +z >4 & < 5, -z >5 &<6.
861  testrand = G4UniformRand();
862  G4double AreaX = halfy * halfz * 4.;
863  G4double AreaY = halfx * halfz * 4.;
864  G4double AreaZ = halfx * halfy * 4.;
865  G4double AreaTotal = 2*(AreaX + AreaY + AreaZ);
866  G4double Probs[6];
867  Probs[0] = AreaX/AreaTotal;
868  Probs[1] = Probs[0] + AreaX/AreaTotal;
869  Probs[2] = Probs[1] + AreaY/AreaTotal;
870  Probs[3] = Probs[2] + AreaY/AreaTotal;
871  Probs[4] = Probs[3] + AreaZ/AreaTotal;
872  Probs[5] = Probs[4] + AreaZ/AreaTotal;
873 
874  x = PosRndm->GenRandX();
875  y = PosRndm->GenRandY();
876  z = PosRndm->GenRandZ();
877 
878  x = x * halfx * 2.;
879  x = x - halfx;
880  y = y * halfy * 2.;
881  y = y - halfy;
882  z = z * halfz * 2.;
883  z = z - halfz;
884  // Pick a side first
885  if(testrand < Probs[0])
886  {
887  // side is +x
888  x = halfx + z*std::tan(ParTheta)*std::cos(ParPhi) + y*std::tan(ParAlpha);
889  y = y + z*std::tan(ParTheta)*std::sin(ParPhi);
890  // z = z;
891  // Cosine-law
892  G4ThreeVector xdash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
893  halfz*std::tan(ParTheta)*std::sin(ParPhi),
894  halfz/std::cos(ParPhi));
895  G4ThreeVector ydash(halfy*std::tan(ParAlpha), -halfy, 0.0);
896  xdash = xdash.unit();
897  ydash = ydash.unit();
898  G4ThreeVector zdash = xdash.cross(ydash);
899  td.CSideRefVec1 = xdash.unit();
900  td.CSideRefVec2 = ydash.unit();
901  td.CSideRefVec3 = zdash.unit();
902  }
903  else if(testrand >= Probs[0] && testrand < Probs[1])
904  {
905  // side is -x
906  x = -halfx + z*std::tan(ParTheta)*std::cos(ParPhi) + y*std::tan(ParAlpha);
907  y = y + z*std::tan(ParTheta)*std::sin(ParPhi);
908  // z = z;
909  // Cosine-law
910  G4ThreeVector xdash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
911  halfz*std::tan(ParTheta)*std::sin(ParPhi),
912  halfz/std::cos(ParPhi));
913  G4ThreeVector ydash(halfy*std::tan(ParAlpha), halfy, 0.0);
914  xdash = xdash.unit();
915  ydash = ydash.unit();
916  G4ThreeVector zdash = xdash.cross(ydash);
917  td.CSideRefVec1 = xdash.unit();
918  td.CSideRefVec2 = ydash.unit();
919  td.CSideRefVec3 = zdash.unit();
920  }
921  else if(testrand >= Probs[1] && testrand < Probs[2])
922  {
923  // side is +y
924  x = x + z*std::tan(ParTheta)*std::cos(ParPhi) + halfy*std::tan(ParAlpha);
925  y = halfy + z*std::tan(ParTheta)*std::sin(ParPhi);
926  // z = z;
927  // Cosine-law
928  G4ThreeVector ydash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
929  halfz*std::tan(ParTheta)*std::sin(ParPhi),
930  halfz/std::cos(ParPhi));
931  ydash = ydash.unit();
932  G4ThreeVector xdash = Roty.cross(ydash);
933  G4ThreeVector zdash = xdash.cross(ydash);
934  td.CSideRefVec1 = xdash.unit();
935  td.CSideRefVec2 = -ydash.unit();
936  td.CSideRefVec3 = -zdash.unit();
937  }
938  else if(testrand >= Probs[2] && testrand < Probs[3])
939  {
940  // side is -y
941  x = x + z*std::tan(ParTheta)*std::cos(ParPhi) - halfy*std::tan(ParAlpha);
942  y = -halfy + z*std::tan(ParTheta)*std::sin(ParPhi);
943  // z = z;
944  // Cosine-law
945  G4ThreeVector ydash(halfz*std::tan(ParTheta)*std::cos(ParPhi),
946  halfz*std::tan(ParTheta)*std::sin(ParPhi),
947  halfz/std::cos(ParPhi));
948  ydash = ydash.unit();
949  G4ThreeVector xdash = Roty.cross(ydash);
950  G4ThreeVector zdash = xdash.cross(ydash);
951  td.CSideRefVec1 = xdash.unit();
952  td.CSideRefVec2 = ydash.unit();
953  td.CSideRefVec3 = zdash.unit();
954  }
955  else if(testrand >= Probs[3] && testrand < Probs[4])
956  {
957  // side is +z
958  z = halfz;
959  y = y + halfz*std::sin(ParPhi)*std::tan(ParTheta);
960  x = x + halfz*std::cos(ParPhi)*std::tan(ParTheta) + y*std::tan(ParAlpha);
961  // Cosine-law
962  td.CSideRefVec1 = Rotx;
963  td.CSideRefVec2 = Roty;
964  td.CSideRefVec3 = Rotz;
965  }
966  else if(testrand >= Probs[4] && testrand < Probs[5])
967  {
968  // side is -z
969  z = -halfz;
970  y = y - halfz*std::sin(ParPhi)*std::tan(ParTheta);
971  x = x - halfz*std::cos(ParPhi)*std::tan(ParTheta) + y*std::tan(ParAlpha);
972  // Cosine-law
973  td.CSideRefVec1 = Rotx;
974  td.CSideRefVec2 = -Roty;
975  td.CSideRefVec3 = -Rotz;
976  }
977  else
978  {
979  G4cout << "Error: testrand out of range" << G4endl;
980  if(verbosityLevel >= 1)
981  G4cout << "testrand=" << testrand << " Probs[5]=" << Probs[5] <<G4endl;
982  }
983 
984  RandPos.setX(x);
985  RandPos.setY(y);
986  RandPos.setZ(z);
987  }
988 
989  // Apply Rotation Matrix
990  // x * Rotx, y * Roty and z * Rotz
991  if(verbosityLevel == 2)
992  G4cout << "Raw position " << RandPos << G4endl;
993 
994  x=(RandPos.x()*Rotx.x())+(RandPos.y()*Roty.x())+(RandPos.z()*Rotz.x());
995  y=(RandPos.x()*Rotx.y())+(RandPos.y()*Roty.y())+(RandPos.z()*Rotz.y());
996  z=(RandPos.x()*Rotx.z())+(RandPos.y()*Roty.z())+(RandPos.z()*Rotz.z());
997 
998  RandPos.setX(x);
999  RandPos.setY(y);
1000  RandPos.setZ(z);
1001 
1002  // Translate
1003  pos = CentreCoords + RandPos;
1004 
1005  if(verbosityLevel >= 1)
1006  {
1007  if(verbosityLevel == 2)
1008  G4cout << "Rotated position " << RandPos << G4endl;
1009  G4cout << "Rotated and translated position " << pos << G4endl;
1010  }
1011  if(verbosityLevel == 2)
1012  {
1013  G4cout << "Reference vectors for cosine-law " << td.CSideRefVec1 << " " << td.CSideRefVec2 << " " << td.CSideRefVec3 << G4endl;
1014  }
1015 }
1016 
1018 {
1019  G4ThreeVector RandPos;
1020  G4double tempx, tempy, tempz;
1021  G4double x, y, z;
1022  G4double expression;
1023  x = y = z = 0.;
1024  if(SourcePosType != "Volume" && verbosityLevel >= 1)
1025  G4cout << "Error SourcePosType not Volume" << G4endl;
1026  //Private method to create points in a volume
1027  if(Shape == "Sphere")
1028  {
1029  x = Radius*2.;
1030  y = Radius*2.;
1031  z = Radius*2.;
1032  while(((x*x)+(y*y)+(z*z)) > (Radius*Radius))
1033  {
1034  x = PosRndm->GenRandX();
1035  y = PosRndm->GenRandY();
1036  z = PosRndm->GenRandZ();
1037 
1038  x = (x*2.*Radius) - Radius;
1039  y = (y*2.*Radius) - Radius;
1040  z = (z*2.*Radius) - Radius;
1041  }
1042  }
1043  else if(Shape == "Ellipsoid")
1044  {
1045  G4double temp;
1046  temp = 100.;
1047  while(temp > 1.)
1048  {
1049  x = PosRndm->GenRandX();
1050  y = PosRndm->GenRandY();
1051  z = PosRndm->GenRandZ();
1052 
1053  x = (x*2.*halfx) - halfx;
1054  y = (y*2.*halfy) - halfy;
1055  z = (z*2.*halfz) - halfz;
1056 
1057  temp = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy))
1058  + ((z*z)/(halfz*halfz));
1059  }
1060  }
1061  else if(Shape == "Cylinder")
1062  {
1063  x = Radius*2.;
1064  y = Radius*2.;
1065  while(((x*x)+(y*y)) > (Radius*Radius))
1066  {
1067  x = PosRndm->GenRandX();
1068  y = PosRndm->GenRandY();
1069  z = PosRndm->GenRandZ();
1070 
1071  x = (x*2.*Radius) - Radius;
1072  y = (y*2.*Radius) - Radius;
1073  z = (z*2.*halfz) - halfz;
1074  }
1075  }
1076  else if(Shape == "EllipticCylinder")
1077  {
1078  expression = 20.;
1079  while(expression > 1.)
1080  {
1081  x = PosRndm->GenRandX();
1082  y = PosRndm->GenRandY();
1083  z = PosRndm->GenRandZ();
1084 
1085  x = (x*2.*halfx) - halfx;
1086  y = (y*2.*halfy) - halfy;
1087  z = (z*2.*halfz) - halfz;
1088 
1089  expression = ((x*x)/(halfx*halfx)) + ((y*y)/(halfy*halfy));
1090  }
1091  }
1092  else if(Shape == "Para")
1093  {
1094  x = PosRndm->GenRandX();
1095  y = PosRndm->GenRandY();
1096  z = PosRndm->GenRandZ();
1097  x = (x*2.*halfx) - halfx;
1098  y = (y*2.*halfy) - halfy;
1099  z = (z*2.*halfz) - halfz;
1100  x = x + z*std::tan(ParTheta)*std::cos(ParPhi) + y*std::tan(ParAlpha);
1101  y = y + z*std::tan(ParTheta)*std::sin(ParPhi);
1102  // z = z;
1103  }
1104  else
1105  G4cout << "Error: Volume Shape Doesnt Exist" << G4endl;
1106 
1107  RandPos.setX(x);
1108  RandPos.setY(y);
1109  RandPos.setZ(z);
1110 
1111  // Apply Rotation Matrix
1112  // x * Rotx, y * Roty and z * Rotz
1113  tempx = (x * Rotx.x()) + (y * Roty.x()) + (z * Rotz.x());
1114  tempy = (x * Rotx.y()) + (y * Roty.y()) + (z * Rotz.y());
1115  tempz = (x * Rotx.z()) + (y * Roty.z()) + (z * Rotz.z());
1116 
1117  RandPos.setX(tempx);
1118  RandPos.setY(tempy);
1119  RandPos.setZ(tempz);
1120 
1121  // Translate
1122  pos = CentreCoords + RandPos;
1123 
1124  if(verbosityLevel == 2)
1125  {
1126  G4cout << "Raw position " << x << "," << y << "," << z << G4endl;
1127  G4cout << "Rotated position " << RandPos << G4endl;
1128  }
1129  if(verbosityLevel >= 1)
1130  G4cout << "Rotated and translated position " << pos << G4endl;
1131 
1132  // Cosine-law (not a good idea to use this here)
1133  G4ThreeVector zdash(tempx,tempy,tempz);
1134  zdash = zdash.unit();
1135  G4ThreeVector xdash = Rotz.cross(zdash);
1136  G4ThreeVector ydash = xdash.cross(zdash);
1137  thread_data_t& td = ThreadData.Get();
1138  td.CSideRefVec1 = xdash.unit();
1139  td.CSideRefVec2 = ydash.unit();
1140  td.CSideRefVec3 = zdash.unit();
1141  if(verbosityLevel == 2)
1142  {
1143  G4cout << "Reference vectors for cosine-law " << td.CSideRefVec1 << " " << td.CSideRefVec2 << " " << td.CSideRefVec3 << G4endl;
1144  }
1145 }
1146 
1148 {
1149  // Method to check point is within the volume specified
1150  if(Confine == false)
1151  G4cout << "Error: Confine is false" << G4endl;
1152  G4ThreeVector null(0.,0.,0.);
1153  G4ThreeVector *ptr;
1154  ptr = &null;
1155 
1156  // Check position is within VolName, if so true,
1157  // else false
1158  G4VPhysicalVolume *theVolume;
1160  theVolume=gNavigator->LocateGlobalPointAndSetup(pos,ptr,true);
1161  if(!theVolume) return(false);
1162  G4String theVolName = theVolume->GetName();
1163 
1164  if(theVolName == VolName)
1165  {
1166  if(verbosityLevel >= 1)
1167  G4cout << "Particle is in volume " << VolName << G4endl;
1168  return(true);
1169  }
1170  else
1171  return(false);
1172 }
1173 
1175 {
1176  //
1177  G4ThreeVector localP;
1178  G4bool srcconf = false;
1179  G4int LoopCount = 0;
1180  while(srcconf == false)
1181  {
1182  if(SourcePosType == "Point")
1183  GeneratePointSource(localP);
1184  else if(SourcePosType == "Beam")
1185  GeneratePointsInBeam(localP);
1186  else if(SourcePosType == "Plane")
1187  GeneratePointsInPlane(localP);
1188  else if(SourcePosType == "Surface")
1189  GeneratePointsOnSurface(localP);
1190  else if(SourcePosType == "Volume")
1191  GeneratePointsInVolume(localP);
1192  else
1193  {
1195  msg << "Error: SourcePosType undefined\n";
1196  msg << "Generating point source\n";
1197  G4Exception("G4SPSPosDistribution::GenerateOne()","G4GPS001",JustWarning,msg);
1198  GeneratePointSource(localP);
1199  }
1200  if(Confine == true)
1201  {
1202  srcconf = IsSourceConfined(localP);
1203  // if source in confined srcconf = true terminating the loop
1204  // if source isnt confined srcconf = false and loop continues
1205  }
1206  else if(Confine == false)
1207  srcconf = true; // terminate loop
1208  LoopCount++;
1209  if(LoopCount == 100000)
1210  {
1212  msg << "LoopCount = 100000\n";
1213  msg << "Either the source distribution >> confinement\n";
1214  msg << "or any confining volume may not overlap with\n";
1215  msg << "the source distribution or any confining volumes\n";
1216  msg << "may not exist\n"<< G4endl;
1217  msg << "If you have set confine then this will be ignored\n";
1218  msg << "for this event.\n" << G4endl;
1219  G4Exception("G4SPSPosDistribution::GenerateOne()","G4GPS001",JustWarning,msg);
1220  srcconf = true; //Avoids an infinite loop
1221  }
1222  }
1223  ThreadData.Get().CParticlePos=localP;
1224  return localP;
1225 }
1226 
1227 
1228 
1229