Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/hadronic/processes/src/G4UCNBoundaryProcess.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 //
 27 ///////////////////////////////////////////////////////////////////////
 28 // UCN BoundaryProcess Class Implementation
 29 ///////////////////////////////////////////////////////////////////////
 30 //
 31 // File:        G4UCNBoundaryProcess.cc
 32 // Description: Discrete Process -- Boundary Process of UCN
 33 // Version:     1.0
 34 // Created:     2014-05-12
 35 // Author:      Peter Gumplinger
 36 //              adopted from Geant4UCN by Peter Fierlinger (9.9.04) and
 37 //              Marcin Kuzniak (21.4.06)
 38 //              1/v energy dependent absorption cross section
 39 //              inside materials
 40 // Updated:     2007 Extensions for the microroughness model by Stefan Heule
 41 //
 42 // mail:        gum@triumf.ca
 43 //
 44 ///////////////////////////////////////////////////////////////////////
 45 
 46 #include "G4UCNProcessSubType.hh"
 47 
 48 
 49 #include "G4UCNBoundaryProcess.hh"
 50 #include "G4UCNBoundaryProcessMessenger.hh"
 51 
 52 #include "G4GeometryTolerance.hh"
 53 
 54 #include "G4StepPoint.hh"
 55 #include "G4ParticleDefinition.hh"
 56 
 57 #include "G4UCNMaterialPropertiesTable.hh"
 58 
 59 #include "G4TransportationManager.hh"
 60 #include "G4ParallelWorldProcess.hh"
 61 
 62 #include "G4VSensitiveDetector.hh"
 63 
 64 #include "G4SystemOfUnits.hh"
 65 #include "G4PhysicalConstants.hh"
 66 
 67 G4UCNBoundaryProcess::G4UCNBoundaryProcess(const G4String& processName,
 68                                            G4ProcessType type)
 69   : G4VDiscreteProcess(processName, type)
 70 {
 71 
 72   if (verboseLevel > 0) G4cout << GetProcessName() << " is created " << G4endl;
 73 
 74   SetProcessSubType(fUCNBoundary);
 75 
 76   theStatus = Undefined;
 77 
 78   fMessenger = new G4UCNBoundaryProcessMessenger(this);
 79 
 80   neV = 1.0e-9*eV;
 81 
 82   kCarTolerance = G4GeometryTolerance::GetInstance()
 83                   ->GetSurfaceTolerance();
 84 
 85   Material1 = NULL;
 86   Material2 = NULL;
 87 
 88   aMaterialPropertiesTable1 = NULL;
 89   aMaterialPropertiesTable2 = NULL;
 90 
 91   UseMicroRoughnessReflection = false;
 92   DoMicroRoughnessReflection  = false;
 93 
 94   nNoMPT = nNoMRT = nNoMRCondition = 0;
 95   nAbsorption = nEzero = nFlip = 0;
 96   aSpecularReflection = bSpecularReflection = 0;
 97   bLambertianReflection = 0;
 98   aMRDiffuseReflection = bMRDiffuseReflection = 0;
 99   nSnellTransmit = mSnellTransmit = 0;
100   aMRDiffuseTransmit = 0;
101   ftheta_o = fphi_o = 0;
102 }
103 
104 G4UCNBoundaryProcess::~G4UCNBoundaryProcess()
105 {
106    delete fMessenger;
107 } 
108 
109 G4VParticleChange*
110 G4UCNBoundaryProcess::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
111 {
112   aParticleChange.Initialize(aTrack);
113   aParticleChange.ProposeVelocity(aTrack.GetVelocity());
114 
115   // Get hyperStep from  G4ParallelWorldProcess
116   //  NOTE: PostSetpDoIt of this process should be
117   //        invoked after G4ParallelWorldProcess!
118 
119   const G4Step* pStep = &aStep;
120 
121   const G4Step* hStep = G4ParallelWorldProcess::GetHyperStep();
122 
123   if (hStep) pStep = hStep;
124 
125   G4bool isOnBoundary =
126           (pStep->GetPostStepPoint()->GetStepStatus() == fGeomBoundary);
127 
128   if (isOnBoundary) {
129      Material1 = pStep->GetPreStepPoint()->GetMaterial();
130      Material2 = pStep->GetPostStepPoint()->GetMaterial();
131   } else {
132      theStatus = NotAtBoundary;
133      if ( verboseLevel > 1 ) BoundaryProcessVerbose();
134      return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
135   }
136 
137   if (aTrack.GetStepLength()<=kCarTolerance/2) {
138      theStatus = StepTooSmall;
139      if ( verboseLevel > 0 ) BoundaryProcessVerbose();
140      return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
141   }
142 
143   aMaterialPropertiesTable1 = (G4UCNMaterialPropertiesTable*)Material1->
144                                                  GetMaterialPropertiesTable();
145   aMaterialPropertiesTable2 = (G4UCNMaterialPropertiesTable*)Material2->
146                                                  GetMaterialPropertiesTable();
147 
148   G4String volnam1 = pStep->GetPreStepPoint() ->GetPhysicalVolume()->GetName();
149   G4String volnam2 = pStep->GetPostStepPoint()->GetPhysicalVolume()->GetName();
150 
151   if (verboseLevel > 0) {
152      G4cout << " UCN at Boundary! " << G4endl;
153      G4cout << " vol1: " << volnam1 << ", vol2: " << volnam2 << G4endl;
154      G4cout << " Ekin:     " << aTrack.GetKineticEnergy()/neV <<"neV"<< G4endl;
155      G4cout << " MomDir:   " << aTrack.GetMomentumDirection() << G4endl;
156   }
157 
158   if (Material1 == Material2) {
159      theStatus = SameMaterial;
160      if ( verboseLevel > 0 ) BoundaryProcessVerbose();
161      return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
162   }
163 
164   G4ThreeVector theGlobalPoint = pStep->GetPostStepPoint()->GetPosition();
165 
166   G4bool valid;
167   //  Use the new method for Exit Normal in global coordinates,
168   //    which provides the normal more reliably.
169 
170   // ID of Navigator which limits step
171 
172   G4int hNavId = G4ParallelWorldProcess::GetHypNavigatorID();
173   std::vector<G4Navigator*>::iterator iNav =
174           G4TransportationManager::GetTransportationManager()->
175                                    GetActiveNavigatorsIterator();
176 
177   G4ThreeVector theGlobalNormal =
178              (iNav[hNavId])->GetGlobalExitNormal(theGlobalPoint,&valid);
179 
180   if (valid) {
181      theGlobalNormal = -theGlobalNormal;
182   }
183   else
184   {
185      G4ExceptionDescription ed;
186      ed << " G4UCNBoundaryProcess/PostStepDoIt(): "
187         << " The Navigator reports that it returned an invalid normal"
188         << G4endl;
189      G4Exception("G4UCNBoundaryProcess::PostStepDoIt", "UCNBoun01",
190                  EventMustBeAborted,ed,
191                  "Invalid Surface Normal - Geometry must return valid surface normal");
192   }
193 
194   const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
195 
196   G4ThreeVector OldMomentum = aParticle->GetMomentumDirection();
197 
198   if (OldMomentum * theGlobalNormal > 0.0) {
199 #ifdef G4OPTICAL_DEBUG
200      G4ExceptionDescription ed;
201      ed << " G4UCNBoundaryProcess/PostStepDoIt(): "
202         << " theGlobalNormal points in a wrong direction. "
203         << G4endl;
204      ed << "    The momentum of the photon arriving at interface (oldMomentum)"
205         << " must exit the volume cross in the step. " << G4endl;
206      ed << "  So it MUST have dot < 0 with the normal that Exits the new volume (globalNormal)." << G4endl;
207      ed << "  >> The dot product of oldMomentum and global Normal is " << OldMomentum*theGlobalNormal << G4endl;
208      ed << "     Old Momentum  (during step)     = " << OldMomentum << G4endl;
209      ed << "     Global Normal (Exiting New Vol) = " << theGlobalNormal << G4endl;
210      ed << G4endl;
211      G4Exception("G4UCNBoundaryProcess::PostStepDoIt", "UCNBoun02",
212                  EventMustBeAborted,  // Or JustWarning to see if it happens repeatedbly on one ray
213                  ed,
214                 "Invalid Surface Normal - Geometry must return valid surface normal pointing in the right direction");
215 #else
216      theGlobalNormal = -theGlobalNormal;
217 #endif
218   }
219 
220   G4ThreeVector theNeutronMomentum = aTrack.GetMomentum();
221 
222   G4double theMomentumNormal = theNeutronMomentum*theGlobalNormal;
223   G4double theVelocityNormal = aTrack.GetVelocity() * 
224                                              (OldMomentum * theGlobalNormal);
225 
226   G4double Enormal = theMomentumNormal*theMomentumNormal/2./neutron_mass_c2;
227   G4double Energy  = aTrack.GetKineticEnergy();
228    
229   G4double FermiPot2  = 0.;
230   G4double pDiffuse   = 0.;
231   G4double pSpinFlip  = 0.;
232   G4double pUpScatter = 0.;
233 
234   if (aMaterialPropertiesTable2) {
235      FermiPot2  = aMaterialPropertiesTable2->GetConstProperty("FERMIPOT")*neV;
236      pDiffuse   = aMaterialPropertiesTable2->GetConstProperty("DIFFUSION");
237      pSpinFlip  = aMaterialPropertiesTable2->GetConstProperty("SPINFLIP");
238      pUpScatter = aMaterialPropertiesTable2->GetConstProperty("LOSS");
239   }
240 
241   G4double FermiPot1 = 0.;
242   if (aMaterialPropertiesTable1)
243      FermiPot1 = aMaterialPropertiesTable1->GetConstProperty("FERMIPOT")*neV;
244 
245   G4double FermiPotDiff = FermiPot2 - FermiPot1;
246 
247   if ( verboseLevel > 1 )
248      G4cout << "UCNBoundaryProcess: new FermiPot: " << FermiPot2/neV 
249             << "neV, old FermiPot:" << FermiPot1/neV << "neV" << G4endl;
250   
251   // Use microroughness diffuse reflection behavior if activated
252 
253   DoMicroRoughnessReflection = UseMicroRoughnessReflection;
254 
255   G4double theta_i = 0.;
256 
257   if (!aMaterialPropertiesTable2) {
258 
259      nNoMPT++;
260      theStatus = NoMPT;
261      if ( verboseLevel > 0 ) BoundaryProcessVerbose();
262      DoMicroRoughnessReflection = false;
263 
264   } else {
265 
266       if (!aMaterialPropertiesTable2->GetMicroRoughnessTable()) {
267 
268          nNoMRT++;
269          theStatus = NoMRT;
270          if ( verboseLevel > 0 ) BoundaryProcessVerbose();
271 
272          DoMicroRoughnessReflection = false;
273       }
274 
275       // Angle theta_in between surface and momentum direction,
276       // Phi_in is defined to be 0
277 
278       theta_i = OldMomentum.angle(-theGlobalNormal);
279 
280       // Checks the MR-conditions
281 
282       if (!aMaterialPropertiesTable2-> 
283                     ConditionsValid(Energy, FermiPotDiff, theta_i)) {
284 
285          nNoMRCondition++;
286          theStatus = NoMRCondition;
287          if ( verboseLevel > 0 ) BoundaryProcessVerbose();
288 
289           DoMicroRoughnessReflection = false;
290       }
291   }
292 
293   G4double MRpDiffuse = 0.;
294   G4double MRpDiffuseTrans = 0.;
295 
296   // If microroughness is available and active for material in question
297 
298   if (DoMicroRoughnessReflection) {
299 
300       // Integral probability for non-specular reflection with microroughness
301 
302       MRpDiffuse = aMaterialPropertiesTable2->
303                                           GetMRIntProbability(theta_i, Energy);
304 
305       // Integral probability for non-specular transmission with microroughness
306 
307       MRpDiffuseTrans = aMaterialPropertiesTable2->
308                                      GetMRIntTransProbability(theta_i, Energy);
309 
310       if ( verboseLevel > 1 ) {
311          G4cout << "theta: " << theta_i/degree << "degree" << G4endl;
312          G4cout << "Energy: " << Energy/neV << "neV"
313                 << ", Enormal: " << Enormal/neV << "neV" << G4endl;
314          G4cout << "FermiPotDiff: " << FermiPotDiff/neV << "neV " << G4endl;
315          G4cout << "Reflection_prob: " << MRpDiffuse 
316                 << ", Transmission_prob: " << MRpDiffuseTrans << G4endl;
317       }
318   }
319 
320   if (!High(Enormal, FermiPotDiff)) {
321 
322      // Below critical velocity
323 
324      if (verboseLevel > 0) G4cout << "G4UCNBoundaryProcess -> BELOW critical velocity" << G4endl;
325 
326      // Loss on reflection
327 
328      if (Loss(pUpScatter, theVelocityNormal, FermiPotDiff)) {
329 
330         // kill it.
331         aParticleChange.ProposeTrackStatus(fStopAndKill);
332         aParticleChange.ProposeLocalEnergyDeposit(Energy);
333 
334         nAbsorption++;
335         theStatus = Absorption;
336         if ( verboseLevel > 0 ) BoundaryProcessVerbose();
337 
338         return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
339      }
340 
341      // spinflips
342 
343      if (SpinFlip(pSpinFlip)) {
344         nFlip++;
345         theStatus = Flip;
346         if ( verboseLevel > 0 ) BoundaryProcessVerbose();
347 
348         G4ThreeVector NewPolarization = -1. * aParticle->GetPolarization();
349         aParticleChange.ProposePolarization(NewPolarization);
350      }
351 
352      // Reflect from surface
353 
354      G4ThreeVector NewMomentum;
355 
356      // If microroughness is available and active - do non-specular reflection
357 
358      if (DoMicroRoughnessReflection)
359         NewMomentum = MRreflect(MRpDiffuse, OldMomentum, theGlobalNormal,
360                                 Energy, FermiPotDiff);
361      else
362 
363         // Else do it with the Lambert model as implemented by Peter Fierlinger
364 
365         NewMomentum = Reflect(pDiffuse, OldMomentum, theGlobalNormal);
366 
367      aParticleChange.ProposeMomentumDirection(NewMomentum);
368     
369   } else {
370 
371      // Above critical velocity
372 
373      if (verboseLevel > 0) G4cout << "G4UCNBoundaryProcess -> ABOVE critical velocity" << G4endl;
374 
375      // If it is faster than the criticial velocity,
376      // there is a probability to be still reflected.
377      // This formula is (only) valid for low loss materials
378 
379      // If microroughness available and active, do reflection with it
380 
381      G4ThreeVector NewMomentum;
382 
383      if (DoMicroRoughnessReflection) {
384 
385         G4double Enew;
386 
387         NewMomentum = 
388                MRreflectHigh(MRpDiffuse, MRpDiffuseTrans, 0., OldMomentum,
389                              theGlobalNormal, Energy, FermiPotDiff, Enew);
390 
391         if (Enew == 0.) {
392           aParticleChange.ProposeTrackStatus(fStopAndKill);
393           aParticleChange.ProposeLocalEnergyDeposit(Energy);
394           return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
395         } else {
396           aParticleChange.ProposeEnergy(Enew);
397           aParticleChange.ProposeMomentumDirection(NewMomentum);
398           aParticleChange.ProposeVelocity(std::sqrt(2*Enew/neutron_mass_c2)*c_light);
399           aParticleChange.ProposeLocalEnergyDeposit(Energy-Enew);
400         }
401 
402      } else {
403 
404         G4double reflectivity = Reflectivity(FermiPotDiff, Enormal);
405 
406         if ( verboseLevel > 1 ) G4cout << "UCNBoundaryProcess: reflectivity "
407                                        << reflectivity << G4endl;
408 
409         if (G4UniformRand() < reflectivity) { 
410 
411           // Reflect from surface
412 
413           NewMomentum = Reflect(pDiffuse, OldMomentum, theGlobalNormal);
414           aParticleChange.ProposeMomentumDirection(NewMomentum);
415 
416         } else {
417 
418           // --- Transmission because it is faster than the critical velocity 
419 
420           G4double Enew = Transmit(FermiPotDiff, Energy);
421 
422           // --- Change of the normal momentum component
423           //     p = sqrt(2*m*Ekin)
424 
425           G4double mass = -std::sqrt(theMomentumNormal*theMomentumNormal - 
426                                 neutron_mass_c2*2.*FermiPotDiff);
427 
428           // --- Momentum direction in new media
429 
430           NewMomentum = 
431                theNeutronMomentum - (theMomentumNormal-mass)*theGlobalNormal;
432 
433           nSnellTransmit++;
434           theStatus = SnellTransmit;
435           if ( verboseLevel > 0 ) BoundaryProcessVerbose();
436 
437           aParticleChange.ProposeEnergy(Enew);
438           aParticleChange.ProposeMomentumDirection(NewMomentum.unit());
439           aParticleChange.ProposeVelocity(std::sqrt(2*Enew/neutron_mass_c2)*c_light);
440           aParticleChange.ProposeLocalEnergyDeposit(Energy-Enew);
441 
442           if (verboseLevel > 1) { 
443              G4cout << "Energy: " << Energy/neV << "neV, Enormal: " 
444                     << Enormal/neV << "neV, fpdiff " << FermiPotDiff/neV 
445                     << "neV, Enew " << Enew/neV << "neV" << G4endl;
446        G4cout << "UCNBoundaryProcess: Transmit and set the new Energy "
447                     << aParticleChange.GetEnergy()/neV << "neV" << G4endl;
448           }
449         }
450      }
451   }
452 
453   return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
454 }
455 
456 G4double G4UCNBoundaryProcess::GetMeanFreePath(const G4Track&, 
457                                                G4double ,
458                                                G4ForceCondition* condition)
459 {
460   *condition = Forced;
461 
462   return DBL_MAX;
463 }
464 
465 G4bool G4UCNBoundaryProcess::Loss(G4double pUpScatter,
466                                   G4double theVelocityNormal,
467                                   G4double FermiPot)
468 {
469   // The surface roughness is not taken into account here.
470   // One could use e.g. ultracold neutrons, R. Golub, p.35,
471   // where mu is increased by roughness parameters sigma and
472   // omega, which are related to the height and the distance of
473   // "disturbances" on the surface
474 
475   G4double vBound = std::sqrt(2.*FermiPot/neutron_mass_c2*c_squared);
476   G4double vRatio = theVelocityNormal/vBound;
477 
478   G4double pLoss = (2*pUpScatter*vRatio)/(std::sqrt(1-(vRatio*vRatio)));
479 
480   // Check, if enhancement for surface roughness should be done
481 
482   if (DoMicroRoughnessReflection) {
483      if (aMaterialPropertiesTable2) {
484         const G4double hdm = hbar_Planck*c_squared/neutron_mass_c2;
485         G4double b = aMaterialPropertiesTable2->GetRMS();
486         G4double w = aMaterialPropertiesTable2->GetCorrLen();
487 
488         // cf. Golub's book p. 35, eq. 2.103
489 
490         pLoss *= std::sqrt(1+2*b*b*vBound*vBound/
491                     (hdm*hdm+0.85*hdm*vBound*w+2*vBound*vBound*w*w));
492      }
493   }
494 
495   return (G4UniformRand() <= std::fabs(pLoss));
496 }
497 
498 G4bool G4UCNBoundaryProcess::SpinFlip(G4double pSpinFlip)
499 {
500   return (G4UniformRand() <= pSpinFlip);
501 }
502 
503 G4double G4UCNBoundaryProcess::Reflectivity(G4double FermiPot, G4double Enormal)
504 {
505   G4double r = (std::sqrt(Enormal) - std::sqrt(Enormal - FermiPot)) /
506                (std::sqrt(Enormal) + std::sqrt(Enormal - FermiPot));
507 
508   return r*r;
509 } 
510 
511 G4ThreeVector G4UCNBoundaryProcess::Reflect(G4double pDiffuse, 
512                                             G4ThreeVector OldMomentum,
513                                             G4ThreeVector Normal)
514 {
515   G4double PdotN = OldMomentum * Normal;
516 
517   G4ThreeVector NewMomentum = OldMomentum - (2.*PdotN)*Normal;
518   NewMomentum.unit();
519 
520   // Reflect diffuse
521 
522   if (NewMomentum == OldMomentum || G4UniformRand() < pDiffuse) {
523 
524      NewMomentum = LDiffRefl(Normal);
525 
526      bLambertianReflection++;
527      theStatus = LambertianReflection;
528      if ( verboseLevel > 0 ) BoundaryProcessVerbose();
529 
530      return NewMomentum;
531   }
532 
533   // Reflect specular
534 
535   bSpecularReflection++;
536   theStatus = SpecularReflection;
537   if ( verboseLevel > 0 ) BoundaryProcessVerbose();
538 
539   return NewMomentum;
540 }
541 
542 G4ThreeVector G4UCNBoundaryProcess::MRreflect(G4double pDiffuse,
543                                               G4ThreeVector OldMomentum,
544                                               G4ThreeVector Normal,
545                                               G4double Energy,
546                                               G4double FermiPot)
547 {
548   // Only for Enormal <= VFermi
549 
550   G4ThreeVector NewMomentum;
551 
552   // Checks if the reflection should be non-specular
553 
554   if (G4UniformRand() <= pDiffuse) {
555 
556       // Reflect diffuse
557 
558       // Determines the angles of the non-specular reflection
559 
560       NewMomentum =
561              MRDiffRefl(Normal, Energy, FermiPot, OldMomentum, pDiffuse);
562 
563       bMRDiffuseReflection++;
564       theStatus = MRDiffuseReflection;
565       if ( verboseLevel > 0 ) BoundaryProcessVerbose();
566 
567       return NewMomentum;
568 
569   } else {
570 
571       // Reflect specular
572 
573       G4double PdotN = OldMomentum * Normal;
574 
575       NewMomentum = OldMomentum - (2.*PdotN)*Normal;
576       NewMomentum.unit();
577 
578       bSpecularReflection++;
579       theStatus = SpecularReflection;
580       if ( verboseLevel > 0 ) BoundaryProcessVerbose();
581 
582       return NewMomentum;
583   }
584 }
585 
586 G4ThreeVector G4UCNBoundaryProcess::MRreflectHigh(G4double pDiffuse,
587                                                   G4double pDiffuseTrans,
588                                                   G4double pLoss,
589                                                   G4ThreeVector OldMomentum,
590                                                   G4ThreeVector Normal,
591                                                   G4double Energy,
592                                                   G4double FermiPot,
593                                                   G4double &Enew)
594 {
595   // Only for Enormal > VFermi
596 
597   G4double costheta = OldMomentum*Normal;
598 
599   G4double Enormal = Energy * (costheta*costheta);
600 
601 //  G4double pSpecular = Reflectivity(Enormal,FermiPot)*
602   G4double pSpecular = Reflectivity(FermiPot,Enormal)*
603                                          (1.-pDiffuse-pDiffuseTrans-pLoss);
604 
605   G4ThreeVector NewMomentum;
606 
607   G4double decide = G4UniformRand();
608 
609   if (decide < pSpecular) {
610 
611      // Reflect specularly
612 
613      G4double PdotN = OldMomentum * Normal;
614      NewMomentum = OldMomentum - (2.*PdotN)*Normal;
615      NewMomentum.unit();
616 
617      Enew = Energy;
618 
619      aSpecularReflection++;
620      theStatus = SpecularReflection;
621      if ( verboseLevel ) BoundaryProcessVerbose();
622 
623      return NewMomentum;
624   }
625 
626   if (decide < pSpecular + pDiffuse) {
627 
628      // Reflect diffusely
629 
630       // Determines the angles of the non-specular reflection
631 
632       NewMomentum =
633           MRDiffRefl(Normal, Energy, FermiPot, OldMomentum, pDiffuse);
634 
635       if (verboseLevel > 0) G4cout << "Diffuse normal " << Normal
636                                    << ", " << NewMomentum << G4endl;
637       Enew = Energy;
638 
639       aMRDiffuseReflection++;
640       theStatus = MRDiffuseReflection;
641       if ( verboseLevel ) BoundaryProcessVerbose();
642 
643       return NewMomentum;
644   }
645 
646   if (decide < pSpecular + pDiffuse + pDiffuseTrans) {
647 
648      // Transmit diffusely
649 
650      // Determines the angles of the non-specular transmission
651 
652      NewMomentum =
653       MRDiffTrans(Normal, Energy, FermiPot, OldMomentum, pDiffuseTrans);
654 
655      Enew = Energy - FermiPot;
656 
657      aMRDiffuseTransmit++;
658      theStatus = MRDiffuseTransmit;
659      if ( verboseLevel ) BoundaryProcessVerbose();
660 
661      return NewMomentum;
662   }
663 
664   if (decide < pSpecular + pDiffuse + pDiffuseTrans + pLoss) {
665 
666      // Loss
667 
668      Enew = 0.;
669 
670      nEzero++;
671      theStatus = Ezero;
672      if ( verboseLevel > 0 ) BoundaryProcessVerbose();
673 
674      return NewMomentum;
675   }
676 
677   // last case: Refractive transmission
678 
679   Enew = Energy - FermiPot;
680 
681   G4double palt = std::sqrt(2*neutron_mass_c2/c_squared*Energy);
682   G4double produ = OldMomentum * Normal;
683 
684   NewMomentum = palt*OldMomentum-
685                 (palt*produ+std::sqrt(palt*palt*produ*produ-2*neutron_mass_c2/
686                       c_squared*FermiPot))*Normal;
687 
688   mSnellTransmit++;
689   theStatus = SnellTransmit;
690   if ( verboseLevel > 0 ) BoundaryProcessVerbose();
691 
692   return NewMomentum.unit();
693 }
694 
695 G4ThreeVector G4UCNBoundaryProcess::MRDiffRefl(G4ThreeVector Normal,
696                                                G4double Energy,
697                                                G4double FermiPot,
698                                                G4ThreeVector OldMomentum,
699                                                G4double pDiffuse)
700 {
701   G4bool accepted = false;
702 
703   G4double theta_o, phi_o;
704 
705   // Polar angle of incidence
706 
707   G4double theta_i = OldMomentum.polarAngle(-Normal);
708 
709   // Azimuthal angle of incidence
710 
711   //  G4double phi_i = -OldMomentum.azimAngle(-Normal);
712 
713   // accept-reject method for MR-reflection
714 
715   G4int count = 0;
716   while (!accepted) {
717         theta_o = G4UniformRand()*pi/2;
718         phi_o = G4UniformRand()*pi*2-pi;
719         // Box over distribution is increased by 50% to ensure no value is above
720         if (1.5*G4UniformRand()*
721            aMaterialPropertiesTable2->
722              GetMRMaxProbability(theta_i, Energy)/pDiffuse <=
723            aMaterialPropertiesTable2->
724              GetMRProbability(theta_i,Energy,FermiPot,theta_o,phi_o)/pDiffuse)
725 
726            accepted = true;
727 
728          // For the case that the box is nevertheless exceeded
729 
730         if (aMaterialPropertiesTable2->
731              GetMRProbability(theta_i, Energy, FermiPot, theta_o, phi_o)/
732              (1.5*aMaterialPropertiesTable2->
733                               GetMRMaxProbability(theta_i, Energy)) > 1) {
734             G4cout << "MRMax Wahrscheinlichkeitsueberschreitung!" << G4endl;
735             G4cout << aMaterialPropertiesTable2->
736                    GetMRProbability(theta_i, Energy, FermiPot, theta_o, phi_o)/
737                    (1.5*aMaterialPropertiesTable2->
738                                GetMRMaxProbability(theta_i, Energy)) << G4endl;
739             aMaterialPropertiesTable2->
740                SetMRMaxProbability(theta_i, Energy,
741                                    aMaterialPropertiesTable2->
742                                     GetMRProbability(theta_i, Energy, 
743                                                      FermiPot, theta_o, phi_o));
744         }
745   // Loop checking, 31-Aug-2015, Vladimir Ivanchenko
746   if(++count > 10000) { accepted = true; }
747   }
748 
749   // Creates vector in the local coordinate system of the reflection
750 
751   G4ThreeVector localmomentum;
752   localmomentum.setRThetaPhi(1., theta_o, phi_o);
753 
754   ftheta_o = theta_o;
755   fphi_o = phi_o;
756 
757   // Get coordinate transform matrix
758 
759   G4RotationMatrix TransCoord = 
760       GetCoordinateTransformMatrix(Normal, OldMomentum);
761 
762   //transfer to the coordinates of the global system
763 
764   G4ThreeVector momentum = TransCoord*localmomentum;
765 
766   //momentum.rotateUz(Normal);
767 
768   if (momentum * Normal<0) {
769      momentum*=-1;
770      // something has gone wrong...
771      G4cout << "G4UCNBoundaryProcess::MRDiffRefl: !" << G4endl;
772   }
773 
774   return momentum.unit();
775 }
776 
777 G4ThreeVector G4UCNBoundaryProcess::MRDiffTrans(G4ThreeVector Normal,
778                                                 G4double Energy,
779                                                 G4double FermiPot,
780                                                 G4ThreeVector OldMomentum,
781                                                 G4double pDiffuseTrans)
782 {
783   G4bool accepted = false;
784 
785   G4double theta_o, phi_o;
786 
787   // Polar angle of incidence
788 
789   G4double theta_i = OldMomentum.polarAngle(-Normal);
790 
791   // azimuthal angle of incidence
792 
793   //  G4double phi_i = -OldMomentum.azimAngle(-Normal);
794 
795   G4int count = 0;
796   while (!accepted) {
797     theta_o = G4UniformRand()*pi/2;
798     phi_o = G4UniformRand()*pi*2-pi;
799 
800     // Box over distribution is increased by 50% to ensure no value is above
801 
802     if (1.5*G4UniformRand()*
803         aMaterialPropertiesTable2->
804           GetMRMaxTransProbability(theta_i, Energy)/pDiffuseTrans <=
805         aMaterialPropertiesTable2->
806           GetMRTransProbability(theta_i,Energy,FermiPot,theta_o,phi_o)/
807                                                           pDiffuseTrans)
808 
809         accepted=true;
810 
811     // For the case that the box is nevertheless exceeded
812 
813     if(aMaterialPropertiesTable2->
814         GetMRTransProbability(theta_i, Energy, FermiPot, theta_o, phi_o)/
815         (1.5*aMaterialPropertiesTable2->
816                          GetMRMaxTransProbability(theta_i, Energy)) > 1) {
817         G4cout << "MRMaxTrans Wahrscheinlichkeitsueberschreitung!" << G4endl;
818         G4cout << aMaterialPropertiesTable2->
819                GetMRTransProbability(theta_i, Energy, FermiPot, theta_o, phi_o)/
820                (1.5*aMaterialPropertiesTable2->
821                            GetMRMaxTransProbability(theta_i, Energy)) << G4endl;
822         aMaterialPropertiesTable2->
823            SetMRMaxTransProbability(theta_i, Energy,
824                                aMaterialPropertiesTable2->
825                                 GetMRTransProbability(theta_i, Energy,
826                                                  FermiPot, theta_o, phi_o));
827     }
828     // Loop checking, 31-Aug-2015, Vladimir Ivanchenko
829     if(++count > 10000) { accepted = true; }
830   }
831 
832   // Creates vector in the local coordinate system of the reflection
833 
834   G4ThreeVector localmomentum;
835   localmomentum.setRThetaPhi(1., pi-theta_o, phi_o);
836 
837   // Get coordinate transform matrix
838 
839   G4RotationMatrix TransCoord = 
840     GetCoordinateTransformMatrix(Normal, OldMomentum);
841 
842   // Transfer to the coordinates of the global system
843 
844   G4ThreeVector momentum = TransCoord*localmomentum;
845 
846   if (momentum*Normal<0) {
847      // something has gone wrong... 
848      momentum*=-1;
849      G4cout << "G4UCNBoundaryProcess::MRDiffTrans: !" << G4endl;
850   }
851 
852   return momentum.unit();
853 }
854 
855 G4double G4UCNBoundaryProcess::Transmit(G4double FermiPot, G4double Energy)
856 {
857   return (Energy - FermiPot);
858 }
859 
860 G4ThreeVector G4UCNBoundaryProcess::LDiffRefl(G4ThreeVector Normal)
861 {
862   G4ThreeVector momentum;
863 
864   // cosine distribution - Lambert's law
865 
866   momentum.setRThetaPhi(1., std::acos(std::sqrt(G4UniformRand())), 2.*pi*G4UniformRand());
867   momentum.rotateUz(Normal);
868 
869   if (momentum*Normal < 0) {
870      momentum*=-1;
871      G4cout << "G4UCNBoundaryProcess::LDiffRefl: !" << G4endl;
872   }
873 
874   return momentum.unit();
875 }
876 
877 G4RotationMatrix G4UCNBoundaryProcess::
878                 GetCoordinateTransformMatrix(G4ThreeVector Normal,
879                                              G4ThreeVector direction)
880 {
881    // Definition of the local coordinate system (c.s. of the reflection)
882 
883   G4ThreeVector  es1, es2, es3;
884 
885   // z-Coordinate is the surface normal, has already length 1
886 
887   es3 = Normal;
888 
889   // Perpendicular part of incident direction w.r.t. normal
890   es1 = direction.perpPart(Normal);
891 
892   // Set to unit length: x-Coordinate
893 
894   es1.setMag(1.);
895   es2 = es1;
896 
897   // y-Coordinate is the pi/2-rotation of x-axis around z-axis
898 
899   es2.rotate(90.*degree, es3);
900 
901   // Transformation matrix consists just of the three coordinate vectors
902   // as the global coordinate system is the 'standard' coordinate system
903 
904   G4RotationMatrix matrix(es1, es2, es3);
905 
906   return matrix;
907 }
908 
909 void G4UCNBoundaryProcess::BoundaryProcessVerbose() const
910 {
911   if ( theStatus == Undefined )
912      G4cout << " *** Undefined *** " << G4endl;
913   if ( theStatus == NotAtBoundary )
914      G4cout << " *** NotAtBoundary *** " << G4endl;
915   if ( theStatus == SameMaterial )
916      G4cout << " *** SameMaterial *** " << G4endl;
917   if ( theStatus == StepTooSmall )
918      G4cout << " *** StepTooSmall *** " << G4endl;
919   if ( theStatus == NoMPT )
920      G4cout << " *** No G4UCNMaterialPropertiesTable *** " << G4endl;
921   if ( theStatus == NoMRT )
922      G4cout << " *** No MicroRoughness Table *** " << G4endl;
923   if ( theStatus == NoMRCondition )
924      G4cout << " *** MicroRoughness Condition not satisfied *** " << G4endl;
925   if ( theStatus == Absorption )
926      G4cout << " *** Loss on Surface *** " << G4endl;
927   if ( theStatus == Ezero )
928      G4cout << " *** Ezero on Surface *** " << G4endl;
929   if ( theStatus == Flip )
930      G4cout << " *** Spin Flip on Surface *** " << G4endl;
931   if ( theStatus == SpecularReflection )
932      G4cout << " *** Specular Reflection *** " << G4endl;
933   if ( theStatus == LambertianReflection )
934      G4cout << " *** LambertianR Reflection *** " << G4endl;
935   if ( theStatus == MRDiffuseReflection )
936      G4cout << " *** MR Model Diffuse Reflection *** " << G4endl;
937   if ( theStatus == SnellTransmit )
938      G4cout << " *** Snell Transmission *** " << G4endl;
939   if ( theStatus == MRDiffuseTransmit )
940      G4cout << " *** MR Model Diffuse Transmission *** " << G4endl;
941 }
942 
943 void G4UCNBoundaryProcess::BoundaryProcessSummary(void) const
944 {
945   G4cout << "Sum NoMT:                            "
946          << nNoMPT << G4endl;
947   G4cout << "Sum NoMRT:                           "
948          << nNoMRT << G4endl;
949   G4cout << "Sum NoMRCondition:                   "
950          << nNoMRCondition << G4endl;
951   G4cout << "Sum No. E < V Loss:                  "
952          << nAbsorption << G4endl;
953   G4cout << "Sum No. E > V Ezero:                 "
954          << nEzero << G4endl;
955   G4cout << "Sum No. E < V SpinFlip:              "
956          << nFlip << G4endl;
957   G4cout << "Sum No. E > V Specular Reflection:   "
958          << aSpecularReflection << G4endl;
959   G4cout << "Sum No. E < V Specular Reflection:   "
960          << bSpecularReflection << G4endl;
961   G4cout << "Sum No. E < V Lambertian Reflection: "
962          << bLambertianReflection << G4endl;
963   G4cout << "Sum No. E > V MR DiffuseReflection:  "
964          << aMRDiffuseReflection << G4endl;
965   G4cout << "Sum No. E < V MR DiffuseReflection:  "
966          << bMRDiffuseReflection << G4endl;
967   G4cout << "Sum No. E > V SnellTransmit:         "
968          << nSnellTransmit << G4endl;
969   G4cout << "Sum No. E > V MR SnellTransmit:      "
970          << mSnellTransmit << G4endl;
971   G4cout << "Sum No. E > V DiffuseTransmit:       "
972          << aMRDiffuseTransmit << G4endl;
973   G4cout << "                                     " << G4endl;
974 }
975 
976 G4bool G4UCNBoundaryProcess::InvokeSD(const G4Step* pStep)
977 {
978   G4Step aStep = *pStep;
979 
980   aStep.AddTotalEnergyDeposit(pStep->GetTrack()->GetKineticEnergy());
981 
982   G4VSensitiveDetector* sd = aStep.GetPostStepPoint()->GetSensitiveDetector();
983   if (sd) return sd->Hit(&aStep);
984   else return false;
985 }
986