Geant4_10
G4PenelopeRayleighModel.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: G4PenelopeRayleighModel.cc 76220 2013-11-08 10:15:00Z gcosmo $
27 //
28 // Author: Luciano Pandola
29 //
30 // History:
31 // --------
32 // 03 Dec 2009 L Pandola First implementation
33 // 25 May 2011 L.Pandola Renamed (make v2008 as default Penelope)
34 // 19 Sep 2013 L.Pandola Migration to MT
35 //
36 
38 #include "G4PhysicalConstants.hh"
39 #include "G4SystemOfUnits.hh"
41 #include "G4ParticleDefinition.hh"
42 #include "G4MaterialCutsCouple.hh"
43 #include "G4ProductionCutsTable.hh"
44 #include "G4DynamicParticle.hh"
45 #include "G4PhysicsTable.hh"
46 #include "G4ElementTable.hh"
47 #include "G4Element.hh"
48 #include "G4PhysicsFreeVector.hh"
49 #include "G4AutoLock.hh"
50 
51 
52 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
53 
55  const G4String& nam)
56  :G4VEmModel(nam),fParticleChange(0),fParticle(0),isInitialised(false),
57  logAtomicCrossSection(0),atomicFormFactor(0),logFormFactorTable(0),
58  pMaxTable(0),samplingTable(0),fLocalTable(false)
59 {
60  fIntrinsicLowEnergyLimit = 100.0*eV;
61  fIntrinsicHighEnergyLimit = 100.0*GeV;
62  // SetLowEnergyLimit(fIntrinsicLowEnergyLimit);
63  SetHighEnergyLimit(fIntrinsicHighEnergyLimit);
64 
65  if (part)
66  SetParticle(part);
67 
68  //
69  verboseLevel= 0;
70  // Verbosity scale:
71  // 0 = nothing
72  // 1 = warning for energy non-conservation
73  // 2 = details of energy budget
74  // 3 = calculation of cross sections, file openings, sampling of atoms
75  // 4 = entering in methods
76 
77  //build the energy grid. It is the same for all materials
78  G4double logenergy = std::log(fIntrinsicLowEnergyLimit/2.);
79  G4double logmaxenergy = std::log(1.5*fIntrinsicHighEnergyLimit);
80  //finer grid below 160 keV
81  G4double logtransitionenergy = std::log(160*keV);
82  G4double logfactor1 = std::log(10.)/250.;
83  G4double logfactor2 = logfactor1*10;
84  logEnergyGridPMax.push_back(logenergy);
85  do{
86  if (logenergy < logtransitionenergy)
87  logenergy += logfactor1;
88  else
89  logenergy += logfactor2;
90  logEnergyGridPMax.push_back(logenergy);
91  }while (logenergy < logmaxenergy);
92 }
93 
94 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
95 
97 {
98  if (IsMaster() || fLocalTable)
99  {
100  std::map <G4int,G4PhysicsFreeVector*>::iterator i;
101  if (logAtomicCrossSection)
102  {
103  /*
104  for (i=logAtomicCrossSection->begin();i != logAtomicCrossSection->end();i++)
105  if (i->second) delete i->second;
106  */
107  delete logAtomicCrossSection;
108  }
109  }
110  if (IsMaster())
111  {
112  std::map <G4int,G4PhysicsFreeVector*>::iterator i;
113  if (atomicFormFactor)
114  {
115  /*
116  for (i=atomicFormFactor->begin();i != atomicFormFactor->end();i++)
117  if (i->second) delete i->second;
118  */
119  delete atomicFormFactor;
120  }
121 
122  ClearTables();
123  }
124 }
125 
126 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
127 void G4PenelopeRayleighModel::ClearTables()
128 {
129  if (!IsMaster())
130  //Should not be here!
131  G4Exception("G4PenelopeRayleighModel::ClearTables()",
132  "em0100",FatalException,"Worker thread in this method");
133 
134  std::map <const G4Material*,G4PhysicsFreeVector*>::iterator i;
135 
136  if (logFormFactorTable)
137  {
138  /*
139  for (i=logFormFactorTable->begin(); i != logFormFactorTable->end(); i++)
140  if (i->second) delete i->second;
141  */
142  delete logFormFactorTable;
143  logFormFactorTable = 0; //zero explicitely
144  }
145 
146  if (pMaxTable)
147  {
148  /*
149  for (i=pMaxTable->begin(); i != pMaxTable->end(); i++)
150  if (i->second) delete i->second;
151  */
152  delete pMaxTable;
153  pMaxTable = 0; //zero explicitely
154  }
155 
156  std::map<const G4Material*,G4PenelopeSamplingData*>::iterator ii;
157  if (samplingTable)
158  {
159  /*
160  for (ii=samplingTable->begin(); ii != samplingTable->end(); ii++)
161  if (ii->second) delete ii->second;
162  */
163  delete samplingTable;
164  samplingTable = 0; //zero explicitely
165  }
166 
167  return;
168 }
169 
170 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
171 
173  const G4DataVector& )
174 {
175  if (verboseLevel > 3)
176  G4cout << "Calling G4PenelopeRayleighModel::Initialise()" << G4endl;
177 
178  SetParticle(part);
179 
180  //Only the master model creates/fills/destroys the tables
181  if (IsMaster() && part == fParticle)
182  {
183  //clear tables depending on materials, not the atomic ones
184  ClearTables();
185 
186  //create new tables
187  //
188  // logAtomicCrossSection and atomicFormFactor are created only once,
189  // since they are never cleared
190  if (!logAtomicCrossSection)
191  logAtomicCrossSection = new std::map<G4int,G4PhysicsFreeVector*>;
192  if (!atomicFormFactor)
193  atomicFormFactor = new std::map<G4int,G4PhysicsFreeVector*>;
194 
195  if (!logFormFactorTable)
196  logFormFactorTable = new std::map<const G4Material*,G4PhysicsFreeVector*>;
197  if (!pMaxTable)
198  pMaxTable = new std::map<const G4Material*,G4PhysicsFreeVector*>;
199  if (!samplingTable)
200  samplingTable = new std::map<const G4Material*,G4PenelopeSamplingData*>;
201 
202 
203  G4ProductionCutsTable* theCoupleTable =
205 
206  for (size_t i=0;i<theCoupleTable->GetTableSize();i++)
207  {
208  const G4Material* material =
209  theCoupleTable->GetMaterialCutsCouple(i)->GetMaterial();
210  const G4ElementVector* theElementVector = material->GetElementVector();
211 
212  for (size_t j=0;j<material->GetNumberOfElements();j++)
213  {
214  G4int iZ = (G4int) theElementVector->at(j)->GetZ();
215  //read data files only in the master
216  if (!logAtomicCrossSection->count(iZ))
217  ReadDataFile(iZ);
218  }
219 
220  //1) If the table has not been built for the material, do it!
221  if (!logFormFactorTable->count(material))
222  BuildFormFactorTable(material);
223 
224  //2) retrieve or build the sampling table
225  if (!(samplingTable->count(material)))
226  InitializeSamplingAlgorithm(material);
227 
228  //3) retrieve or build the pMax data
229  if (!pMaxTable->count(material))
230  GetPMaxTable(material);
231 
232  }
233 
234  if (verboseLevel > 1) {
235  G4cout << "Penelope Rayleigh model v2008 is initialized " << G4endl
236  << "Energy range: "
237  << LowEnergyLimit() / keV << " keV - "
238  << HighEnergyLimit() / GeV << " GeV"
239  << G4endl;
240  }
241  }
242 
243  if(isInitialised) return;
245  isInitialised = true;
246 }
247 
248 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
249 
251  G4VEmModel *masterModel)
252 {
253  if (verboseLevel > 3)
254  G4cout << "Calling G4PenelopeRayleighModel::InitialiseLocal()" << G4endl;
255 
256  //
257  //Check that particle matches: one might have multiple master models (e.g.
258  //for e+ and e-).
259  //
260  if (part == fParticle)
261  {
262  //Get the const table pointers from the master to the workers
263  const G4PenelopeRayleighModel* theModel =
264  static_cast<G4PenelopeRayleighModel*> (masterModel);
265 
266  //Copy pointers to the data tables
267  logAtomicCrossSection = theModel->logAtomicCrossSection;
268  atomicFormFactor = theModel->atomicFormFactor;
269  logFormFactorTable = theModel->logFormFactorTable;
270  pMaxTable = theModel->pMaxTable;
271  samplingTable = theModel->samplingTable;
272 
273  //copy the G4DataVector with the grid
274  logQSquareGrid = theModel->logQSquareGrid;
275 
276  //Same verbosity for all workers, as the master
277  verboseLevel = theModel->verboseLevel;
278  }
279 
280  return;
281 }
282 
283 
284 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
285 namespace { G4Mutex PenelopeRayleighModelMutex = G4MUTEX_INITIALIZER; }
288  G4double Z,
289  G4double,
290  G4double,
291  G4double)
292 {
293  // Cross section of Rayleigh scattering in Penelope v2008 is calculated by the EPDL97
294  // tabulation, Cuellen et al. (1997), with non-relativistic form factors from Hubbel
295  // et al. J. Phys. Chem. Ref. Data 4 (1975) 471; Erratum ibid. 6 (1977) 615.
296 
297  if (verboseLevel > 3)
298  G4cout << "Calling CrossSectionPerAtom() of G4PenelopeRayleighModel" << G4endl;
299 
300  G4int iZ = (G4int) Z;
301 
302  //Either Initialize() was not called, or we are in a slave and InitializeLocal() was
303  //not invoked
304  if (!logAtomicCrossSection)
305  {
306  //create a **thread-local** version of the table. Used only for G4EmCalculator and
307  //Unit Tests
308  fLocalTable = true;
309  logAtomicCrossSection = new std::map<G4int,G4PhysicsFreeVector*>;
310  }
311  //now it should be ok
312  if (!logAtomicCrossSection->count(iZ))
313  {
314  //If we are here, it means that Initialize() was inkoved, but the MaterialTable was
315  //not filled up. This can happen in a UnitTest or via G4EmCalculator
317  ed << "Unable to retrieve the cross section table for Z=" << iZ << G4endl;
318  ed << "This can happen only in Unit Tests or via G4EmCalculator" << G4endl;
319  G4Exception("G4PenelopeRayleighModel::ComputeCrossSectionPerAtom()",
320  "em2040",JustWarning,ed);
321  //protect file reading via autolock
322  G4AutoLock lock(&PenelopeRayleighModelMutex);
323  ReadDataFile(iZ);
324  lock.unlock();
325  }
326 
327  G4double cross = 0;
328 
329  G4PhysicsFreeVector* atom = logAtomicCrossSection->find(iZ)->second;
330  if (!atom)
331  {
333  ed << "Unable to find Z=" << iZ << " in the atomic cross section table" << G4endl;
334  G4Exception("G4PenelopeRayleighModel::ComputeCrossSectionPerAtom()",
335  "em2041",FatalException,ed);
336  return 0;
337  }
338  G4double logene = std::log(energy);
339  G4double logXS = atom->Value(logene);
340  cross = std::exp(logXS);
341 
342  if (verboseLevel > 2)
343  G4cout << "Rayleigh cross section at " << energy/keV << " keV for Z=" << Z <<
344  " = " << cross/barn << " barn" << G4endl;
345  return cross;
346 }
347 
348 
349 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
350 void G4PenelopeRayleighModel::BuildFormFactorTable(const G4Material* material)
351 {
352  if (!IsMaster())
353  //Should not be here!
354  G4Exception("G4PenelopeRayleighModel::BuildFormFactorTable()",
355  "em0100",FatalException,"Worker thread in this method");
356 
357  /*
358  1) get composition and equivalent molecular density
359  */
360 
361  G4int nElements = material->GetNumberOfElements();
362  const G4ElementVector* elementVector = material->GetElementVector();
363  const G4double* fractionVector = material->GetFractionVector();
364 
365  std::vector<G4double> *StechiometricFactors = new std::vector<G4double>;
366  for (G4int i=0;i<nElements;i++)
367  {
368  G4double fraction = fractionVector[i];
369  G4double atomicWeigth = (*elementVector)[i]->GetA()/(g/mole);
370  StechiometricFactors->push_back(fraction/atomicWeigth);
371  }
372  //Find max
373  G4double MaxStechiometricFactor = 0.;
374  for (G4int i=0;i<nElements;i++)
375  {
376  if ((*StechiometricFactors)[i] > MaxStechiometricFactor)
377  MaxStechiometricFactor = (*StechiometricFactors)[i];
378  }
379  if (MaxStechiometricFactor<1e-16)
380  {
382  ed << "Inconsistent data of atomic composition for " <<
383  material->GetName() << G4endl;
384  G4Exception("G4PenelopeRayleighModel::BuildFormFactorTable()",
385  "em2042",FatalException,ed);
386  }
387  //Normalize
388  for (G4int i=0;i<nElements;i++)
389  (*StechiometricFactors)[i] /= MaxStechiometricFactor;
390 
391  // Equivalent atoms per molecule
392  G4double atomsPerMolecule = 0;
393  for (G4int i=0;i<nElements;i++)
394  atomsPerMolecule += (*StechiometricFactors)[i];
395 
396  /*
397  CREATE THE FORM FACTOR TABLE
398  */
399  G4PhysicsFreeVector* theFFVec = new G4PhysicsFreeVector(logQSquareGrid.size());
400  theFFVec->SetSpline(true);
401 
402  for (size_t k=0;k<logQSquareGrid.size();k++)
403  {
404  G4double ff2 = 0; //squared form factor
405  for (G4int i=0;i<nElements;i++)
406  {
407  G4int iZ = (G4int) (*elementVector)[i]->GetZ();
408  G4PhysicsFreeVector* theAtomVec = atomicFormFactor->find(iZ)->second;
409  G4double f = (*theAtomVec)[k]; //the q-grid is always the same
410  ff2 += f*f*(*StechiometricFactors)[i];
411  }
412  if (ff2)
413  theFFVec->PutValue(k,logQSquareGrid[k],std::log(ff2)); //NOTICE: THIS IS log(Q^2) vs. log(F^2)
414  }
415  logFormFactorTable->insert(std::make_pair(material,theFFVec));
416 
417  delete StechiometricFactors;
418 
419  return;
420 }
421 
422 
423 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
424 
425 void G4PenelopeRayleighModel::SampleSecondaries(std::vector<G4DynamicParticle*>* ,
426  const G4MaterialCutsCouple* couple,
427  const G4DynamicParticle* aDynamicGamma,
428  G4double,
429  G4double)
430 {
431  // Sampling of the Rayleigh final state (namely, scattering angle of the photon)
432  // from the Penelope2008 model. The scattering angle is sampled from the atomic
433  // cross section dOmega/d(cosTheta) from Born ("Atomic Phyisics", 1969), disregarding
434  // anomalous scattering effects. The Form Factor F(Q) function which appears in the
435  // analytical cross section is retrieved via the method GetFSquared(); atomic data
436  // are tabulated for F(Q). Form factor for compounds is calculated according to
437  // the additivity rule. The sampling from the F(Q) is made via a Rational Inverse
438  // Transform with Aliasing (RITA) algorithm; RITA parameters are calculated once
439  // for each material and managed by G4PenelopeSamplingData objects.
440  // The sampling algorithm (rejection method) has efficiency 67% at low energy, and
441  // increases with energy. For E=100 keV the efficiency is 100% and 86% for
442  // hydrogen and uranium, respectively.
443 
444  if (verboseLevel > 3)
445  G4cout << "Calling SamplingSecondaries() of G4PenelopeRayleighModel" << G4endl;
446 
447  G4double photonEnergy0 = aDynamicGamma->GetKineticEnergy();
448 
449  if (photonEnergy0 <= fIntrinsicLowEnergyLimit)
450  {
454  return ;
455  }
456 
457  G4ParticleMomentum photonDirection0 = aDynamicGamma->GetMomentumDirection();
458 
459  const G4Material* theMat = couple->GetMaterial();
460 
461 
462  //1) Verify if tables are ready
463  if (!pMaxTable || !samplingTable)
464  {
465  G4Exception("G4PenelopeRayleighModel::SampleSecondaries()",
466  "em2043",FatalException,"Invalid model initialization");
467  return;
468  }
469 
470  G4PenelopeSamplingData* theDataTable = samplingTable->find(theMat)->second;
471 
472 
473  G4PhysicsFreeVector* thePMax = pMaxTable->find(theMat)->second;
474 
475  G4double cosTheta = 1.0;
476 
477  //OK, ready to go!
478  G4double qmax = 2.0*photonEnergy0/electron_mass_c2; //this is non-dimensional now
479 
480  if (qmax < 1e-10) //very low momentum transfer
481  {
482  G4bool loopAgain=false;
483  do
484  {
485  loopAgain = false;
486  cosTheta = 1.0-2.0*G4UniformRand();
487  G4double G = 0.5*(1+cosTheta*cosTheta);
488  if (G4UniformRand()>G)
489  loopAgain = true;
490  }while(loopAgain);
491  }
492  else //larger momentum transfer
493  {
494  size_t nData = theDataTable->GetNumberOfStoredPoints();
495  G4double LastQ2inTheTable = theDataTable->GetX(nData-1);
496  G4double q2max = std::min(qmax*qmax,LastQ2inTheTable);
497 
498  G4bool loopAgain = false;
499  G4double MaxPValue = thePMax->Value(photonEnergy0);
500  G4double xx=0;
501 
502  //Sampling by rejection method. The rejection function is
503  //G = 0.5*(1+cos^2(theta))
504  //
505  do{
506  loopAgain = false;
507  G4double RandomMax = G4UniformRand()*MaxPValue;
508  xx = theDataTable->SampleValue(RandomMax);
509  //xx is a random value of q^2 in (0,q2max),sampled according to
510  //F(Q^2) via the RITA algorithm
511  if (xx > q2max)
512  loopAgain = true;
513  cosTheta = 1.0-2.0*xx/q2max;
514  G4double G = 0.5*(1+cosTheta*cosTheta);
515  if (G4UniformRand()>G)
516  loopAgain = true;
517  }while(loopAgain);
518  }
519 
520  G4double sinTheta = std::sqrt(1-cosTheta*cosTheta);
521 
522  // Scattered photon angles. ( Z - axis along the parent photon)
523  G4double phi = twopi * G4UniformRand() ;
524  G4double dirX = sinTheta*std::cos(phi);
525  G4double dirY = sinTheta*std::sin(phi);
526  G4double dirZ = cosTheta;
527 
528  // Update G4VParticleChange for the scattered photon
529  G4ThreeVector photonDirection1(dirX, dirY, dirZ);
530 
531  photonDirection1.rotateUz(photonDirection0);
532  fParticleChange->ProposeMomentumDirection(photonDirection1) ;
533  fParticleChange->SetProposedKineticEnergy(photonEnergy0) ;
534 
535  return;
536 }
537 
538 
539 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
540 
541 void G4PenelopeRayleighModel::ReadDataFile(const G4int Z)
542 {
543  if (!IsMaster())
544  //Should not be here!
545  G4Exception("G4PenelopeRayleighModel::ReadDataFile()",
546  "em0100",FatalException,"Worker thread in this method");
547 
548  if (verboseLevel > 2)
549  {
550  G4cout << "G4PenelopeRayleighModel::ReadDataFile()" << G4endl;
551  G4cout << "Going to read Rayleigh data files for Z=" << Z << G4endl;
552  }
553 
554  char* path = getenv("G4LEDATA");
555  if (!path)
556  {
557  G4String excep = "G4LEDATA environment variable not set!";
558  G4Exception("G4PenelopeRayleighModel::ReadDataFile()",
559  "em0006",FatalException,excep);
560  return;
561  }
562 
563  /*
564  Read first the cross section file
565  */
566  std::ostringstream ost;
567  if (Z>9)
568  ost << path << "/penelope/rayleigh/pdgra" << Z << ".p08";
569  else
570  ost << path << "/penelope/rayleigh/pdgra0" << Z << ".p08";
571  std::ifstream file(ost.str().c_str());
572  if (!file.is_open())
573  {
574  G4String excep = "Data file " + G4String(ost.str()) + " not found!";
575  G4Exception("G4PenelopeRayleighModel::ReadDataFile()",
576  "em0003",FatalException,excep);
577  }
578  G4int readZ =0;
579  size_t nPoints= 0;
580  file >> readZ >> nPoints;
581  //check the right file is opened.
582  if (readZ != Z || nPoints <= 0 || nPoints >= 5000)
583  {
585  ed << "Corrupted data file for Z=" << Z << G4endl;
586  G4Exception("G4PenelopeRayleighModel::ReadDataFile()",
587  "em0005",FatalException,ed);
588  return;
589  }
590  G4PhysicsFreeVector* theVec = new G4PhysicsFreeVector((size_t)nPoints);
591  G4double ene=0,f1=0,f2=0,xs=0;
592  for (size_t i=0;i<nPoints;i++)
593  {
594  file >> ene >> f1 >> f2 >> xs;
595  //dimensional quantities
596  ene *= eV;
597  xs *= cm2;
598  theVec->PutValue(i,std::log(ene),std::log(xs));
599  if (file.eof() && i != (nPoints-1)) //file ended too early
600  {
602  ed << "Corrupted data file for Z=" << Z << G4endl;
603  ed << "Found less than " << nPoints << "entries " <<G4endl;
604  G4Exception("G4PenelopeRayleighModel::ReadDataFile()",
605  "em0005",FatalException,ed);
606  }
607  }
608  if (!logAtomicCrossSection)
609  {
610  G4Exception("G4PenelopeRayleighModel::ReadDataFile()",
611  "em2044",FatalException,"Unable to allocate the atomic cross section table");
612  delete theVec;
613  return;
614  }
615  logAtomicCrossSection->insert(std::make_pair(Z,theVec));
616  file.close();
617 
618  /*
619  Then read the form factor file
620  */
621  std::ostringstream ost2;
622  if (Z>9)
623  ost2 << path << "/penelope/rayleigh/pdaff" << Z << ".p08";
624  else
625  ost2 << path << "/penelope/rayleigh/pdaff0" << Z << ".p08";
626  file.open(ost2.str().c_str());
627  if (!file.is_open())
628  {
629  G4String excep = "Data file " + G4String(ost2.str()) + " not found!";
630  G4Exception("G4PenelopeRayleighModel::ReadDataFile()",
631  "em0003",FatalException,excep);
632  }
633  file >> readZ >> nPoints;
634  //check the right file is opened.
635  if (readZ != Z || nPoints <= 0 || nPoints >= 5000)
636  {
638  ed << "Corrupted data file for Z=" << Z << G4endl;
639  G4Exception("G4PenelopeRayleighModel::ReadDataFile()",
640  "em0005",FatalException,ed);
641  return;
642  }
643  G4PhysicsFreeVector* theFFVec = new G4PhysicsFreeVector((size_t)nPoints);
644  G4double q=0,ff=0,incoh=0;
645  G4bool fillQGrid = false;
646  //fill this vector only the first time.
647  if (!logQSquareGrid.size())
648  fillQGrid = true;
649  for (size_t i=0;i<nPoints;i++)
650  {
651  file >> q >> ff >> incoh;
652  //q and ff are dimensionless (q is in units of (m_e*c)
653  theFFVec->PutValue(i,q,ff);
654  if (fillQGrid)
655  {
656  logQSquareGrid.push_back(2.0*std::log(q));
657  }
658  if (file.eof() && i != (nPoints-1)) //file ended too early
659  {
661  ed << "Corrupted data file for Z=" << Z << G4endl;
662  ed << "Found less than " << nPoints << "entries " <<G4endl;
663  G4Exception("G4PenelopeRayleighModel::ReadDataFile()",
664  "em0005",FatalException,ed);
665  }
666  }
667  if (!atomicFormFactor)
668  {
669  G4Exception("G4PenelopeRayleighModel::ReadDataFile()",
670  "em2045",FatalException,
671  "Unable to allocate the atomicFormFactor data table");
672  delete theFFVec;
673  return;
674  }
675  atomicFormFactor->insert(std::make_pair(Z,theFFVec));
676  file.close();
677  return;
678 }
679 
680 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
681 
682 G4double G4PenelopeRayleighModel::GetFSquared(const G4Material* mat, const G4double QSquared)
683 {
684  G4double f2 = 0;
685  //Input value QSquared could be zero: protect the log() below against
686  //the FPE exception
687  //If Q<1e-10, set Q to 1e-10
688  G4double logQSquared = (QSquared>1e-10) ? std::log(QSquared) : -23.;
689  //last value of the table
690  G4double maxlogQ2 = logQSquareGrid[logQSquareGrid.size()-1];
691 
692 
693  //now it should be all right
694  G4PhysicsFreeVector* theVec = logFormFactorTable->find(mat)->second;
695 
696  if (!theVec)
697  {
699  ed << "Unable to retrieve F squared table for " << mat->GetName() << G4endl;
700  G4Exception("G4PenelopeRayleighModel::GetFSquared()",
701  "em2046",FatalException,ed);
702  return 0;
703  }
704  if (logQSquared < -20) // Q < 1e-9
705  {
706  G4double logf2 = (*theVec)[0]; //first value of the table
707  f2 = std::exp(logf2);
708  }
709  else if (logQSquared > maxlogQ2)
710  f2 =0;
711  else
712  {
713  //log(Q^2) vs. log(F^2)
714  G4double logf2 = theVec->Value(logQSquared);
715  f2 = std::exp(logf2);
716 
717  }
718  if (verboseLevel > 3)
719  {
720  G4cout << "G4PenelopeRayleighModel::GetFSquared() in " << mat->GetName() << G4endl;
721  G4cout << "Q^2 = " << QSquared << " (units of 1/(m_e*c); F^2 = " << f2 << G4endl;
722  }
723  return f2;
724 }
725 
726 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
727 
728 void G4PenelopeRayleighModel::InitializeSamplingAlgorithm(const G4Material* mat)
729 {
730  if (!IsMaster())
731  //Should not be here!
732  G4Exception("G4PenelopeRayleighModel::InitializeSamplingAlgorithm()",
733  "em0100",FatalException,"Worker thread in this method");
734 
735  G4double q2min = 0;
736  G4double q2max = 0;
737  const size_t np = 150; //hard-coded in Penelope
738  //G4cout << "Init N= " << logQSquareGrid.size() << G4endl;
739  for (size_t i=1;i<logQSquareGrid.size();i++)
740  {
741  G4double Q2 = std::exp(logQSquareGrid[i]);
742  if (GetFSquared(mat,Q2) > 1e-35)
743  {
744  q2max = std::exp(logQSquareGrid[i-1]);
745  }
746  //G4cout << "Q2= " << Q2 << " q2max= " << q2max << G4endl;
747  }
748 
749  size_t nReducedPoints = np/4;
750 
751  //check for errors
752  if (np < 16)
753  {
754  G4Exception("G4PenelopeRayleighModel::InitializeSamplingAlgorithm()",
755  "em2047",FatalException,
756  "Too few points to initialize the sampling algorithm");
757  }
758  if (q2min > (q2max-1e-10))
759  {
760  G4cout << "q2min= " << q2min << " q2max= " << q2max << G4endl;
761  G4Exception("G4PenelopeRayleighModel::InitializeSamplingAlgorithm()",
762  "em2048",FatalException,
763  "Too narrow grid to initialize the sampling algorithm");
764  }
765 
766  //This is subroutine RITAI0 of Penelope
767  //Create an object of type G4PenelopeRayleighSamplingData --> store in a map::Material*
768 
769  //temporary vectors --> Then everything is stored in G4PenelopeSamplingData
770  G4DataVector* x = new G4DataVector();
771 
772  /*******************************************************************************
773  Start with a grid of NUNIF points uniformly spaced in the interval q2min,q2max
774  ********************************************************************************/
775  size_t NUNIF = std::min(std::max(((size_t)8),nReducedPoints),np/2);
776  const G4int nip = 51; //hard-coded in Penelope
777 
778  G4double dx = (q2max-q2min)/((G4double) NUNIF-1);
779  x->push_back(q2min);
780  for (size_t i=1;i<NUNIF-1;i++)
781  {
782  G4double app = q2min + i*dx;
783  x->push_back(app); //increase
784  }
785  x->push_back(q2max);
786 
787  if (verboseLevel> 3)
788  G4cout << "Vector x has " << x->size() << " points, while NUNIF = " << NUNIF << G4endl;
789 
790  //Allocate temporary storage vectors
791  G4DataVector* area = new G4DataVector();
792  G4DataVector* a = new G4DataVector();
793  G4DataVector* b = new G4DataVector();
794  G4DataVector* c = new G4DataVector();
795  G4DataVector* err = new G4DataVector();
796 
797  for (size_t i=0;i<NUNIF-1;i++) //build all points but the last
798  {
799  //Temporary vectors for this loop
800  G4DataVector* pdfi = new G4DataVector();
801  G4DataVector* pdfih = new G4DataVector();
802  G4DataVector* sumi = new G4DataVector();
803 
804  G4double dxi = ((*x)[i+1]-(*x)[i])/(G4double (nip-1));
805  G4double pdfmax = 0;
806  for (G4int k=0;k<nip;k++)
807  {
808  G4double xik = (*x)[i]+k*dxi;
809  G4double pdfk = std::max(GetFSquared(mat,xik),0.);
810  pdfi->push_back(pdfk);
811  pdfmax = std::max(pdfmax,pdfk);
812  if (k < (nip-1))
813  {
814  G4double xih = xik + 0.5*dxi;
815  G4double pdfIK = std::max(GetFSquared(mat,xih),0.);
816  pdfih->push_back(pdfIK);
817  pdfmax = std::max(pdfmax,pdfIK);
818  }
819  }
820 
821  //Simpson's integration
822  G4double cons = dxi*0.5*(1./3.);
823  sumi->push_back(0.);
824  for (G4int k=1;k<nip;k++)
825  {
826  G4double previous = (*sumi)[k-1];
827  G4double next = previous + cons*((*pdfi)[k-1]+4.0*(*pdfih)[k-1]+(*pdfi)[k]);
828  sumi->push_back(next);
829  }
830 
831  G4double lastIntegral = (*sumi)[sumi->size()-1];
832  area->push_back(lastIntegral);
833  //Normalize cumulative function
834  G4double factor = 1.0/lastIntegral;
835  for (size_t k=0;k<sumi->size();k++)
836  (*sumi)[k] *= factor;
837 
838  //When the PDF vanishes at one of the interval end points, its value is modified
839  if ((*pdfi)[0] < 1e-35)
840  (*pdfi)[0] = 1e-5*pdfmax;
841  if ((*pdfi)[pdfi->size()-1] < 1e-35)
842  (*pdfi)[pdfi->size()-1] = 1e-5*pdfmax;
843 
844  G4double pli = (*pdfi)[0]*factor;
845  G4double pui = (*pdfi)[pdfi->size()-1]*factor;
846  G4double B_temp = 1.0-1.0/(pli*pui*dx*dx);
847  G4double A_temp = (1.0/(pli*dx))-1.0-B_temp;
848  G4double C_temp = 1.0+A_temp+B_temp;
849  if (C_temp < 1e-35)
850  {
851  a->push_back(0.);
852  b->push_back(0.);
853  c->push_back(1.);
854  }
855  else
856  {
857  a->push_back(A_temp);
858  b->push_back(B_temp);
859  c->push_back(C_temp);
860  }
861 
862  //OK, now get ERR(I), the integral of the absolute difference between the rational interpolation
863  //and the true pdf, extended over the interval (X(I),X(I+1))
864  G4int icase = 1; //loop code
865  G4bool reLoop = false;
866  err->push_back(0.);
867  do
868  {
869  reLoop = false;
870  (*err)[i] = 0.; //zero variable
871  for (G4int k=0;k<nip;k++)
872  {
873  G4double rr = (*sumi)[k];
874  G4double pap = (*area)[i]*(1.0+((*a)[i]+(*b)[i]*rr)*rr)*(1.0+((*a)[i]+(*b)[i]*rr)*rr)/
875  ((1.0-(*b)[i]*rr*rr)*(*c)[i]*((*x)[i+1]-(*x)[i]));
876  if (k == 0 || k == nip-1)
877  (*err)[i] += 0.5*std::fabs(pap-(*pdfi)[k]);
878  else
879  (*err)[i] += std::fabs(pap-(*pdfi)[k]);
880  }
881  (*err)[i] *= dxi;
882 
883  //If err(I) is too large, the pdf is approximated by a uniform distribution
884  if ((*err)[i] > 0.1*(*area)[i] && icase == 1)
885  {
886  (*b)[i] = 0;
887  (*a)[i] = 0;
888  (*c)[i] = 1.;
889  icase = 2;
890  reLoop = true;
891  }
892  }while(reLoop);
893 
894  delete pdfi;
895  delete pdfih;
896  delete sumi;
897  } //end of first loop over i
898 
899  //Now assign last point
900  (*x)[x->size()-1] = q2max;
901  a->push_back(0.);
902  b->push_back(0.);
903  c->push_back(0.);
904  err->push_back(0.);
905  area->push_back(0.);
906 
907  if (x->size() != NUNIF || a->size() != NUNIF ||
908  err->size() != NUNIF || area->size() != NUNIF)
909  {
911  ed << "Problem in building the Table for Sampling: array dimensions do not match" << G4endl;
912  G4Exception("G4PenelopeRayleighModel::InitializeSamplingAlgorithm()",
913  "em2049",FatalException,ed);
914  }
915 
916  /*******************************************************************************
917  New grid points are added by halving the sub-intervals with the largest absolute error
918  This is done up to np=150 points in the grid
919  ********************************************************************************/
920  do
921  {
922  G4double maxError = 0.0;
923  size_t iErrMax = 0;
924  for (size_t i=0;i<err->size()-2;i++)
925  {
926  //maxError is the lagest of the interval errors err[i]
927  if ((*err)[i] > maxError)
928  {
929  maxError = (*err)[i];
930  iErrMax = i;
931  }
932  }
933 
934  //OK, now I have to insert one new point in the position iErrMax
935  G4double newx = 0.5*((*x)[iErrMax]+(*x)[iErrMax+1]);
936 
937  x->insert(x->begin()+iErrMax+1,newx);
938  //Add place-holders in the other vectors
939  area->insert(area->begin()+iErrMax+1,0.);
940  a->insert(a->begin()+iErrMax+1,0.);
941  b->insert(b->begin()+iErrMax+1,0.);
942  c->insert(c->begin()+iErrMax+1,0.);
943  err->insert(err->begin()+iErrMax+1,0.);
944 
945  //Now calculate the other parameters
946  for (size_t i=iErrMax;i<=iErrMax+1;i++)
947  {
948  //Temporary vectors for this loop
949  G4DataVector* pdfi = new G4DataVector();
950  G4DataVector* pdfih = new G4DataVector();
951  G4DataVector* sumi = new G4DataVector();
952 
953  G4double dxLocal = (*x)[i+1]-(*x)[i];
954  G4double dxi = ((*x)[i+1]-(*x)[i])/(G4double (nip-1));
955  G4double pdfmax = 0;
956  for (G4int k=0;k<nip;k++)
957  {
958  G4double xik = (*x)[i]+k*dxi;
959  G4double pdfk = std::max(GetFSquared(mat,xik),0.);
960  pdfi->push_back(pdfk);
961  pdfmax = std::max(pdfmax,pdfk);
962  if (k < (nip-1))
963  {
964  G4double xih = xik + 0.5*dxi;
965  G4double pdfIK = std::max(GetFSquared(mat,xih),0.);
966  pdfih->push_back(pdfIK);
967  pdfmax = std::max(pdfmax,pdfIK);
968  }
969  }
970 
971  //Simpson's integration
972  G4double cons = dxi*0.5*(1./3.);
973  sumi->push_back(0.);
974  for (G4int k=1;k<nip;k++)
975  {
976  G4double previous = (*sumi)[k-1];
977  G4double next = previous + cons*((*pdfi)[k-1]+4.0*(*pdfih)[k-1]+(*pdfi)[k]);
978  sumi->push_back(next);
979  }
980  G4double lastIntegral = (*sumi)[sumi->size()-1];
981  (*area)[i] = lastIntegral;
982 
983  //Normalize cumulative function
984  G4double factor = 1.0/lastIntegral;
985  for (size_t k=0;k<sumi->size();k++)
986  (*sumi)[k] *= factor;
987 
988  //When the PDF vanishes at one of the interval end points, its value is modified
989  if ((*pdfi)[0] < 1e-35)
990  (*pdfi)[0] = 1e-5*pdfmax;
991  if ((*pdfi)[pdfi->size()-1] < 1e-35)
992  (*pdfi)[pdfi->size()-1] = 1e-5*pdfmax;
993 
994  G4double pli = (*pdfi)[0]*factor;
995  G4double pui = (*pdfi)[pdfi->size()-1]*factor;
996  G4double B_temp = 1.0-1.0/(pli*pui*dxLocal*dxLocal);
997  G4double A_temp = (1.0/(pli*dxLocal))-1.0-B_temp;
998  G4double C_temp = 1.0+A_temp+B_temp;
999  if (C_temp < 1e-35)
1000  {
1001  (*a)[i]= 0.;
1002  (*b)[i] = 0.;
1003  (*c)[i] = 1;
1004  }
1005  else
1006  {
1007  (*a)[i]= A_temp;
1008  (*b)[i] = B_temp;
1009  (*c)[i] = C_temp;
1010  }
1011  //OK, now get ERR(I), the integral of the absolute difference between the rational interpolation
1012  //and the true pdf, extended over the interval (X(I),X(I+1))
1013  G4int icase = 1; //loop code
1014  G4bool reLoop = false;
1015  do
1016  {
1017  reLoop = false;
1018  (*err)[i] = 0.; //zero variable
1019  for (G4int k=0;k<nip;k++)
1020  {
1021  G4double rr = (*sumi)[k];
1022  G4double pap = (*area)[i]*(1.0+((*a)[i]+(*b)[i]*rr)*rr)*(1.0+((*a)[i]+(*b)[i]*rr)*rr)/
1023  ((1.0-(*b)[i]*rr*rr)*(*c)[i]*((*x)[i+1]-(*x)[i]));
1024  if (k == 0 || k == nip-1)
1025  (*err)[i] += 0.5*std::fabs(pap-(*pdfi)[k]);
1026  else
1027  (*err)[i] += std::fabs(pap-(*pdfi)[k]);
1028  }
1029  (*err)[i] *= dxi;
1030 
1031  //If err(I) is too large, the pdf is approximated by a uniform distribution
1032  if ((*err)[i] > 0.1*(*area)[i] && icase == 1)
1033  {
1034  (*b)[i] = 0;
1035  (*a)[i] = 0;
1036  (*c)[i] = 1.;
1037  icase = 2;
1038  reLoop = true;
1039  }
1040  }while(reLoop);
1041  delete pdfi;
1042  delete pdfih;
1043  delete sumi;
1044  }
1045  }while(x->size() < np);
1046 
1047  if (x->size() != np || a->size() != np ||
1048  err->size() != np || area->size() != np)
1049  {
1050  G4Exception("G4PenelopeRayleighModel::InitializeSamplingAlgorithm()",
1051  "em2050",FatalException,
1052  "Problem in building the extended Table for Sampling: array dimensions do not match ");
1053  }
1054 
1055  /*******************************************************************************
1056  Renormalization
1057  ********************************************************************************/
1058  G4double ws = 0;
1059  for (size_t i=0;i<np-1;i++)
1060  ws += (*area)[i];
1061  ws = 1.0/ws;
1062  G4double errMax = 0;
1063  for (size_t i=0;i<np-1;i++)
1064  {
1065  (*area)[i] *= ws;
1066  (*err)[i] *= ws;
1067  errMax = std::max(errMax,(*err)[i]);
1068  }
1069 
1070  //Vector with the normalized cumulative distribution
1071  G4DataVector* PAC = new G4DataVector();
1072  PAC->push_back(0.);
1073  for (size_t i=0;i<np-1;i++)
1074  {
1075  G4double previous = (*PAC)[i];
1076  PAC->push_back(previous+(*area)[i]);
1077  }
1078  (*PAC)[PAC->size()-1] = 1.;
1079 
1080  /*******************************************************************************
1081  Pre-calculated limits for the initial binary search for subsequent sampling
1082  ********************************************************************************/
1083 
1084  //G4DataVector* ITTL = new G4DataVector();
1085  std::vector<size_t> *ITTL = new std::vector<size_t>;
1086  std::vector<size_t> *ITTU = new std::vector<size_t>;
1087 
1088  //Just create place-holders
1089  for (size_t i=0;i<np;i++)
1090  {
1091  ITTL->push_back(0);
1092  ITTU->push_back(0);
1093  }
1094 
1095  G4double bin = 1.0/(np-1);
1096  (*ITTL)[0]=0;
1097  for (size_t i=1;i<(np-1);i++)
1098  {
1099  G4double ptst = i*bin;
1100  G4bool found = false;
1101  for (size_t j=(*ITTL)[i-1];j<np && !found;j++)
1102  {
1103  if ((*PAC)[j] > ptst)
1104  {
1105  (*ITTL)[i] = j-1;
1106  (*ITTU)[i-1] = j;
1107  found = true;
1108  }
1109  }
1110  }
1111  (*ITTU)[ITTU->size()-2] = ITTU->size()-1;
1112  (*ITTU)[ITTU->size()-1] = ITTU->size()-1;
1113  (*ITTL)[ITTL->size()-1] = ITTU->size()-2;
1114 
1115  if (ITTU->size() != np || ITTU->size() != np)
1116  {
1117  G4Exception("G4PenelopeRayleighModel::InitializeSamplingAlgorithm()",
1118  "em2051",FatalException,
1119  "Problem in building the Limit Tables for Sampling: array dimensions do not match");
1120  }
1121 
1122 
1123  /********************************************************************************
1124  Copy tables
1125  ********************************************************************************/
1126  G4PenelopeSamplingData* theTable = new G4PenelopeSamplingData(np);
1127  for (size_t i=0;i<np;i++)
1128  {
1129  theTable->AddPoint((*x)[i],(*PAC)[i],(*a)[i],(*b)[i],(*ITTL)[i],(*ITTU)[i]);
1130  }
1131 
1132  if (verboseLevel > 2)
1133  {
1134  G4cout << "*************************************************************************" <<
1135  G4endl;
1136  G4cout << "Sampling table for Penelope Rayleigh scattering in " << mat->GetName() << G4endl;
1137  theTable->DumpTable();
1138  }
1139  samplingTable->insert(std::make_pair(mat,theTable));
1140 
1141 
1142  //Clean up temporary vectors
1143  delete x;
1144  delete a;
1145  delete b;
1146  delete c;
1147  delete err;
1148  delete area;
1149  delete PAC;
1150  delete ITTL;
1151  delete ITTU;
1152 
1153  //DONE!
1154  return;
1155 
1156 }
1157 
1158 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1159 
1160 void G4PenelopeRayleighModel::GetPMaxTable(const G4Material* mat)
1161 {
1162  if (!IsMaster())
1163  //Should not be here!
1164  G4Exception("G4PenelopeRayleighModel::GetPMaxTable()",
1165  "em0100",FatalException,"Worker thread in this method");
1166 
1167  if (!pMaxTable)
1168  {
1169  G4cout << "G4PenelopeRayleighModel::BuildPMaxTable" << G4endl;
1170  G4cout << "Going to instanziate the pMaxTable !" << G4endl;
1171  G4cout << "That should _not_ be here! " << G4endl;
1172  pMaxTable = new std::map<const G4Material*,G4PhysicsFreeVector*>;
1173  }
1174  //check if the table is already there
1175  if (pMaxTable->count(mat))
1176  return;
1177 
1178  //otherwise build it
1179  if (!samplingTable)
1180  {
1181  G4Exception("G4PenelopeRayleighModel::GetPMaxTable()",
1182  "em2052",FatalException,
1183  "SamplingTable is not properly instantiated");
1184  return;
1185  }
1186 
1187  if (!samplingTable->count(mat))
1188  InitializeSamplingAlgorithm(mat);
1189 
1190  G4PenelopeSamplingData *theTable = samplingTable->find(mat)->second;
1191  size_t tablePoints = theTable->GetNumberOfStoredPoints();
1192 
1193  size_t nOfEnergyPoints = logEnergyGridPMax.size();
1194  G4PhysicsFreeVector* theVec = new G4PhysicsFreeVector(nOfEnergyPoints);
1195 
1196  const size_t nip = 51; //hard-coded in Penelope
1197 
1198  for (size_t ie=0;ie<logEnergyGridPMax.size();ie++)
1199  {
1200  G4double energy = std::exp(logEnergyGridPMax[ie]);
1201  G4double Qm = 2.0*energy/electron_mass_c2; //this is non-dimensional now
1202  G4double Qm2 = Qm*Qm;
1203  G4double firstQ2 = theTable->GetX(0);
1204  G4double lastQ2 = theTable->GetX(tablePoints-1);
1205  G4double thePMax = 0;
1206 
1207  if (Qm2 > firstQ2)
1208  {
1209  if (Qm2 < lastQ2)
1210  {
1211  //bisection to look for the index of Qm
1212  size_t lowerBound = 0;
1213  size_t upperBound = tablePoints-1;
1214  while (lowerBound <= upperBound)
1215  {
1216  size_t midBin = (lowerBound + upperBound)/2;
1217  if( Qm2 < theTable->GetX(midBin))
1218  { upperBound = midBin-1; }
1219  else
1220  { lowerBound = midBin+1; }
1221  }
1222  //upperBound is the output (but also lowerBounf --> should be the same!)
1223  G4double Q1 = theTable->GetX(upperBound);
1224  G4double Q2 = Qm2;
1225  G4double DQ = (Q2-Q1)/((G4double)(nip-1));
1226  G4double theA = theTable->GetA(upperBound);
1227  G4double theB = theTable->GetB(upperBound);
1228  G4double thePAC = theTable->GetPAC(upperBound);
1229  G4DataVector* fun = new G4DataVector();
1230  for (size_t k=0;k<nip;k++)
1231  {
1232  G4double qi = Q1 + k*DQ;
1233  G4double tau = (qi-Q1)/
1234  (theTable->GetX(upperBound+1)-Q1);
1235  G4double con1 = 2.0*theB*tau;
1236  G4double ci = 1.0+theA+theB;
1237  G4double con2 = ci-theA*tau;
1238  G4double etap = 0;
1239  if (std::fabs(con1) > 1.0e-16*std::fabs(con2))
1240  etap = con2*(1.0-std::sqrt(1.0-2.0*tau*con1/(con2*con2)))/con1;
1241  else
1242  etap = tau/con2;
1243  G4double theFun = (theTable->GetPAC(upperBound+1)-thePAC)*
1244  (1.0+(theA+theB*etap)*etap)*(1.0+(theA+theB*etap)*etap)/
1245  ((1.0-theB*etap*etap)*ci*(theTable->GetX(upperBound+1)-Q1));
1246  fun->push_back(theFun);
1247  }
1248  //Now intergrate numerically the fun Cavalieri-Simpson's method
1249  G4DataVector* sum = new G4DataVector;
1250  G4double CONS = DQ*(1./12.);
1251  G4double HCONS = 0.5*CONS;
1252  sum->push_back(0.);
1253  G4double secondPoint = (*sum)[0] +
1254  (5.0*(*fun)[0]+8.0*(*fun)[1]-(*fun)[2])*CONS;
1255  sum->push_back(secondPoint);
1256  for (size_t hh=2;hh<nip-1;hh++)
1257  {
1258  G4double previous = (*sum)[hh-1];
1259  G4double next = previous+(13.0*((*fun)[hh-1]+(*fun)[hh])-
1260  (*fun)[hh+1]-(*fun)[hh-2])*HCONS;
1261  sum->push_back(next);
1262  }
1263  G4double last = (*sum)[nip-2]+(5.0*(*fun)[nip-1]+8.0*(*fun)[nip-2]-
1264  (*fun)[nip-3])*CONS;
1265  sum->push_back(last);
1266  thePMax = thePAC + (*sum)[sum->size()-1]; //last point
1267  delete fun;
1268  delete sum;
1269  }
1270  else
1271  {
1272  thePMax = 1.0;
1273  }
1274  }
1275  else
1276  {
1277  thePMax = theTable->GetPAC(0);
1278  }
1279 
1280  //Write number in the table
1281  theVec->PutValue(ie,energy,thePMax);
1282  }
1283 
1284  pMaxTable->insert(std::make_pair(mat,theVec));
1285  return;
1286 
1287 }
1288 
1289 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1290 
1292 {
1293  G4cout << "*****************************************************************" << G4endl;
1294  G4cout << "G4PenelopeRayleighModel: Form Factor Table for " << mat->GetName() << G4endl;
1295  //try to use the same format as Penelope-Fortran, namely Q (/m_e*c) and F
1296  G4cout << "Q/(m_e*c) F(Q) " << G4endl;
1297  G4cout << "*****************************************************************" << G4endl;
1298  if (!logFormFactorTable->count(mat))
1299  BuildFormFactorTable(mat);
1300 
1301  G4PhysicsFreeVector* theVec = logFormFactorTable->find(mat)->second;
1302  for (size_t i=0;i<theVec->GetVectorLength();i++)
1303  {
1304  G4double logQ2 = theVec->GetLowEdgeEnergy(i);
1305  G4double Q = std::exp(0.5*logQ2);
1306  G4double logF2 = (*theVec)[i];
1307  G4double F = std::exp(0.5*logF2);
1308  G4cout << Q << " " << F << G4endl;
1309  }
1310  //DONE
1311  return;
1312 }
1313 
1314 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...
1315 
1316 void G4PenelopeRayleighModel::SetParticle(const G4ParticleDefinition* p)
1317 {
1318  if(!fParticle) {
1319  fParticle = p;
1320  }
1321 }
tuple app
Definition: testem0.py:189
hh[ixs]
Definition: PlotSingle.C:6
G4double LowEnergyLimit() const
Definition: G4VEmModel.hh:599
std::vector< G4Element * > G4ElementVector
void PutValue(size_t binNumber, G4double binValue, G4double dataValue)
tuple a
Definition: test.py:11
std::ostringstream G4ExceptionDescription
Definition: globals.hh:76
G4double GetKineticEnergy() const
G4double HighEnergyLimit() const
Definition: G4VEmModel.hh:592
TFile ff[ntarg]
Definition: Style.C:26
virtual void Initialise(const G4ParticleDefinition *, const G4DataVector &)
G4double GetB(size_t index)
const char * p
Definition: xmltok.h:285
const G4String & GetName() const
Definition: G4Material.hh:176
virtual void InitialiseLocal(const G4ParticleDefinition *, G4VEmModel *masterModel)
float bin[41]
Definition: plottest35.C:14
Double_t xx
Definition: macro.C:10
G4bool IsMaster() const
Definition: G4VEmModel.hh:676
G4double GetPAC(size_t index)
tuple x
Definition: test.py:50
size_t GetVectorLength() const
G4double GetLowEdgeEnergy(size_t binNumber) const
TFile * file
const G4ElementVector * GetElementVector() const
Definition: G4Material.hh:188
int G4int
Definition: G4Types.hh:78
void ProposeMomentumDirection(G4double Px, G4double Py, G4double Pz)
#define G4MUTEX_INITIALIZER
Definition: G4Threading.hh:158
TFile f
Definition: plotHisto.C:6
void ProposeLocalEnergyDeposit(G4double anEnergyPart)
void SetSpline(G4bool)
void SetHighEnergyLimit(G4double)
Definition: G4VEmModel.hh:683
Float_t mat
Definition: plot.C:40
string material
Definition: eplot.py:19
function g(Y1, Y2, PT2)
Definition: hijing1.383.f:5205
tuple b
Definition: test.py:12
Float_t f1
#define G4UniformRand()
Definition: Randomize.hh:87
G4GLOB_DLL std::ostream G4cout
double energy
Definition: plottest35.C:25
Float_t f2
Float_t Z
Definition: plot.C:39
bool G4bool
Definition: G4Types.hh:79
const G4ThreeVector & GetMomentumDirection() const
Hep3Vector & rotateUz(const Hep3Vector &)
Definition: ThreeVector.cc:72
TString part[npart]
Definition: Style.C:32
void DumpFormFactorTable(const G4Material *)
float electron_mass_c2
Definition: hepunit.py:274
G4double Value(G4double theEnergy, size_t &lastidx) const
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41
static G4ProductionCutsTable * GetProductionCutsTable()
G4int G4Mutex
Definition: G4Threading.hh:156
G4double SampleValue(G4double rndm)
const G4MaterialCutsCouple * GetMaterialCutsCouple(G4int i) const
T max(const T t1, const T t2)
brief Return the largest of the two arguments
G4double GetA(size_t index)
T min(const T t1, const T t2)
brief Return the smallest of the two arguments
G4double GetX(size_t index)
G4ParticleChangeForGamma * fParticleChange
void SetProposedKineticEnergy(G4double proposedKinEnergy)
#define G4endl
Definition: G4ios.hh:61
virtual void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy)
size_t GetNumberOfElements() const
Definition: G4Material.hh:184
double G4double
Definition: G4Types.hh:76
void ProposeTrackStatus(G4TrackStatus status)
tuple c
Definition: test.py:13
G4PenelopeRayleighModel(const G4ParticleDefinition *p=0, const G4String &processName="PenRayleigh")
void AddPoint(G4double x0, G4double pac0, G4double a0, G4double b0, size_t ITTL0, size_t ITTU0)
const G4double * GetFractionVector() const
Definition: G4Material.hh:192
virtual G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double kinEnergy, G4double Z, G4double A=0, G4double cut=0, G4double emax=DBL_MAX)
const G4ParticleDefinition * fParticle
G4ParticleChangeForGamma * GetParticleChangeForGamma()
Definition: G4VEmModel.cc:121
const G4Material * GetMaterial() const