Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/electromagnetic/xrays/src/G4XrayReflection.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 //------------------ G4XrayReflection physics process -----------------------
 27 //
 28 // History:
 29 // 14-09-23 H. Burkhardt, initial implementation
 30 //
 31 // --------------------------------------------------------------------------
 32 
 33 #include "G4XrayReflection.hh"
 34 
 35 #include "G4EmProcessSubType.hh"
 36 #include "G4Exp.hh"
 37 #include "G4Gamma.hh"
 38 #include "G4Step.hh"
 39 #include "G4SystemOfUnits.hh"
 40 #include "G4ThreeVector.hh"
 41 #include "G4Track.hh"
 42 #include "G4TransportationManager.hh"
 43 #include "G4VDiscreteProcess.hh"
 44 
 45 G4double G4XrayReflection::fSurfaceRoughness = 0;
 46 
 47 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 48 
 49 G4XrayReflection::G4XrayReflection(const G4String& processName,
 50                                    G4ProcessType type)  //  Constructor
 51   : G4VDiscreteProcess(processName, type)
 52 {
 53   SetProcessSubType(fGammaReflection);
 54   SaveHenkeDataAsMaterialProperty();
 55 }
 56 
 57 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 58 
 59 G4bool G4XrayReflection::IsApplicable(const G4ParticleDefinition& particle)
 60 {
 61   return (&particle == G4Gamma::Gamma());  // apply only to gamma
 62 }
 63 
 64 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 65 
 66 G4double G4XrayReflection::Reflectivity(const G4double GamEner, const G4double SinIncidentAngle,
 67                                         const G4Material* theMat) const
 68 {
 69   G4double theReflectivity = 0;
 70   const G4MaterialPropertiesTable* theMatProp = theMat->GetMaterialPropertiesTable();
 71   if (SinIncidentAngle < 0.9 && theMatProp != nullptr)
 72   {  // avoid perpendicular refl. at straight entry  and require
 73     // data available
 74     G4MaterialPropertyVector* RealIndex = theMatProp->GetProperty(kREALRINDEX);
 75     G4MaterialPropertyVector* ImagIndex = theMatProp->GetProperty(kIMAGINARYRINDEX);
 76     if (nullptr == RealIndex || nullptr == ImagIndex) { return theReflectivity; }
 77     const G4double delta = RealIndex->Value(GamEner);
 78     const G4double beta = ImagIndex->Value(GamEner);
 79     const G4double sin2 = std::pow(SinIncidentAngle, 2);
 80     const G4double rho2 =
 81       0.5 * (sin2 - 2 * delta + std::sqrt(std::pow(sin2 - 2 * delta, 2) + 4 * beta * beta));
 82     const G4double rho = std::sqrt(rho2);
 83     const G4double Refl_sigma = (rho2 * std::pow(SinIncidentAngle - rho, 2) + std::pow(beta, 2))
 84                                 / (rho2 * std::pow(SinIncidentAngle + rho, 2) + std::pow(beta, 2));
 85     const G4double coscot = std::sqrt(1 - sin2) / SinIncidentAngle;
 86     const G4double pi_over_sigma = (rho2 * std::pow(rho - coscot, 2) + std::pow(beta, 2))
 87                                    / (rho2 * std::pow(rho + coscot, 2) + std::pow(beta, 2));
 88     const G4double Refl_pi = Refl_sigma * pi_over_sigma;
 89     theReflectivity = 0.5 * (Refl_sigma + Refl_pi);  // unpolarized
 90     G4double RoughAtten = 1;
 91     if (fSurfaceRoughness > 0) {
 92       G4double kiz = SinIncidentAngle * GamEner / CLHEP::hbarc;
 93       G4double kjz = SinIncidentAngle * (1 - delta) * GamEner / CLHEP::hbarc;
 94       RoughAtten = G4Exp(-2 * kiz * kjz * fSurfaceRoughness * fSurfaceRoughness);  // Nevot–Croce
 95       theReflectivity *= RoughAtten;
 96     }
 97     if (GetVerboseLevel() > 1)
 98       G4cout << std::left << std::setw(12) << __FILE__ << " " << __FUNCTION__ << " line "
 99              << std::right << std::setw(4) << __LINE__ << " GamEner=" << GamEner
100              << " fSurfaceRoughness=" << G4BestUnit(fSurfaceRoughness, "Length")
101              << " RoughAtten=" << RoughAtten << " SinIncidentAngle=" << SinIncidentAngle
102              << " delta=" << delta << " beta=" << beta << " Refl_sigma=" << Refl_sigma
103              << " Refl_pi=" << Refl_pi << " theReflectivity=" << theReflectivity << G4endl;
104   }
105   return theReflectivity;
106 }
107 
108 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
109 
110 G4double G4XrayReflection::GetMeanFreePath(const G4Track& aTrack, G4double previousStepSize,
111                                            G4ForceCondition* condition)
112 {
113   *condition = NotForced;
114   G4double GamEner = aTrack.GetDynamicParticle()->GetTotalEnergy();
115   if (GamEner < 30. * eV || GamEner > 30. * keV)
116     return DBL_MAX;  // do nothing below and above the limits
117 
118   if (GetVerboseLevel() > 2)
119     G4cout << std::left << std::setw(12) << __FILE__ << " " << __FUNCTION__ << " line "
120            << std::right << std::setw(4) << __LINE__ << " GamEner=" << GamEner / keV
121            << " keV previousStepSize=" << previousStepSize
122            << " TrackLength=" << aTrack.GetTrackLength() << " StepLength=" << aTrack.GetStepLength()
123            << G4endl;
124 
125   G4double MeanFreePath = DBL_MAX;  // by default no reflection
126   G4VPhysicalVolume* Volume = aTrack.GetVolume();
127   if (fLastVolume && Volume != fLastVolume && aTrack.GetTrackLength() > 0) {  // at a boundary
128     const G4Material* theLastMat = fLastVolume->GetLogicalVolume()->GetMaterial();
129     const G4Material* theMat = Volume->GetLogicalVolume()->GetMaterial();
130 
131     G4double last_density = theLastMat->GetDensity();
132     G4double density = theMat->GetDensity();
133     if (density > last_density) {  // density has increased
134       G4Navigator* theNavigator =
135         G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking();
136       G4bool valid = false;
137       G4ThreeVector theSurfaceNormal =
138         theNavigator->GetGlobalExitNormal(aTrack.GetPosition(), &valid);
139       if (valid) fSurfaceNormal = theSurfaceNormal;
140       G4double SinIncidentAngle =
141         aTrack.GetDynamicParticle()->GetMomentumDirection() * fSurfaceNormal;
142       if (G4UniformRand() < Reflectivity(GamEner, SinIncidentAngle, theMat)) {
143         MeanFreePath = 0;
144       }
145       G4ThreeVector Position = aTrack.GetPosition();  // only for info
146       const G4VSolid* LastSolid_Volume = fLastVolume->GetLogicalVolume()->GetSolid();  // for info
147       if (GetVerboseLevel() > 1 && MeanFreePath == 0)
148         G4cout << std::left << std::setw(12) << __FILE__ << " " << __FUNCTION__ << " line "
149                << std::right << std::setw(4) << __LINE__
150                << " trigger reflection SinIncidentAngle=" << SinIncidentAngle
151                << " at z=" << Position.getZ() / meter << " m" << G4endl;
152       else if (GetVerboseLevel() > 2)
153         G4cout << std::left << std::setw(12) << __FILE__ << " " << __FUNCTION__ << " line "
154                << std::right << std::setw(4) << __LINE__ << " volume has changed "
155                << " last logical volume name =" << fLastVolume->GetLogicalVolume()->GetName()
156                << " last logical volume material name =" << theLastMat->GetName()
157                << " last density=" << last_density << " part/cm3 ? "
158                << " logical volume name =" << Volume->GetLogicalVolume()->GetName()
159                << " logical volume material name =" << theMat->GetName() << " density=" << density
160                << " part/cm3 ? "
161                << " LastSolid_Volume->Inside(Position)=" << LastSolid_Volume->Inside(Position)
162                << " sin(IncidentAngle)=" << SinIncidentAngle << " MeanFreePath=" << MeanFreePath
163                << G4endl;
164     }
165   }
166   fLastVolume = Volume;
167   return MeanFreePath;
168 }
169 
170 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
171 
172 G4VParticleChange* G4XrayReflection::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
173 {
174   aParticleChange.Initialize(aTrack);  // copy the current position to the changed particle
175   G4ThreeVector PhotDir = aTrack.GetDynamicParticle()->GetMomentumDirection();
176   G4ThreeVector para_part = (PhotDir * fSurfaceNormal) * fSurfaceNormal;
177   G4ThreeVector photon_reflected = PhotDir - 2 * para_part;  // invert the parallel component
178   if (GetVerboseLevel() > 1)
179     G4cout << std::left << std::setw(12) << __FILE__ << " " << __FUNCTION__ << " line "
180            << std::right << std::setw(4) << __LINE__ << " fSurfaceNormal=" << fSurfaceNormal
181            << " StepLength=" << aStep.GetStepLength() << " PhotDir=" << PhotDir
182            << " photon_reflected=" << photon_reflected << " para_part=" << para_part
183            << " aParticleChange.GetTrackStatus()=" << aParticleChange.GetTrackStatus()
184            << G4endl;
185 
186   aParticleChange.ProposeTrackStatus(
187     fStopAndKill);  // needed when working with primary gamma to get rid of
188   // primary
189   auto ReflectedPhoton = new G4DynamicParticle(G4Gamma::Gamma(), photon_reflected,
190                                                aTrack.GetDynamicParticle()->GetTotalEnergy());
191   aParticleChange.AddSecondary(ReflectedPhoton);
192   return &aParticleChange;
193 }
194 
195 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
196 
197 void G4XrayReflection::BuildPhysicsTable(const G4ParticleDefinition& part)
198 {
199   ProcessDescription(G4cout);
200 
201   if (GetVerboseLevel() > 2)
202     G4cout << std::left << std::setw(12) << __FILE__ << " " << __FUNCTION__ << " line "
203            << std::right << std::setw(4) << __LINE__
204            << " is gamma=" << (&part == G4Gamma::Definition())
205            << " fSurfaceRoughness=" << G4BestUnit(fSurfaceRoughness, "Length") << G4endl;
206 }
207 
208 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
209 
210 void G4XrayReflection::ProcessDescription(std::ostream& out) const
211 {
212   if (G4Threading::IsMasterThread())
213     out << '\n' << GetProcessName() << ": Gamma specular reflection for energies > 30 eV.\n";
214 }
215 
216 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
217 
218 G4int G4XrayReflection::ReadHenkeXrayData(std::string ElName, std::vector<G4double>& Ephot,
219                                           std::vector<G4double>& f1, std::vector<G4double>& f2)
220 {
221   std::transform(ElName.begin(), ElName.end(), ElName.begin(),
222                  ::tolower);  // henke_physical_reference uses lower case filanames
223   const G4String DataDir = G4EmParameters::Instance()->GetDirLEDATA() + "/XRayReflection_data/";
224   const G4String InpFname = DataDir + ElName + ".nff";
225   std::ifstream infile(InpFname);
226   if (!infile.is_open()) {
227     G4cout << "ReadHenkeXrayReflData " << InpFname << " not found" << G4endl;
228     return 1;  // failure
229   }
230   std::vector<std::string> VarName(3);
231   infile >> VarName[0] >> VarName[1] >> VarName[2];
232   if (GetVerboseLevel())
233     G4cout << "ReadHenkeXrayData variable names " << VarName[0] << " " << VarName[1] << " "
234            << VarName[2] << G4endl;
235   G4double E_eV_i, f1_i, f2_i;
236   Ephot.resize(0);
237   f1.resize(0);
238   f2.resize(0);
239   for (;;) {
240     infile >> E_eV_i >> f1_i >> f2_i;
241     if (infile.eof()) break;
242     Ephot.push_back(E_eV_i * eV);
243     f1.push_back(f1_i);
244     f2.push_back(f2_i);
245   }
246   return 0;  // success
247 }
248 
249 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
250 
251 void G4XrayReflection::SaveHenkeDataAsMaterialProperty()
252 {
253   // loop through the material table and load set up MaterialPropertiesTable
254   // with Henke data used to calculate the reflection
255   auto materialTable = G4Material::GetMaterialTable();
256   for (auto a_material : *materialTable) {
257     auto N = a_material->GetTotNbOfAtomsPerVolume();
258     if (GetVerboseLevel() > 2)
259       if (GetVerboseLevel() > 2)
260         G4cout << std::left << std::setw(12) << __FILE__ << " " << __FUNCTION__ << " line "
261                << std::right << std::setw(4) << __LINE__ << " " << a_material->GetName()
262                << " NbOfAtomsPerVolume()=" << N
263                << " NumberOfElements()=" << a_material->GetNumberOfElements() << G4endl;
264     // calculate the reflectivity from input data. Implemented for dense
265     // materials of a single element
266     if (a_material->GetNumberOfElements() == 1 && a_material->GetDensity() > 1) {
267       G4double factor = N * CLHEP::classic_electr_radius / CLHEP::twopi;
268       std::vector<G4double> Ephot, f1, f2;
269       const G4Element* theElement = a_material->GetElement(0);
270       G4int iret = ReadHenkeXrayData(theElement->GetName(), Ephot, f1, f2);
271       if (iret) {
272         if (GetVerboseLevel() > 2)
273           G4cout << std::left << std::setw(12) << __FILE__ << " " << __FUNCTION__ << " line "
274                  << std::right << std::setw(4) << __LINE__ << " no Henke data found for "
275                  << a_material->GetName() << " " << theElement->GetName() << G4endl;
276       }
277       else {
278         std::vector<G4double> RealIndex(Ephot.size()), ImagIndex(Ephot.size());
279         for (std::size_t i = 0; i < Ephot.size(); ++i) {
280           G4double lambda = CLHEP::twopi * CLHEP::hbarc / Ephot[i];
281           G4double lambda_sqr = lambda * lambda;
282           RealIndex[i] = fmax(0, factor * lambda_sqr * f1[i]);  // delta or 1-RealIndex
283           ImagIndex[i] = factor * lambda_sqr * f2[i];  // beta  or  -ImagIndex
284           if (GetVerboseLevel() > 2)
285             G4cout << "Ephot=" << std::setw(10) << Ephot[i] / eV << " eV delta=" << std::setw(10)
286                    << RealIndex[i] << " beta=" << std::setw(10) << ImagIndex[i] << G4endl;
287         }  // photon energy
288         G4MaterialPropertiesTable* proptab = a_material->GetMaterialPropertiesTable();
289         if(proptab == nullptr) {
290           proptab = new G4MaterialPropertiesTable();
291           a_material->SetMaterialPropertiesTable(proptab);
292         }
293         proptab->AddProperty("REALRINDEX", Ephot, RealIndex);  // 1-RealIndex
294         proptab->AddProperty("IMAGINARYRINDEX", Ephot, ImagIndex);
295         if (GetVerboseLevel() > 2)
296           G4cout << std::left << std::setw(12) << __FILE__ << " " << __FUNCTION__ << " line "
297                  << std::right << std::setw(4) << __LINE__ << " " << a_material->GetName()
298                  << " " << theElement->GetName()
299                  << " reflection data saved in PropertiesTable" << G4endl;
300       }  // data found
301     }
302   }
303 }
304 
305 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
306 
307 void G4XrayReflection::SetSurfaceRoughness(const G4double value)
308 {
309   fSurfaceRoughness = value;
310 }
311 
312 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
313