ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4SeltzerBergerModel.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4SeltzerBergerModel.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 //
26 // -------------------------------------------------------------------
27 //
28 // GEANT4 Class file
29 //
30 //
31 // File name: G4SeltzerBergerModel
32 //
33 // Author: Vladimir Ivanchenko use inheritance from Andreas Schaelicke
34 // base class implementing ultra relativistic bremsstrahlung
35 // model
36 //
37 // Creation date: 04.10.2011
38 //
39 // Modifications:
40 //
41 // 24.07.2018 Introduced possibility to use sampling tables to sample the
42 // emitted photon energy (instead of using rejectio) from the
43 // Seltzer-Berger scalled DCS for bremsstrahlung photon emission.
44 // Using these sampling tables option gives faster(30-70%) final
45 // state generation than the original rejection but takes some
46 // extra memory (+ ~6MB in the case of the full CMS detector).
47 // (M Novak)
48 //
49 // -------------------------------------------------------------------
50 //
51 
52 #include "G4SeltzerBergerModel.hh"
53 #include "G4PhysicalConstants.hh"
54 #include "G4SystemOfUnits.hh"
55 #include "Randomize.hh"
56 #include "G4Material.hh"
57 #include "G4Element.hh"
58 #include "G4ElementVector.hh"
60 #include "G4SBBremTable.hh"
61 #include "G4ModifiedTsai.hh"
62 //#include "G4DipBustGenerator.hh"
63 #include "G4EmParameters.hh"
64 #include "G4ProductionCutsTable.hh"
65 
66 #include "G4Physics2DVector.hh"
67 #include "G4Exp.hh"
68 #include "G4Log.hh"
69 
70 #include "G4ios.hh"
71 
72 #include <fstream>
73 #include <iomanip>
74 #include <sstream>
75 
80 
81 #ifdef G4MULTITHREADED
82  G4Mutex G4SeltzerBergerModel::theSBMutex = G4MUTEX_INITIALIZER;
83 #endif
84 
87 
89  const G4String& nam)
90 : G4eBremsstrahlungRelModel(p,nam), fIsUseBicubicInterpolation(false),
91  fIsUseSamplingTables(true), fNumWarnings(0), fIndx(0), fIndy(0)
92 {
93  fLowestKinEnergy = 1.0*keV;
95  SetLPMFlag(false);
97 }
98 
100 {
101  // delete SB-DCS data per Z
102  if (IsMaster()) {
103  for (size_t iz = 0; iz < gMaxZet; ++iz) {
104  if (gSBDCSData[iz]) {
105  delete gSBDCSData[iz];
106  gSBDCSData[iz] = nullptr;
107  }
108  }
109  if (gSBSamplingTable) {
110  delete gSBSamplingTable;
111  gSBSamplingTable = nullptr;
112  }
113  }
114 }
115 
117  const G4DataVector& cuts)
118 {
119  if (p) {
120  SetParticle(p);
121  }
123  // Access to elements
124  if (IsMaster()) {
125 
126  auto theCoupleTable = G4ProductionCutsTable::GetProductionCutsTable();
127  size_t numOfCouples = theCoupleTable->GetTableSize();
128  for(size_t j=0; j<numOfCouples; ++j) {
129  auto mat = theCoupleTable->GetMaterialCutsCouple(j)->GetMaterial();
130  auto elmVec = mat->GetElementVector();
131  size_t numOfElem = mat->GetNumberOfElements();
132  for (size_t ie = 0; ie < numOfElem; ++ie) {
133  G4int Z = std::max(1,std::min(((*elmVec)[ie])->GetZasInt(), gMaxZet-1));
134  // load SB-DCS data for this atomic number if it has not been loaded yet
135  InitialiseForElement(nullptr, Z);
136  }
137  }
138  // elem.selectr. only for master: base class init-local will set for workers
139  if (LowEnergyLimit() < HighEnergyLimit()) {
141  }
142  // init sampling tables if it was requested
143  if (fIsUseSamplingTables) {
144  if (!gSBSamplingTable) {
146  }
148  HighEnergyLimit());
149  }
150  }
151  //
153  if (GetTripletModel()) {
154  GetTripletModel()->Initialise(p, cuts);
155  fIsScatOffElectron = true;
156  }
157 }
158 
160 {
161  // check environment variable
162  // build the complete string identifying the file with the data set
163  if(gDataDirectory.empty()) {
164  const char* path = std::getenv("G4LEDATA");
165  if (path) {
166  std::ostringstream ost;
167  ost << path << "/brem_SB/br";
168  gDataDirectory = ost.str();
169  } else {
170  G4Exception("G4SeltzerBergerModel::FindDirectoryPath()","em0006",
172  "Environment variable G4LEDATA not defined");
173  }
174  }
175  return gDataDirectory;
176 }
177 
179  // return if it has been already loaded
180  if (gSBDCSData[Z]) {
181  return;
182  }
183  std::ostringstream ost;
184  ost << FindDirectoryPath() << Z;
185  std::ifstream fin(ost.str().c_str());
186  if (!fin.is_open()) {
188  ed << "Bremsstrahlung data file <" << ost.str().c_str()
189  << "> is not opened!";
190  G4Exception("G4SeltzerBergerModel::ReadData()","em0003",FatalException,
191  ed,"G4LEDATA version should be G4EMLOW6.23 or later.");
192  return;
193  }
194  //G4cout << "G4SeltzerBergerModel read from <" << ost.str().c_str()
195  // << ">" << G4endl;
197  if (v->Retrieve(fin)) {
199  static const G4double emaxlog = 4*G4Log(10.);
200  gYLimitData[Z] = v->Value(0.97, emaxlog, fIndx, fIndy);
201  gSBDCSData[Z] = v;
202  } else {
204  ed << "Bremsstrahlung data file <" << ost.str().c_str()
205  << "> is not retrieved!";
206  G4Exception("G4SeltzerBergerModel::ReadData()","em0005",FatalException,
207  ed,"G4LEDATA version should be G4EMLOW6.23 or later.");
208  delete v;
209  }
210 }
211 
213 {
214  G4double dxsec = 0.0;
215  if (gammaEnergy < 0.0 || fPrimaryKinEnergy <= 0.0) {
216  return dxsec;
217  }
218  // reduced photon energy
219  const G4double x = gammaEnergy/fPrimaryKinEnergy;
220  // l-kinetic energy of the e-/e+
222  // make sure that the Z-related SB-DCS are loaded
223  // NOTE: fCurrentIZ should have been set before.
225  if (!gSBDCSData[fCurrentIZ]) {
226  InitialiseForElement(nullptr, fCurrentIZ);
227  }
228  // NOTE: SetupForMaterial should have been called before!
232  dxsec = val*invb2*CLHEP::millibarn/gBremFactor;
233  // e+ correction
234  if (!fIsElectron) {
235  const G4double invbeta1 = std::sqrt(invb2);
236  const G4double e2 = fPrimaryKinEnergy-gammaEnergy;
237  if (e2 > 0.0) {
238  const G4double invbeta2 = (e2+kMC2)/std::sqrt(e2*(e2+2.0*kMC2));
239  const G4double dum0 = kAlpha*fCurrentIZ*(invbeta1-invbeta2);
240  if (dum0 < gExpNumLimit) {
241  dxsec = 0.0;
242  } else {
243  dxsec *= G4Exp(dum0);
244  }
245  } else {
246  dxsec = 0.0;
247  }
248  }
249  return dxsec;
250 }
251 
252 void
253 G4SeltzerBergerModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
254  const G4MaterialCutsCouple* couple,
255  const G4DynamicParticle* dp,
256  G4double cutEnergy,
257  G4double maxEnergy)
258 {
259  const G4double kinEnergy = dp->GetKineticEnergy();
260  const G4double logKinEnergy = dp->GetLogKineticEnergy();
261  const G4double tmin = std::min(cutEnergy, kinEnergy);
262  const G4double tmax = std::min(maxEnergy, kinEnergy);
263  if (tmin >= tmax) {
264  return;
265  }
266  // set local variables and select target element
267  SetupForMaterial(fPrimaryParticle, couple->GetMaterial(), kinEnergy);
268  const G4Element* elm = SelectTargetAtom(couple, fPrimaryParticle, kinEnergy,
269  logKinEnergy, tmin, tmax);
270  fCurrentIZ = std::max(std::min(elm->GetZasInt(),gMaxZet-1), 1);
271  //
272  const G4double totMomentum = std::sqrt(kinEnergy*(fPrimaryTotalEnergy+kMC2));
273  /*
274  G4cout << "G4SeltzerBergerModel::SampleSecondaries E(MeV)= "
275  << kinEnergy/MeV
276  << " Z= " << fCurrentIZ << " cut(MeV)= " << tmin/MeV
277  << " emax(MeV)= " << tmax/MeV << " corr= " << fDensityCorr << G4endl;
278  */
279  // sample emitted photon energy either by rejection or from samplign tables
280  const G4double gammaEnergy = !fIsUseSamplingTables
281  ? SampleEnergyTransfer(kinEnergy, logKinEnergy, tmin, tmax)
282  : gSBSamplingTable->SampleEnergyTransfer(kinEnergy, logKinEnergy, tmin,
284  // should never happen under normal conditions but protect it
285  if (gammaEnergy <= 0.) {
286  return;
287  }
288  //
289  // angles of the emitted gamma. ( Z - axis along the parent particle) use
290  // general interface
292  fPrimaryTotalEnergy-gammaEnergy, fCurrentIZ, couple->GetMaterial());
293  // create G4DynamicParticle object for the emitted Gamma
295  gammaEnergy);
296  vdp->push_back(gamma);
297  //
298  // compute post-interaction kinematics of the primary e-/e+
299  G4ThreeVector dir =
300  (totMomentum*dp->GetMomentumDirection()-gammaEnergy*gamDir).unit();
301  const G4double finalE = kinEnergy - gammaEnergy;
302  /*
303  G4cout << "### G4SBModel: v= "
304  << " Eg(MeV)= " << gammaEnergy
305  << " Ee(MeV)= " << kineticEnergy
306  << " DirE " << direction << " DirG " << gammaDirection
307  << G4endl;
308  */
309  // if secondary gamma energy is higher than threshold(very high by default)
310  // then stop tracking the primary particle and create new secondary e-/e+
311  // instead of the primary
312  if (gammaEnergy > SecondaryThreshold()) {
316  const_cast<G4ParticleDefinition*>(fPrimaryParticle), dir, finalE);
317  vdp->push_back(el);
318  } else { // continue tracking the primary e-/e+ otherwise
321  }
322 }
323 
324 // sample emitted photon energy by usign rejection
325 G4double
327  const G4double logKinEnergy,
328  const G4double tmin,
329  const G4double tmax)
330 {
331  // min max of the transformed variable: x(k) = ln(k^2+k_p^2) that is in
332  // [ln(k_c^2+k_p^2), ln(E_k^2+k_p^2)]
333  const G4double xmin = G4Log(tmin*tmin+fDensityCorr);
334  const G4double xrange = G4Log(tmax*tmax+fDensityCorr)-xmin;
335  const G4double y = logKinEnergy;
336  // majoranta
337  const G4double x0 = tmin/kinEnergy;
338  G4double vmax;
339  if (!gSBDCSData[fCurrentIZ]) {
340  InitialiseForElement(nullptr, fCurrentIZ);
341  }
342  vmax = gSBDCSData[fCurrentIZ]->Value(x0, y, fIndx, fIndy)*1.02;
343  //
344  static const G4double kEPeakLim = 300.*CLHEP::MeV;
345  static const G4double kELowLim = 20.*CLHEP::keV;
346  // majoranta corrected for e-
347  if (fIsElectron && x0 < 0.97 &&
348  ((kinEnergy>kEPeakLim) || (kinEnergy<kELowLim))) {
349  G4double ylim = std::min(gYLimitData[fCurrentIZ],
350  1.1*gSBDCSData[fCurrentIZ]->Value(0.97,y,fIndx,fIndy));
351  vmax = std::max(vmax, ylim);
352  }
353  if (x0 < 0.05) {
354  vmax *= 1.2;
355  }
356  //G4cout<<"y= "<<y<<" xmin= "<<xmin<<" xmax= "<<xmax
357  //<<" vmax= "<<vmax<<G4endl;
358  static const G4int kNCountMax = 100;
359  CLHEP::HepRandomEngine* rndmEngine = G4Random::getTheEngine();
360  G4double rndm[2];
361  G4double gammaEnergy, v;
362  for (G4int nn = 0; nn < kNCountMax; ++nn) {
363  rndmEngine->flatArray(2, rndm);
364  gammaEnergy =
365  std::sqrt(std::max(G4Exp(xmin + rndm[0]*xrange)-fDensityCorr,0.));
366  v = gSBDCSData[fCurrentIZ]->Value(gammaEnergy/kinEnergy, y, fIndx, fIndy);
367  // e+ correction
368  if (!fIsElectron) {
369  const G4double e1 = kinEnergy - tmin;
370  const G4double invbeta1 = (e1+kMC2)/std::sqrt(e1*(e1+2.*kMC2));
371  const G4double e2 = kinEnergy-gammaEnergy;
372  const G4double invbeta2 = (e2+kMC2)/std::sqrt(e2*(e2+2.*kMC2));
373  const G4double dum0 = kAlpha*fCurrentIZ*(invbeta1-invbeta2);
374  if (dum0 < gExpNumLimit) {
375  v = 0.0;
376  } else {
377  v *= G4Exp(dum0);
378  }
379  }
380  if (v > 1.05*vmax && fNumWarnings < 11) {
381  ++fNumWarnings;
383  ed << "### G4SeltzerBergerModel Warning: Majoranta exceeded! "
384  << v << " > " << vmax << " by " << v/vmax
385  << " Niter= " << nn
386  << " Egamma(MeV)= " << gammaEnergy
387  << " Ee(MeV)= " << kinEnergy
388  << " Z= " << fCurrentIZ << " " << fPrimaryParticle->GetParticleName();
389  //
390  if (10 == fNumWarnings) {
391  ed << "\n ### G4SeltzerBergerModel Warnings stopped";
392  }
393  G4Exception("G4SeltzerBergerModel::SampleScattering","em0044",
394  JustWarning, ed,"");
395  }
396  if (v >= vmax*rndm[1]) {
397  break;
398  }
399  }
400  return gammaEnergy;
401 }
402 
404  G4int Z)
405 {
406  if (!gSBDCSData[Z]) {
407 #ifdef G4MULTITHREADED
408  G4MUTEXLOCK(&theSBMutex);
409  if (!gSBDCSData[Z]) {
410 #endif
411  ReadData(Z);
412 #ifdef G4MULTITHREADED
413  }
414  G4MUTEXUNLOCK(&theSBMutex);
415 #endif
416  }
417 }
418 
420  const G4Material* mat,
421  G4double kineticEnergy)
422 {
424  // calculate threshold for density effect: gamma*k_p = sqrt(fDensityCorr)
425  fPrimaryKinEnergy = kineticEnergy;
428  fIsLPMActive = LPMFlag();
429 }
430