Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4PenelopeBremsstrahlungFS.cc
Go to the documentation of this file.
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 // $Id$
27 //
28 // Author: Luciano Pandola
29 //
30 // History:
31 // --------
32 // 23 Nov 2010 L Pandola First complete implementation
33 // 02 May 2011 L.Pandola Remove dependency on CLHEP::HepMatrix
34 // 24 May 2011 L. Pandola Renamed (make v2008 as default Penelope)
35 //
36 
37 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
38 
39 #include "G4PhysicalConstants.hh"
40 #include "G4SystemOfUnits.hh"
42 #include "G4PhysicsFreeVector.hh"
43 #include "G4PhysicsLogVector.hh"
44 #include "G4PhysicsTable.hh"
45 #include "G4Material.hh"
46 #include "Randomize.hh"
47 
48 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
49 
51  theReducedXSTable(0),theEffectiveZSq(0),theSamplingTable(0),
52  thePBcut(0)
53 {
54  G4double tempvector[nBinsX] =
55  {1.0e-12,0.025e0,0.05e0,0.075e0,0.1e0,0.15e0,0.2e0,0.25e0,
56  0.3e0,0.35e0,0.4e0,0.45e0,0.5e0,0.55e0,0.6e0,0.65e0,0.7e0,
57  0.75e0,0.8e0,0.85e0,0.9e0,0.925e0,0.95e0,0.97e0,0.99e0,
58  0.995e0,0.999e0,0.9995e0,0.9999e0,0.99995e0,0.99999e0,1.0e0};
59 
60  for (size_t ix=0;ix<nBinsX;ix++)
61  theXGrid[ix] = tempvector[ix];
62 
63  for (size_t i=0;i<nBinsE;i++)
64  theEGrid[i] = 0.;
65 
66  theElementData = new std::map<G4int,G4DataVector*>;
67  theTempVec = new G4PhysicsFreeVector(nBinsX);
68 }
69 
70 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
71 
73 {
74  ClearTables();
75 
76  if (theTempVec)
77  delete theTempVec;
78 
79  //Clear manually theElementData
80  std::map<G4int,G4DataVector*>::iterator i;
81  if (theElementData)
82  {
83  for (i=theElementData->begin(); i != theElementData->end(); i++)
84  delete i->second;
85  delete theElementData;
86  theElementData = 0;
87  }
88 
89 }
90 
91 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...
92 
93 
95 {
96  std::map< std::pair<const G4Material*,G4double> ,G4PhysicsTable*>::iterator j;
97 
98  if (theReducedXSTable)
99  {
100  for (j=theReducedXSTable->begin(); j != theReducedXSTable->end(); j++)
101  {
102  G4PhysicsTable* tab = j->second;
103  tab->clearAndDestroy();
104  delete tab;
105  }
106  delete theReducedXSTable;
107  theReducedXSTable = 0;
108  }
109 
110  if (theSamplingTable)
111  {
112  for (j=theSamplingTable->begin(); j != theSamplingTable->end(); j++)
113  {
114  G4PhysicsTable* tab = j->second;
115  tab->clearAndDestroy();
116  delete tab;
117  }
118  delete theSamplingTable;
119  theSamplingTable = 0;
120  }
121 
122  std::map< std::pair<const G4Material*,G4double> ,G4PhysicsFreeVector*>::iterator kk;
123  if (thePBcut)
124  {
125  for (kk=thePBcut->begin(); kk != thePBcut->end(); kk++)
126  delete kk->second;
127  delete thePBcut;
128  thePBcut = 0;
129  }
130 
131 
132  if (theEffectiveZSq)
133  {
134  delete theEffectiveZSq;
135  theEffectiveZSq = 0;
136  }
137 
138  return;
139 }
140 
141 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
142 
144 {
145  if (!theEffectiveZSq)
146  {
148  ed << "The container for the <Z^2> values is not initialized" << G4endl;
149  G4Exception("G4PenelopeBremsstrahlungFS::GetEffectiveZSquared()",
150  "em2007",FatalException,ed);
151  return 0;
152  }
153  //found in the table: return it
154  if (theEffectiveZSq->count(material))
155  return theEffectiveZSq->find(material)->second;
156  else
157  {
159  ed << "The value of <Z^2> is not properly set for material " <<
160  material->GetName() << G4endl;
161  //requires running of BuildScaledXSTable()
162  G4Exception("G4PenelopeBremsstrahlungFS::GetEffectiveZSquared()",
163  "em2008",FatalException,ed);
164  }
165  return 0;
166 }
167 
168 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
169 
170 void G4PenelopeBremsstrahlungFS::BuildScaledXSTable(const G4Material* material,
171  G4double cut)
172 {
173  //Corresponds to subroutines EBRaW and EBRaR of PENELOPE
174  /*
175  This method generates the table of the scaled energy-loss cross section from
176  bremsstrahlung emission for the given material. Original data are read from
177  file. The table is normalized according to the Berger-Seltzer cross section.
178  */
179 
180  //*********************************************************************
181  //Determine the equivalent atomic number <Z^2>
182  //*********************************************************************
183  std::vector<G4double> *StechiometricFactors = new std::vector<G4double>;
184  G4int nElements = material->GetNumberOfElements();
185  const G4ElementVector* elementVector = material->GetElementVector();
186  const G4double* fractionVector = material->GetFractionVector();
187  for (G4int i=0;i<nElements;i++)
188  {
189  G4double fraction = fractionVector[i];
190  G4double atomicWeigth = (*elementVector)[i]->GetA()/(g/mole);
191  StechiometricFactors->push_back(fraction/atomicWeigth);
192  }
193  //Find max
194  G4double MaxStechiometricFactor = 0.;
195  for (G4int i=0;i<nElements;i++)
196  {
197  if ((*StechiometricFactors)[i] > MaxStechiometricFactor)
198  MaxStechiometricFactor = (*StechiometricFactors)[i];
199  }
200  //Normalize
201  for (G4int i=0;i<nElements;i++)
202  (*StechiometricFactors)[i] /= MaxStechiometricFactor;
203 
204  G4double sumz2 = 0;
205  G4double sums = 0;
206  for (G4int i=0;i<nElements;i++)
207  {
208  G4double Z = (*elementVector)[i]->GetZ();
209  sumz2 += (*StechiometricFactors)[i]*Z*Z;
210  sums += (*StechiometricFactors)[i];
211  }
212  G4double ZBR2 = sumz2/sums;
213 
214  theEffectiveZSq->insert(std::make_pair(material,ZBR2));
215 
216 
217  //*********************************************************************
218  // loop on elements and read data files
219  //*********************************************************************
220  G4DataVector* tempData = new G4DataVector(nBinsE);
221  G4DataVector* tempMatrix = new G4DataVector(nBinsE*nBinsX,0.);
222 
223  for (G4int iel=0;iel<nElements;iel++)
224  {
225  G4double Z = (*elementVector)[iel]->GetZ();
226  G4int iZ = (G4int) Z;
227  G4double wgt = (*StechiometricFactors)[iel]*Z*Z/ZBR2;
228  //
229 
230  //the element is not already loaded
231  if (!theElementData->count(iZ))
232  {
233  ReadDataFile(iZ);
234  if (!theElementData->count(iZ))
235  {
237  ed << "Error in G4PenelopeBremsstrahlungFS::BuildScaledXSTable" << G4endl;
238  ed << "Unable to retrieve data for element " << iZ << G4endl;
239  G4Exception("G4PenelopeBremsstrahlungFS::BuildScaledXSTable()",
240  "em2009",FatalException,ed);
241  }
242  }
243 
244  G4DataVector* atomData = theElementData->find(iZ)->second;
245 
246  for (size_t ie=0;ie<nBinsE;ie++)
247  {
248  (*tempData)[ie] += wgt*(*atomData)[ie*(nBinsX+1)+nBinsX]; //last column contains total XS
249  for (size_t ix=0;ix<nBinsX;ix++)
250  (*tempMatrix)[ie*nBinsX+ix] += wgt*(*atomData)[ie*(nBinsX+1)+ix];
251  }
252  }
253 
254  //*********************************************************************
255  // the total energy loss spectrum is re-normalized to reproduce the total
256  // scaled cross section of Berger and Seltzer
257  //*********************************************************************
258  for (size_t ie=0;ie<nBinsE;ie++)
259  {
260  //for each energy, calculate integral of dSigma/dx over dx
261  G4double* tempData2 = new G4double[nBinsX];
262  for (size_t ix=0;ix<nBinsX;ix++)
263  tempData2[ix] = (*tempMatrix)[ie*nBinsX+ix];
264  G4double rsum = GetMomentumIntegral(tempData2,1.0,0);
265  delete[] tempData2;
266  G4double fact = millibarn*(theEGrid[ie]+electron_mass_c2)*(1./fine_structure_const)/
268  G4double fnorm = (*tempData)[ie]/(rsum*fact);
269  G4double TST = 100.*std::fabs(fnorm-1.0);
270  if (TST > 1.0)
271  {
273  ed << "G4PenelopeBremsstrahlungFS. Corrupted data files?" << G4endl;
274  G4cout << "TST= " << TST << "; fnorm = " << fnorm << G4endl;
275  G4cout << "rsum = " << rsum << G4endl;
276  G4cout << "fact = " << fact << G4endl;
277  G4cout << ie << " " << theEGrid[ie]/keV << " " << (*tempData)[ie]/barn << G4endl;
278  G4Exception("G4PenelopeBremsstrahlungFS::BuildScaledXSTable()",
279  "em2010",FatalException,ed);
280  }
281  for (size_t ix=0;ix<nBinsX;ix++)
282  (*tempMatrix)[ie*nBinsX+ix] *= fnorm;
283  }
284 
285  //*********************************************************************
286  // create and fill the tables
287  //*********************************************************************
288  G4PhysicsTable* thePhysicsTable = new G4PhysicsTable();
289  // the table will contain 32 G4PhysicsFreeVectors with different
290  // values of x. Each of the G4PhysicsFreeVectors has a profile of
291  // log(XS) vs. log(E)
292 
293  //reserve space of the vectors. Everything is log-log
294  //I add one extra "fake" point at low energy, since the Penelope
295  //table starts at 1 keV
296  for (size_t i=0;i<nBinsX;i++)
297  thePhysicsTable->push_back(new G4PhysicsFreeVector(nBinsE+1));
298 
299  for (size_t ix=0;ix<nBinsX;ix++)
300  {
301  G4PhysicsFreeVector* theVec =
302  (G4PhysicsFreeVector*) ((*thePhysicsTable)[ix]);
303  for (size_t ie=0;ie<nBinsE;ie++)
304  {
305  G4double logene = std::log(theEGrid[ie]);
306  G4double aValue = (*tempMatrix)[ie*nBinsX+ix];
307  if (aValue < 1e-20*millibarn) //protection against log(0)
308  aValue = 1e-20*millibarn;
309  theVec->PutValue(ie+1,logene,std::log(aValue));
310  }
311  //Add fake point at 1 eV using an extrapolation with the derivative
312  //at the first valid point (Penelope approach)
313  G4double derivative = ((*theVec)[2]-(*theVec)[1])/(theVec->Energy(2) - theVec->Energy(1));
314  G4double log1eV = std::log(1*eV);
315  G4double val1eV = (*theVec)[1]+derivative*(log1eV-theVec->Energy(1));
316  //fake point at very low energy
317  theVec->PutValue(0,log1eV,val1eV);
318  }
319  std::pair<const G4Material*,G4double> theKey = std::make_pair(material,cut);
320  theReducedXSTable->insert(std::make_pair(theKey,thePhysicsTable));
321 
322  delete StechiometricFactors;
323  delete tempData;
324  delete tempMatrix;
325 
326  return;
327 }
328 
329 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
330 
331 void G4PenelopeBremsstrahlungFS::ReadDataFile(G4int Z)
332 {
333 
334  char* path = getenv("G4LEDATA");
335  if (!path)
336  {
337  G4String excep = "G4PenelopeBremsstrahlungFS - G4LEDATA environment variable not set!";
338  G4Exception("G4PenelopeBremsstrahlungFS::ReadDataFile()",
339  "em0006",FatalException,excep);
340  return;
341  }
342  /*
343  Read the cross section file
344  */
345  std::ostringstream ost;
346  if (Z>9)
347  ost << path << "/penelope/bremsstrahlung/pdebr" << Z << ".p08";
348  else
349  ost << path << "/penelope/bremsstrahlung/pdebr0" << Z << ".p08";
350  std::ifstream file(ost.str().c_str());
351  if (!file.is_open())
352  {
353  G4String excep = "G4PenelopeBremsstrahlungFS - data file " +
354  G4String(ost.str()) + " not found!";
355  G4Exception("G4PenelopeBremsstrahlungFS::ReadDataFile()",
356  "em0003",FatalException,excep);
357  return;
358  }
359 
360  G4int readZ =0;
361  file >> readZ;
362 
363  //check the right file is opened.
364  if (readZ != Z)
365  {
367  ed << "Corrupted data file for Z=" << Z << G4endl;
368  G4Exception("G4PenelopeBremsstrahlungFS::ReadDataFile()",
369  "em0005",FatalException,ed);
370  return;
371  }
372 
373  G4DataVector* theMatrix = new G4DataVector(nBinsE*(nBinsX+1),0.); //initialized with zeros
374 
375  for (size_t ie=0;ie<nBinsE;ie++)
376  {
377  G4double myDouble = 0;
378  file >> myDouble; //energy (eV)
379  if (!theEGrid[ie]) //fill only the first time
380  theEGrid[ie] = myDouble*eV;
381  //
382  for (size_t ix=0;ix<nBinsX;ix++)
383  {
384  file >> myDouble;
385  (*theMatrix)[ie*(nBinsX+1)+ix] = myDouble*millibarn;
386  }
387  file >> myDouble; //total cross section
388  (*theMatrix)[ie*(nBinsX+1)+nBinsX] = myDouble*millibarn;
389  }
390 
391  if (theElementData)
392  theElementData->insert(std::make_pair(Z,theMatrix));
393  else
394  delete theMatrix;
395  file.close();
396  return;
397 }
398 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
399 
401  G4double xup,G4int momOrder)
402 //x is always the gridX
403 {
404  //Corresponds to the function RLMOM of Penelope
405  //This method performs the calculation of the integral of (x^momOrder)*y over the interval
406  //from x[0] to xup, obtained by linear interpolation on a table of y.
407  //The independent variable is assumed to take positive values only.
408  //
409  size_t size = nBinsX;
410  const G4double eps = 1e-35;
411 
412  //Check that the call is valid
413  if (momOrder<-1 || size<2 || theXGrid[0]<0)
414  {
415  G4Exception("G4PenelopeBremsstrahlungFS::GetMomentumIntegral()",
416  "em2011",FatalException,"Invalid call");
417  }
418 
419  for (size_t i=1;i<size;i++)
420  {
421  if (theXGrid[i]<0 || theXGrid[i]<theXGrid[i-1])
422  {
424  ed << "Invalid call for bin " << i << G4endl;
425  G4Exception("G4PenelopeBremsstrahlungFS::GetMomentumIntegral()",
426  "em2012",FatalException,ed);
427  }
428  }
429 
430  //Compute the integral
431  G4double result = 0;
432  if (xup < theXGrid[0])
433  return result;
434  bool loopAgain = true;
435  G4double xt = std::min(xup,theXGrid[size-1]);
436  G4double xtc = 0;
437  for (size_t i=0;i<size-1;i++)
438  {
439  G4double x1 = std::max(theXGrid[i],eps);
440  G4double y1 = y[i];
441  G4double x2 = std::max(theXGrid[i+1],eps);
442  G4double y2 = y[i+1];
443  if (xt < x2)
444  {
445  xtc = xt;
446  loopAgain = false;
447  }
448  else
449  xtc = x2;
450  G4double dx = x2-x1;
451  G4double dy = y2-y1;
452  G4double ds = 0;
453  if (std::fabs(dx)>1e-14*std::fabs(dy))
454  {
455  G4double b=dy/dx;
456  G4double a=y1-b*x1;
457  if (momOrder == -1)
458  ds = a*std::log(xtc/x1)+b*(xtc-x1);
459  else if (momOrder == 0) //speed it up, not using pow()
460  ds = a*(xtc-x1) + 0.5*b*(xtc*xtc-x1*x1);
461  else
462  ds = a*(std::pow(xtc,momOrder+1)-std::pow(x1,momOrder+1))/((G4double) (momOrder + 1))
463  + b*(std::pow(xtc,momOrder+2)-std::pow(x1,momOrder+2))/((G4double) (momOrder + 2));
464  }
465  else
466  ds = 0.5*(y1+y2)*(xtc-x1)*std::pow(xtc,momOrder);
467  result += ds;
468  if (!loopAgain)
469  return result;
470  }
471  return result;
472 }
473 
474 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
475 
477  G4double cut)
478 {
479  //check if the container exists (if not, create it)
480  if (!theReducedXSTable)
481  theReducedXSTable = new std::map< std::pair<const G4Material*,G4double> ,
482  G4PhysicsTable*>;
483  if (!theEffectiveZSq)
484  theEffectiveZSq = new std::map<const G4Material*,G4double>;
485 
486  //check if it already contains the entry
487  std::pair<const G4Material*,G4double> theKey = std::make_pair(mat,cut);
488  if (!(theReducedXSTable->count(theKey))) //not found
489  BuildScaledXSTable(mat,cut);
490 
491  if (!(theReducedXSTable->count(theKey)))
492  {
493  G4Exception("G4PenelopeBremsstrahlungFS::GetScaledXSTable()",
494  "em2013",FatalException,"Unable to retrieve the cross section table");
495  }
496 
497  return theReducedXSTable->find(theKey)->second;
498 }
499 
500 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
501 
502 void G4PenelopeBremsstrahlungFS::InitializeEnergySampling(const G4Material* material,
503  G4double cut)
504 {
505  std::pair<const G4Material*,G4double> theKey = std::make_pair(material,cut);
506 
507  G4PhysicsTable* thePhysicsTable = new G4PhysicsTable();
508  // the table will contain 57 G4PhysicsFreeVectors with different
509  // values of E.
510  G4PhysicsFreeVector* thePBvec = new G4PhysicsFreeVector(nBinsE);
511 
512  //I reserve space of the vectors.
513  for (size_t i=0;i<nBinsE;i++)
514  thePhysicsTable->push_back(new G4PhysicsFreeVector(nBinsX));
515 
516  //Retrieve existing table using the method GetScaledXSTable()
517  //This will create the table ex-novo, if it does not exist for
518  //some reason
519  G4PhysicsTable* theTableReduced = GetScaledXSTable(material,cut);
520 
521  for (size_t ie=0;ie<nBinsE;ie++)
522  {
523  G4PhysicsFreeVector* theVec =
524  (G4PhysicsFreeVector*) ((*thePhysicsTable)[ie]);
525  //Fill the table
526  G4double value = 0; //first value
527  theVec->PutValue(0,theXGrid[0],value);
528  for (size_t ix=1;ix<nBinsX;ix++)
529  {
530  //Here calculate the cumulative distribution
531  // int_{0}^{x} dSigma(x',E)/dx' (1/x') dx'
532  G4PhysicsFreeVector* v1 = (G4PhysicsFreeVector*) (*theTableReduced)[ix-1];
533  G4PhysicsFreeVector* v2 = (G4PhysicsFreeVector*) (*theTableReduced)[ix];
534 
535  G4double x1=std::max(theXGrid[ix-1],1.0e-35);
536  //Remember: the table theReducedXSTable has a fake first point in energy
537  //so, it contains one more bin than nBinsE.
538  G4double y1=std::exp((*v1)[ie+1]);
539  G4double x2=std::max(theXGrid[ix],1.0e-35);
540  G4double y2=std::exp((*v2)[ie+1]);
541  G4double B = (y2-y1)/(x2-x1);
542  G4double A = y1-B*x1;
543  G4double dS = A*std::log(x2/x1)+B*(x2-x1);
544  value += dS;
545  theVec->PutValue(ix,theXGrid[ix],value);
546  }
547 
548  //fill the PB vector
549  G4double xc = cut/theEGrid[ie];
550  //Fill a temp data vector
551  G4double* tempData = new G4double[nBinsX];
552  for (size_t ix=0;ix<nBinsX;ix++)
553  {
554  G4PhysicsFreeVector* vv = (G4PhysicsFreeVector*) (*theTableReduced)[ix];
555  tempData[ix] = std::exp((*vv)[ie+1]);
556  }
557  G4double pbval = (xc<=1) ?
558  GetMomentumIntegral(tempData,xc,-1) :
559  GetMomentumIntegral(tempData,1.0,-1);
560  thePBvec->PutValue(ie,theEGrid[ie],pbval);
561  delete[] tempData;
562  }
563 
564  theSamplingTable->insert(std::make_pair(theKey,thePhysicsTable));
565  thePBcut->insert(std::make_pair(theKey,thePBvec));
566  return;
567 }
568 
569 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
570 
572  G4double cut)
573 {
574  if (!theSamplingTable)
575  theSamplingTable =
576  new std::map< std::pair<const G4Material*,G4double> , G4PhysicsTable*>;
577  if (!thePBcut)
578  thePBcut =
579  new std::map< std::pair<const G4Material*,G4double> , G4PhysicsFreeVector* >;
580 
581  std::pair<const G4Material*,G4double> theKey = std::make_pair(mat,cut);
582 
583  if (!(theSamplingTable->count(theKey)))
584  {
585  InitializeEnergySampling(mat,cut);
586  if (!(theSamplingTable->count(theKey)) || !(thePBcut->count(theKey)))
587  {
589  ed << "Unable to create the SamplingTable: " <<
590  theSamplingTable->count(theKey) << " " <<
591  thePBcut->count(theKey) << G4endl;
592  G4Exception("G4PenelopeBremsstrahlungFS::SampleGammaEnergy()",
593  "em2014",FatalException,ed);
594  }
595  }
596 
597  G4PhysicsTable* theTableInte = theSamplingTable->find(theKey)->second;
598  G4PhysicsTable* theTableRed = theReducedXSTable->find(theKey)->second;
599 
600  //Find the energy bin using bi-partition
601  size_t eBin = 0;
602  G4bool firstOrLastBin = false;
603 
604  if (energy < theEGrid[0]) //below first bin
605  {
606  eBin = 0;
607  firstOrLastBin = true;
608  }
609  else if (energy > theEGrid[nBinsE-1]) //after last bin
610  {
611  eBin = nBinsE-1;
612  firstOrLastBin = true;
613  }
614  else
615  {
616  size_t i=0;
617  size_t j=nBinsE-1;
618  while ((j-i)>1)
619  {
620  size_t k = (i+j)/2;
621  if (energy > theEGrid[k])
622  i = k;
623  else
624  j = k;
625  }
626  eBin = i;
627  }
628 
629  //Get the appropriate physics vector
630  G4PhysicsFreeVector* theVec1 = (G4PhysicsFreeVector*) (*theTableInte)[eBin];
631 
632  //use a "temporary" vector which contains the linear interpolation of the x spectra
633  //in energy
634 
635  //theTempVect is allocated only once (member variable), but it is overwritten at
636  //every call of this method (because the interpolation factors change!)
637  if (!firstOrLastBin)
638  {
639  G4PhysicsFreeVector* theVec2 = (G4PhysicsFreeVector*) (*theTableInte)[eBin+1];
640  for (size_t iloop=0;iloop<nBinsX;iloop++)
641  {
642  G4double val = (*theVec1)[iloop]+(((*theVec2)[iloop]-(*theVec1)[iloop]))*
643  (energy-theEGrid[eBin])/(theEGrid[eBin+1]-theEGrid[eBin]);
644  theTempVec->PutValue(iloop,theXGrid[iloop],val);
645  }
646  }
647  else //first or last bin, no interpolation
648  {
649  for (size_t iloop=0;iloop<nBinsX;iloop++)
650  theTempVec->PutValue(iloop,theXGrid[iloop],(*theVec1)[iloop]);
651  }
652 
653  //Start the game
654  G4double pbcut = (*(thePBcut->find(theKey)->second))[eBin];
655 
656  if (!firstOrLastBin) //linear interpolation on pbcut as well
657  {
658  pbcut = (*(thePBcut->find(theKey)->second))[eBin] +
659  ((*(thePBcut->find(theKey)->second))[eBin+1]-(*(thePBcut->find(theKey)->second))[eBin])*
660  (energy-theEGrid[eBin])/(theEGrid[eBin+1]-theEGrid[eBin]);
661  }
662 
663  G4double pCumulative = (*theTempVec)[nBinsX-1]; //last value
664 
665  G4double eGamma = 0;
666  do
667  {
668  G4double pt = pbcut + G4UniformRand()*(pCumulative - pbcut);
669 
670  //find where it is
671  size_t ibin = 0;
672  if (pt < (*theTempVec)[0])
673  ibin = 0;
674  else if (pt > (*theTempVec)[nBinsX-1])
675  {
676  //We observed problems due to numerical rounding here (STT).
677  //delta here is a tiny positive number
678  G4double delta = pt-(*theTempVec)[nBinsX-1];
679  if (delta < pt*1e-10) // very small! Numerical rounding only
680  {
681  ibin = nBinsX-2;
683  ed << "Found that (pt > (*theTempVec)[nBinsX-1]) with pt = " << pt <<
684  " , (*theTempVec)[nBinsX-1] = " << (*theTempVec)[nBinsX-1] << " and delta = " <<
685  (pt-(*theTempVec)[nBinsX-1]) << G4endl;
686  ed << "Possible symptom of problem with numerical precision" << G4endl;
687  G4Exception("G4PenelopeBremsstrahlungFS::SampleGammaEnergy()",
688  "em2015",JustWarning,ed);
689  }
690  else //real problem
691  {
693  ed << "Crash at (pt > (*theTempVec)[nBinsX-1]) with pt = " << pt <<
694  " , (*theTempVec)[nBinsX-1]=" << (*theTempVec)[nBinsX-1] << " and nBinsX = " <<
695  nBinsX << G4endl;
696  ed << "Material: " << mat->GetName() << ", energy = " << energy/keV << " keV" <<
697  G4endl;
698  G4Exception("G4PenelopeBremsstrahlungFS::SampleGammaEnergy()",
699  "em2015",FatalException,ed);
700  }
701  }
702  else
703  {
704  size_t i=0;
705  size_t j=nBinsX-1;
706  while ((j-i)>1)
707  {
708  size_t k = (i+j)/2;
709  if (pt > (*theTempVec)[k])
710  i = k;
711  else
712  j = k;
713  }
714  ibin = i;
715  }
716 
717  G4double w1 = theXGrid[ibin];
718  G4double w2 = theXGrid[ibin+1];
719 
720  G4PhysicsFreeVector* v1 = (G4PhysicsFreeVector*) (*theTableRed)[ibin];
721  G4PhysicsFreeVector* v2 = (G4PhysicsFreeVector*) (*theTableRed)[ibin+1];
722  //Remember: the table theReducedXSTable has a fake first point in energy
723  //so, it contains one more bin than nBinsE.
724  G4double pdf1 = std::exp((*v1)[eBin+1]);
725  G4double pdf2 = std::exp((*v2)[eBin+1]);
726  G4double deltaW = w2-w1;
727  G4double dpdfb = pdf2-pdf1;
728  G4double B = dpdfb/deltaW;
729  G4double A = pdf1-B*w1;
730  //I already made an interpolation in energy, so I can use the actual value for the
731  //calculation of the wbcut, instead of the grid values (except for the last bin)
732  G4double wbcut = (cut < energy) ? cut/energy : 1.0;
733  if (firstOrLastBin) //this is an particular case: no interpolation available
734  wbcut = (cut < theEGrid[eBin]) ? cut/theEGrid[eBin] : 1.0;
735 
736  if (w1 < wbcut)
737  w1 = wbcut;
738  if (w2 < w1)
739  {
740  G4cout << "Warning in G4PenelopeBremsstrahlungFS::SampleX()" << G4endl;
741  G4cout << "Conflicting end-point values: w1=" << w1 << "; w2 = " << w2 << G4endl;
742  G4cout << "wbcut = " << wbcut << " energy= " << energy/keV << " keV" << G4endl;
743  G4cout << "cut = " << cut/keV << " keV" << G4endl;
744  return w1*energy;
745  }
746 
747  G4double pmax = std::max(A+B*w1,A+B*w2);
748  G4bool loopAgain = false;
749  do
750  {
751  loopAgain = false;
752  eGamma = w1* std::pow((w2/w1),G4UniformRand());
753  if (G4UniformRand()*pmax > (A+B*eGamma))
754  loopAgain = true;
755  }while(loopAgain);
756  eGamma *= energy;
757  }while(eGamma < cut); //repeat if sampled sub-cut!
758 
759  return eGamma;
760 }
761 
762 
763 
764