G4StationSimulator/G4TankOpBoundaryProcess.cc
Go to the documentation of this file.
1 #include <config.h>
2 
4 // Optical Photon Boundary Process Class Implementation
6 //
7 // File: G4TankOpBoundaryProcess.cc
8 // Description: Discrete Process -- reflection/refraction at
9 // optical interfaces
10 // Version: 1.1
11 // Created: 1997-06-18
12 // Modified: 1998-05-25 - Correct parallel component of polarization
13 // (thanks to: Stefano Magni + Giovanni Pieri)
14 // 1998-05-28 - NULL Rindex pointer before reuse
15 // (thanks to: Stefano Magni)
16 // 1998-06-11 - delete *sint1 in oblique reflection
17 // (thanks to: Giovanni Pieri)
18 // 1998-06-19 - move from GetLocalExitNormal() to the new
19 // method: GetLocalExitNormal(&valid) to get
20 // the surface normal in all cases
21 // 1998-11-07 - NULL OpticalSurface pointer before use
22 // comparison not sharp for: abs(cost1) < 1.0
23 // remove sin1, sin2 in lines 556,567
24 // (thanks to Stefano Magni)
25 // 1999-10-10 - Accommodate changes done in DoAbsorption by
26 // changing logic in DielectricMetal
27 //
28 // Author: Peter Gumplinger
29 // adopted from work by Werner Keil - April 2/96
30 // mail: gum@triumf.ca
31 //
33 
34 #include "G4ios.hh"
35 #include "G4ProcessType.hh"
36 
38 
39 #include <utl/Math.h>
40 #include <utl/config.h>
41 
42 #include <iostream>
43 
44 using namespace std;
45 using utl::Sqr;
46 
47 
48 namespace G4StationSimulatorOG {
49 
50  G4TankOpBoundaryProcess::G4TankOpBoundaryProcess(const G4String& processName,
51  const G4ProcessType /*type*/) :
52  G4VDiscreteProcess(processName, fOptical)
53  {
54  if (verboseLevel > 0)
55  G4cerr << GetProcessName() << " is created " << G4endl;
56  }
57 
58 
59  G4VParticleChange*
60  G4TankOpBoundaryProcess::PostStepDoIt(const G4Track& track, const G4Step& step)
61  {
62  aParticleChange.Initialize(track);
63 
64  G4StepPoint* const preStepPoint = step.GetPreStepPoint();
65  G4StepPoint* const postStepPoint = step.GetPostStepPoint();
66 
67  if (postStepPoint->GetStepStatus() != fGeomBoundary)
68  return G4VDiscreteProcess::PostStepDoIt(track, step);
69 
70  if (track.GetStepLength() <= kCarTolerance / 2)
71  return G4VDiscreteProcess::PostStepDoIt(track, step);
72 
73  fMaterial1 = preStepPoint->GetPhysicalVolume()->GetLogicalVolume()->GetMaterial();
74  fMaterial2 = postStepPoint->GetPhysicalVolume()->GetLogicalVolume()->GetMaterial();
75 
76  if (fMaterial1 == fMaterial2)
77  return G4VDiscreteProcess::PostStepDoIt(track, step);
78 
79  const G4DynamicParticle* const particle = track.GetDynamicParticle();
80 
81  fPhotonMomentum = particle->GetTotalMomentum();
82  fOldMomentum = particle->GetMomentumDirection();
83  fOldPolarization = particle->GetPolarization();
84 
85  if (verboseLevel > 0) {
86  G4cerr << " Photon at Boundary!\n"
87  " Old Momentum Direction: " << fOldMomentum << "\n"
88  " Old Polarization: " << fOldPolarization << G4endl;
89  }
90 
91  {
92  const auto t = fMaterial1->GetMaterialPropertiesTable();
93  const auto ri = t ? t->GetProperty("RINDEX") : nullptr;
94  if (ri)
95  fRIndex1 = ri->Value(fPhotonMomentum);
96  else {
97  fRIndex1 = 0;
98  aParticleChange.ProposeTrackStatus(fStopAndKill);
99  return G4VDiscreteProcess::PostStepDoIt(track, step);
100  }
101  }
102 
103  if (const auto s = G4LogicalBorderSurface::GetSurface(preStepPoint->GetPhysicalVolume(), postStepPoint->GetPhysicalVolume()))
104  fOpticalSurface = (G4OpticalSurface*)s->GetSurfaceProperty();
105  else if (const auto s = G4LogicalSkinSurface::GetSurface(preStepPoint->GetPhysicalVolume()->GetLogicalVolume()))
106  fOpticalSurface = (G4OpticalSurface*)s->GetSurfaceProperty();
107  else
108  fOpticalSurface = nullptr;
109 
110  fModel = glisur;
111  fFinish = polished;
112 
113  G4SurfaceType type = dielectric_dielectric;
114  fRIndex2 = 0;
115  {
116  const auto t = fMaterial2->GetMaterialPropertiesTable();
117  const auto ri = t ? t->GetProperty("RINDEX") : nullptr;
118  if (ri) {
119  fRIndex2 = ri->Value(fPhotonMomentum);
120  } else if (fOpticalSurface) {
121  type = fOpticalSurface->GetType();
122  } else {
123  fRIndex2 = 0;
124  aParticleChange.ProposeTrackStatus(fStopAndKill);
125  return G4VDiscreteProcess::PostStepDoIt(track, step);
126  }
127  }
128 
129  if (fOpticalSurface) {
130  fModel = fOpticalSurface->GetModel();
131  fFinish = fOpticalSurface->GetFinish();
132  const auto t = fOpticalSurface->GetMaterialPropertiesTable();
133  if (t) {
134  if (!fRIndex2) {
135  if (const auto p = t->GetProperty("RINDEX"))
136  fRIndex2 = p->Value(fPhotonMomentum);
137  }
138  if (const auto p = t->GetProperty("REFLECTIVITY"))
139  fReflectivity = p->Value(fPhotonMomentum);
140  if (const auto p = t->GetProperty("EFFICIENCY"))
141  fEfficiency = p->Value(fPhotonMomentum);
142  if (fModel == unified) {
143  if (const auto p = t->GetProperty("SPECULARLOBECONSTANT"))
144  fProb_sl = p->Value(fPhotonMomentum);
145  if (const auto p = t->GetProperty("SPECULARSPIKECONSTANT"))
146  fProb_ss = p->Value(fPhotonMomentum);
147  if (const auto p = t->GetProperty("BACKSCATTERCONSTANT"))
148  fProb_bs = p->Value(fPhotonMomentum);
149  }
150  }
151  }
152 
153  // No optical surface
154 
155  const G4ThreeVector& globalPoint = postStepPoint->GetPosition();
156 
157  G4Navigator* const navigator = G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking();
158 
159  const G4ThreeVector localPoint = navigator->GetGlobalToLocalTransform().TransformPoint(globalPoint);
160 
161  G4bool valid = false;
162  // Normal points back into volume
163  const G4ThreeVector localNormal = -navigator->GetLocalExitNormal(&valid);
164  if (!valid) {
165  G4cerr << " G4TankOpBoundaryProcess/PostStepDoIt(): "
166  " The Navigator reports that it returned an invalid normal"
167  << G4endl;
168  }
169 
170  fGlobalNormal = navigator->GetLocalToGlobalTransform().TransformAxis(localNormal);
171  fStatus = Undefined;
172 
173  if (type == dielectric_metal)
174 
175  DielectricMetal();
176 
177  else if (type == dielectric_dielectric) {
178 
179  if (fFinish == polishedfrontpainted || fFinish == groundfrontpainted) {
180 
182 
183  DoAbsorption();
184 
185  } else {
186 
187  if (fFinish == groundfrontpainted)
189  DoReflection();
190 
191  }
192 
193  } else {
194 
195  // MY HACK (tp) (I added the DoAbsorption option so that it takes
196  // effect even for the ground finish. I had to do this because
197  // groundbackpainted option causes a crash somewhere in G4Tubs..)
198  // tm : Oct. 19, 2001
199  // This hack creates a problem when the photons go directly from the
200  // water to a surface where the OpticalSurface machinery has not been
201  // used (like the dome) The reflectivity is then 0 and all the photon
202  // are absorbed. Also, this hack screws up a normal optical interface
203  // because it checks against the reflectivity instead of doing it the
204  // way it should, in for example, Jackson. Only check against the
205  // reflectivity for tyvek...
206 
207  if (fMaterial2->GetName() == "HDPE") {
208 
210  DoAbsorption();
211  else
213 
214  } else {
215 
217 
218  }
219 
220  }
221 
222  } else {
223 
224  G4cerr << " Error: G4BoundaryProcess: illegal boundary type " << G4endl;
225  return G4VDiscreteProcess::PostStepDoIt(track, step);
226 
227  }
228 
229  fNewMomentum = fNewMomentum.unit();
231 
232  aParticleChange.ProposeMomentumDirection(fNewMomentum);
233  aParticleChange.ProposePolarization(fNewPolarization);
234 
235  return G4VDiscreteProcess::PostStepDoIt(track, step);
236  }
237 
238 
239  G4ThreeVector
241  const
242  {
243  // Returns a random isotropic unit vector
244  G4ThreeVector vect;
245  G4double len2;
246  do {
247  vect.set(G4UniformRand() - 0.5, G4UniformRand() - 0.5, G4UniformRand() - 0.5);
248  len2 = vect.mag2();
249  } while (len2 < 0.01 || len2 > 0.25);
250  return vect.unit();
251  }
252 
253 
254  G4ThreeVector
255  G4TankOpBoundaryProcess::G4LambertianRand(const G4ThreeVector& normal)
256  const
257  {
258  // Returns a random lambertian unit vector
259  G4ThreeVector vect;
260  G4double ndotv;
261  do {
262  vect = G4IsotropicRand();
263  ndotv = normal * vect;
264  if (ndotv < 0) {
265  vect *= -1;
266  ndotv *= -1;
267  }
268  } while (!G4BooleanRand(ndotv));
269  return vect;
270  }
271 
272 
273  G4ThreeVector
274  G4TankOpBoundaryProcess::G4PlaneVectorRand(const G4ThreeVector& normal)
275  const
276  {
277  // This function chooses a random vector within a plane given by the unit normal
278  const G4ThreeVector vec1 = normal.orthogonal();
279  const G4ThreeVector vec2 = vec1.cross(normal);
280  const G4double phi = twopi * G4UniformRand();
281  const G4double cosphi = std::cos(phi);
282  const G4double sinphi = std::sin(phi);
283  return cosphi * vec1 + sinphi * vec2;
284  }
285 
286 
287  G4ThreeVector
288  G4TankOpBoundaryProcess::GetFacetNormal(const G4ThreeVector& momentum, const G4ThreeVector& normal)
289  const
290  {
291  G4ThreeVector facetNormal;
292 
293  if (fModel == unified) {
294 
295  /* This function code alpha to a random value taken from the
296  distribution p(alpha) = g(alpha; 0, sigma_alpha)*sin(alpha),
297  for alpha > 0 and alpha < 90, where g(alpha; 0, sigma_alpha)
298  is a gaussian distribution with mean 0 and standard deviation
299  sigma_alpha. */
300 
301  G4double sigmaAlpha = 0;
302 
303  if (fOpticalSurface)
304  sigmaAlpha = fOpticalSurface->GetSigmaAlpha();
305 
306  const G4double maxF = std::min(1., 4 * sigmaAlpha);
307 
308  do {
309 
310  G4double alpha;
311  do {
312  alpha = G4RandGauss::shoot(0, sigmaAlpha);
313  } while (G4UniformRand() * maxF > std::sin(alpha) || alpha >= halfpi);
314  const G4double phi = G4UniformRand() * twopi;
315 
316  const G4double sinAlpha = std::sin(alpha);
317  const G4double cosAlpha = std::cos(alpha);
318  const G4double sinPhi = std::sin(phi);
319  const G4double cosPhi = std::cos(phi);
320 
321  facetNormal.set(sinAlpha*cosPhi, sinAlpha*sinPhi, cosAlpha);
322  facetNormal.rotateUz(normal);
323 
324  } while (momentum * facetNormal >= 0);
325 
326  } else {
327 
328  G4double polish = 1;
329 
330  if (fOpticalSurface)
331  polish = fOpticalSurface->GetPolish();
332 
333  if (polish >= 1)
334  facetNormal = normal;
335  else {
336  do {
337  G4ThreeVector smear;
338  do {
339  smear.set(
340  2 * G4UniformRand() - 1,
341  2 * G4UniformRand() - 1,
342  2 * G4UniformRand() - 1
343  );
344  } while (smear.mag() > 1);
345  smear = (1 - polish) * smear;
346  facetNormal = normal + smear;
347  } while (momentum * facetNormal >= 0);
348  facetNormal = facetNormal.unit();
349 
350  }
351 
352  }
353 
354  return facetNormal;
355  }
356 
357 
358  void
360  {
361  do {
363  DoAbsorption();
364  break;
365  } else {
366  DoReflection();
369  }
370  } while (fNewMomentum * fGlobalNormal < 0);
371  }
372 
373 
374  void
376  {
377  G4bool inside = false;
378  G4bool swap = false;
379  G4bool done;
380 
381  do {
382 
383  G4bool through = false;
384  done = false;
385 
386  do {
387 
388  if (through) {
389  swap = !swap;
390  through = false;
394  }
395 
396  if (fFinish == ground || fFinish == groundbackpainted) {
398  } else {
400  }
401 
402  G4double cost1 = -(fOldMomentum * fFacetNormal);
403  G4double sint1 = 0;
404  G4double sint2 = 0;
405 
406  if (std::abs(cost1) < 1 - kCarTolerance) {
407  sint1 = std::sqrt(1 - Sqr(cost1));
408  sint2 = sint1 * fRIndex1 / fRIndex2; // Snell's Law
409  }
410 
411  if (sint2 >= 1) {
412 
413  // Simulate total internal reflection
414  if (swap)
415  swap = false;
416 
418 
419  if (fModel == unified && fFinish != polished)
421 
422  if (fStatus == LambertianReflection) {
423  DoReflection();
424  } else if (fStatus == BackScattering) {
427  } else {
428  const G4double pDotN = fOldMomentum * fFacetNormal;
429  fNewMomentum = fOldMomentum - (2 * pDotN) * fFacetNormal;
430  const G4double eDotN = fOldPolarization * fFacetNormal;
431  fNewPolarization = -fOldPolarization + (2 * eDotN) * fFacetNormal;
432  }
433 
434  } else if (sint2 < 1) {
435 
436  // Calculate amplitude for transmission (Q = P x N)
437  const G4double cost2 = (cost1 > 0) ? std::sqrt(1 - Sqr(sint2)) : -std::sqrt(1 - Sqr(sint2));
438 
439  G4ThreeVector a_trans;
440  G4ThreeVector atrans;
441  G4ThreeVector e1pp;
442  G4ThreeVector e1pl;
443  G4double e1_perp;
444  G4double e1_parl;
445 
446  if (sint1 > 0) {
447  a_trans = fOldMomentum.cross(fFacetNormal);
448  atrans = a_trans.unit();
449  e1_perp = fOldPolarization * atrans;
450  e1pp = e1_perp * atrans;
451  e1pl = fOldPolarization - e1pp;
452  e1_parl = e1pl.mag();
453  } else {
454  a_trans = fOldPolarization;
455  // Here we Follow Jackson's conventions and we set the parallel
456  // component = 1 in case of a ray perpendicular to the surface
457  e1_perp = 0;
458  e1_parl = 1;
459  }
460 
461  G4double e2_perp = 0;
462  G4double e2_parl = 0;
463  G4double e2_total = 0;
464  G4double transCoeff = 0;
465 
466  if (cost1 != 0) {
467  const G4double s1 = fRIndex1 * cost1;
468  e2_perp = 2 * s1 * e1_perp / (fRIndex1 * cost1 + fRIndex2 * cost2);
469  e2_parl = 2 * s1 * e1_parl / (fRIndex2 * cost1 + fRIndex1 * cost2);
470  e2_total = e2_perp * e2_perp + e2_parl * e2_parl;
471  const G4double s2 = fRIndex2 * cost2 * e2_total;
472  transCoeff = s2 / s1;
473  }
474 
475  G4ThreeVector refracted;
476  G4ThreeVector deflected;
477  G4double e2_abs;
478  G4double c_parl;
479  G4double c_perp;
480 
481  if (!G4BooleanRand(transCoeff)) {
482 
483  // Simulate reflection
484  if (swap)
485  swap = false;
486 
488 
489  if (fModel == unified && fFinish != polished)
491 
492  if (fStatus == LambertianReflection) {
493 
494  DoReflection();
495 
496  } else if (fStatus == BackScattering) {
497 
500 
501  } else {
502 
503  const G4double pDotN = fOldMomentum * fFacetNormal;
504  fNewMomentum = fOldMomentum - (2 * pDotN) * fFacetNormal;
505 
506  if (sint1 > 0) { // incident ray oblique
507 
508  e2_parl = fRIndex2 * e2_parl / fRIndex1 - e1_parl;
509  e2_perp = e2_perp - e1_perp;
510  e2_total = e2_perp * e2_perp + e2_parl * e2_parl;
511  refracted = fFacetNormal + pDotN * fNewMomentum;
512  e2_abs = std::sqrt(e2_total);
513  c_parl = e2_parl / e2_abs;
514  c_perp = e2_perp / e2_abs;
515  fNewPolarization = c_parl * refracted - c_perp * a_trans;
516 
517  } else if (fRIndex2 > fRIndex1) { // incident ray perpendicular
518 
520 
521  }
522 
523  }
524 
525  } else { // photon gets transmitted
526 
527  // Simulate transmission/refraction
528  inside = !inside;
529  through = true;
531 
532  if (sint1 > 0) { // incident ray oblique
533 
534  const G4double alpha = cost1 - cost2 * fRIndex2 / fRIndex1;
535  deflected = fOldMomentum + alpha * fFacetNormal;
536  fNewMomentum = deflected.unit();
537  const G4double pDotN = -cost2;
538  refracted = fFacetNormal - pDotN * fNewMomentum;
539  e2_abs = std::sqrt(e2_total);
540  c_parl = e2_parl / e2_abs;
541  c_perp = e2_perp / e2_abs;
542  fNewPolarization = c_parl * refracted + c_perp * a_trans;
543 
544  } else { // incident ray perpendicular
545 
548 
549  }
550 
551  }
552 
553  }
554 
557 
558  {
559  const G4double proj = fNewMomentum * fGlobalNormal;
560  done = (fStatus == FresnelRefraction) ? (proj <= 0) : (proj >= 0);
561  }
562 
563  } while (!done);
564 
565  if (inside &&
566  !swap &&
567  (fFinish == polishedbackpainted || fFinish == groundbackpainted)) {
568 
570  DoAbsorption();
571  else {
572  if (fStatus != FresnelRefraction)
574  else {
575  swap = !swap;
578  }
579 
580  if (fFinish == groundbackpainted)
582 
583  DoReflection();
584 
587 
588  done = false; // go again
589  }
590 
591  }
592 
593  } while (!done);
594  }
595 
596 
597  void
599  {
600  const G4double rand = G4UniformRand();
601  if (rand >= 0 && rand < fProb_ss) {
604  } else if (rand >= fProb_ss && rand <= fProb_ss + fProb_sl)
606  else if (rand > fProb_ss + fProb_sl && rand < fProb_ss + fProb_sl + fProb_bs)
608  else
610  }
611 
612 
613  void
615  {
617 
618  if (G4BooleanRand(fEfficiency)) {
619  // EnergyDeposited =/= 0 means: photon has been detected
620  fStatus = Detection;
621  aParticleChange.ProposeLocalEnergyDeposit(fPhotonMomentum);
622  } else
623  aParticleChange.ProposeLocalEnergyDeposit(0);
624 
627 
628  aParticleChange.ProposeTrackStatus(fStopAndKill);
629  }
630 
631 
632  void
634  {
635  if (fStatus == LambertianReflection) {
638  } else if (fFinish == ground) {
641  const G4double pDotN = fOldMomentum * fFacetNormal;
642  fNewMomentum = fOldMomentum - (2 * pDotN) * fFacetNormal;
643  } else {
646  const G4double pDotN = fOldMomentum * fFacetNormal;
647  fNewMomentum = fOldMomentum - (2 * pDotN) * fFacetNormal;
648  }
649  const G4double eDotN = fOldPolarization * fFacetNormal;
650  fNewPolarization = -fOldPolarization + (2 * eDotN) * fFacetNormal;
651  }
652 
653 }
G4ThreeVector G4LambertianRand(const G4ThreeVector &normal) const
G4ThreeVector GetFacetNormal(const G4ThreeVector &momentum, const G4ThreeVector &normal) const
void swap(utl::Trace< T > &t1, utl::Trace< T > &t2)
Definition: Trace.h:363
constexpr T Sqr(const T &x)
void swap(OverCounted &oc1, OverCounted &oc2)
constexpr double s
Definition: AugerUnits.h:163
virtual G4VParticleChange * PostStepDoIt(const G4Track &track, const G4Step &step) override
double abs(const SVector< n, T > &v)
const double unit[npar]
Definition: UnivRec.h:76
G4ThreeVector G4PlaneVectorRand(const G4ThreeVector &normal) const
struct particle_info particle[80]

, generated on Tue Sep 26 2023.