Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4PenelopeRayleighModelMI.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// Author: Luciano Pandola and Gianfranco Paterno
27//
28// -------------------------------------------------------------------
29// History:
30// 03 Dec 2009 L. Pandola 1st implementation
31// 25 May 2011 L. Pandola Renamed (make v2008 as default Penelope)
32// 27 Sep 2013 L. Pandola Migration to MT paradigm
33// 20 Aug 2017 G. Paterno Molecular Interference implementation
34// 24 Mar 2019 G. Paterno Improved Molecular Interference implementation
35// 20 Jun 2020 G. Paterno Read qext separately and leave original atomic form factors
36// 27 Aug 2020 G. Paterno Further improvement of MI implementation
37//
38// -------------------------------------------------------------------
39// Class description:
40// Low Energy Electromagnetic Physics, Rayleigh Scattering
41// with the model from Penelope, version 2008
42// -------------------------------------------------------------------
43//
44//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
45
47
52#include "G4DynamicParticle.hh"
53#include "G4ElementTable.hh"
54#include "G4Element.hh"
56#include "G4AutoLock.hh"
57#include "G4Exp.hh"
58#include "G4ExtendedMaterial.hh"
59#include "G4CrystalExtension.hh"
60#include "G4EmParameters.hh"
61
63#include "G4SystemOfUnits.hh"
64//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
65
66const G4int G4PenelopeRayleighModelMI::fMaxZ;
67G4PhysicsFreeVector* G4PenelopeRayleighModelMI::fLogAtomicCrossSection[] = {nullptr};
68G4PhysicsFreeVector* G4PenelopeRayleighModelMI::fAtomicFormFactor[] = {nullptr};
69
70//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
71
73 const G4String& nam) :
74 G4VEmModel(nam),
75 fParticleChange(nullptr),fParticle(nullptr),fLogFormFactorTable(nullptr),fPMaxTable(nullptr),
76 fSamplingTable(nullptr),fMolInterferenceData(nullptr),fAngularFunction(nullptr), fKnownMaterials(nullptr),
77 fIsInitialised(false),fLocalTable(false),fIsMIActive(true)
78{
79 fIntrinsicLowEnergyLimit = 100.0*eV;
80 fIntrinsicHighEnergyLimit = 100.0*GeV;
81 //SetLowEnergyLimit(fIntrinsicLowEnergyLimit);
82 SetHighEnergyLimit(fIntrinsicHighEnergyLimit);
83
84 if (part) SetParticle(part);
85
86 fVerboseLevel = 0;
87 // Verbosity scale:
88 // 0 = nothing
89 // 1 = warning for energy non-conservation
90 // 2 = details of energy budget
91 // 3 = calculation of FF and CS, file openings, sampling of atoms
92 // 4 = entering in methods
93
94 //build the energy grid. It is the same for all materials
95 G4double logenergy = G4Log(fIntrinsicLowEnergyLimit/2.);
96 G4double logmaxenergy = G4Log(1.5*fIntrinsicHighEnergyLimit);
97 //finer grid below 160 keV
98 G4double logtransitionenergy = G4Log(160*keV);
99 G4double logfactor1 = G4Log(10.)/250.;
100 G4double logfactor2 = logfactor1*10;
101 fLogEnergyGridPMax.push_back(logenergy);
102 do {
103 if (logenergy < logtransitionenergy)
104 logenergy += logfactor1;
105 else
106 logenergy += logfactor2;
107 fLogEnergyGridPMax.push_back(logenergy);
108 } while (logenergy < logmaxenergy);
109}
110
111//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
112
114{
115 if (IsMaster() || fLocalTable) {
116
117 for(G4int i=0; i<=fMaxZ; ++i)
118 {
119 if(fLogAtomicCrossSection[i])
120 {
121 delete fLogAtomicCrossSection[i];
122 fLogAtomicCrossSection[i] = nullptr;
123 }
124 if(fAtomicFormFactor[i])
125 {
126 delete fAtomicFormFactor[i];
127 fAtomicFormFactor[i] = nullptr;
128 }
129 }
130 if (fMolInterferenceData) {
131 for (auto& item : (*fMolInterferenceData))
132 if (item.second) delete item.second;
133 delete fMolInterferenceData;
134 fMolInterferenceData = nullptr;
135 }
136 if (fKnownMaterials)
137 {
138 delete fKnownMaterials;
139 fKnownMaterials = nullptr;
140 }
141 if (fAngularFunction)
142 {
143 delete fAngularFunction;
144 fAngularFunction = nullptr;
145 }
146 ClearTables();
147 }
148}
149
150//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
151
152void G4PenelopeRayleighModelMI::ClearTables()
153{
154 if (fLogFormFactorTable) {
155 for (auto& item : (*fLogFormFactorTable))
156 if (item.second) delete item.second;
157 delete fLogFormFactorTable;
158 fLogFormFactorTable = nullptr; //zero explicitly
159 }
160
161 if (fPMaxTable) {
162 for (auto& item : (*fPMaxTable))
163 if (item.second) delete item.second;
164 delete fPMaxTable;
165 fPMaxTable = nullptr; //zero explicitly
166 }
167
168 if (fSamplingTable) {
169 for (auto& item : (*fSamplingTable))
170 if (item.second) delete item.second;
171 delete fSamplingTable;
172 fSamplingTable = nullptr; //zero explicitly
173 }
174
175 return;
176}
177
178//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
179
181 const G4DataVector& )
182{
183 if (fVerboseLevel > 3)
184 G4cout << "Calling G4PenelopeRayleighModelMI::Initialise()" << G4endl;
185
186 SetParticle(part);
187
188 if (fVerboseLevel)
189 G4cout << "# Molecular Interference is " << (fIsMIActive ? "ON" : "OFF") << " #" << G4endl;
190
191 //Only the master model creates/fills/destroys the tables
192 if (IsMaster() && part == fParticle) {
193 //clear tables depending on materials, not the atomic ones
194 ClearTables();
195
196 //Use here the highest verbosity, from G4EmParameter or local
197 G4int globVerb = G4EmParameters::Instance()->Verbose();
198 if (globVerb > fVerboseLevel)
199 {
200 fVerboseLevel = globVerb;
201 if (fVerboseLevel)
202 G4cout << "Verbosity level of G4PenelopeRayleighModelMI set to " << fVerboseLevel <<
203 " from G4EmParameters()" << G4endl;
204 }
205 if (fVerboseLevel > 3)
206 G4cout << "Calling G4PenelopeRayleighModelMI::Initialise() [master]" << G4endl;
207
208 //Load the list of known materials and the DCS integration grid
209 if (fIsMIActive)
210 {
211 if (!fKnownMaterials)
212 fKnownMaterials = new std::map<G4String,G4String>;
213 if (!fKnownMaterials->size())
214 LoadKnownMIFFMaterials();
215 if (!fAngularFunction)
216 {
217 //Create and fill once
218 fAngularFunction = new G4PhysicsFreeVector(fNtheta);
219 CalculateThetaAndAngFun(); //angular funtion for DCS integration
220 }
221 }
222 if (fIsMIActive && !fMolInterferenceData)
223 fMolInterferenceData = new std::map<G4String,G4PhysicsFreeVector*>;
224 if (!fLogFormFactorTable)
225 fLogFormFactorTable = new std::map<const G4Material*,G4PhysicsFreeVector*>;
226 if (!fPMaxTable)
227 fPMaxTable = new std::map<const G4Material*,G4PhysicsFreeVector*>;
228 if (!fSamplingTable)
229 fSamplingTable = new std::map<const G4Material*,G4PenelopeSamplingData*>;
230
231 //loop on the used materials
233
234 for (G4int i=0;i<(G4int)theCoupleTable->GetTableSize();++i) {
235 const G4Material* material =
236 theCoupleTable->GetMaterialCutsCouple(i)->GetMaterial();
237 const G4ElementVector* theElementVector = material->GetElementVector();
238
239 for (std::size_t j=0;j<material->GetNumberOfElements();++j) {
240 G4int iZ = theElementVector->at(j)->GetZasInt();
241 //read data files only in the master
242 if (!fLogAtomicCrossSection[iZ])
243 ReadDataFile(iZ);
244 }
245
246 //1) Read MI form factors
247 if (fIsMIActive && !fMolInterferenceData->count(material->GetName()))
248 ReadMolInterferenceData(material->GetName());
249
250 //2) If the table has not been built for the material, do it!
251 if (!fLogFormFactorTable->count(material))
252 BuildFormFactorTable(material);
253
254 //3) retrieve or build the sampling table
255 if (!(fSamplingTable->count(material)))
256 InitializeSamplingAlgorithm(material);
257
258 //4) retrieve or build the pMax data
259 if (!fPMaxTable->count(material))
260 GetPMaxTable(material);
261 }
262
263 if (fVerboseLevel > 1) {
264 G4cout << G4endl << "Penelope Rayleigh model v2008 is initialized" << G4endl
265 << "Energy range: "
266 << LowEnergyLimit() / keV << " keV - "
267 << HighEnergyLimit() / GeV << " GeV"
268 << G4endl;
269 }
270 }
271
272 if (fIsInitialised)
273 return;
274 fParticleChange = GetParticleChangeForGamma();
275 fIsInitialised = true;
276}
277
278//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
279
281 G4VEmModel *masterModel)
282{
283 if (fVerboseLevel > 3)
284 G4cout << "Calling G4PenelopeRayleighModelMI::InitialiseLocal()" << G4endl;
285
286 //Check that particle matches: one might have multiple master models
287 //(e.g. for e+ and e-)
288 if (part == fParticle) {
289
290 //Get the const table pointers from the master to the workers
291 const G4PenelopeRayleighModelMI* theModel =
292 static_cast<G4PenelopeRayleighModelMI*> (masterModel);
293
294 //Copy pointers to the data tables
295 for(G4int i=0; i<=fMaxZ; ++i)
296 {
297 fLogAtomicCrossSection[i] = theModel->fLogAtomicCrossSection[i];
298 fAtomicFormFactor[i] = theModel->fAtomicFormFactor[i];
299 }
300 fMolInterferenceData = theModel->fMolInterferenceData;
301 fLogFormFactorTable = theModel->fLogFormFactorTable;
302 fPMaxTable = theModel->fPMaxTable;
303 fSamplingTable = theModel->fSamplingTable;
304 fKnownMaterials = theModel->fKnownMaterials;
305 fAngularFunction = theModel->fAngularFunction;
306
307 //Copy the G4DataVector with the grid
308 fLogQSquareGrid = theModel->fLogQSquareGrid;
309
310 //Same verbosity for all workers, as the master
311 fVerboseLevel = theModel->fVerboseLevel;
312 }
313 return;
314}
315
316//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
317
318namespace {G4Mutex PenelopeRayleighModelMutex = G4MUTEX_INITIALIZER;}
320 G4double energy,
321 G4double Z,
322 G4double,
323 G4double,
324 G4double)
325{
326 //Cross section of Rayleigh scattering in Penelope v2008 is calculated by the EPDL97
327 //tabulation, Cuellen et al. (1997), with non-relativistic form factors from Hubbel
328 //et al. J. Phys. Chem. Ref. Data 4 (1975) 471; Erratum ibid. 6 (1977) 615.
329
330 if (fVerboseLevel > 3)
331 G4cout << "Calling CrossSectionPerAtom() of G4PenelopeRayleighModelMI" << G4endl;
332
333 G4int iZ = G4int(Z);
334 if (!fLogAtomicCrossSection[iZ]) {
335 //If we are here, it means that Initialize() was inkoved, but the MaterialTable was
336 //not filled up. This can happen in a UnitTest or via G4EmCalculator
337 if (fVerboseLevel > 0) {
338 //Issue a G4Exception (warning) only in verbose mode
340 ed << "Unable to retrieve the cross section table for Z=" << iZ << G4endl;
341 ed << "This can happen only in Unit Tests or via G4EmCalculator" << G4endl;
342 G4Exception("G4PenelopeRayleighModelMI::ComputeCrossSectionPerAtom()",
343 "em2040",JustWarning,ed);
344 }
345
346 //protect file reading via autolock
347 G4AutoLock lock(&PenelopeRayleighModelMutex);
348 ReadDataFile(iZ);
349 lock.unlock();
350 }
351
352 G4double cross = 0;
353 G4PhysicsFreeVector* atom = fLogAtomicCrossSection[iZ];
354 if (!atom) {
356 ed << "Unable to find Z=" << iZ << " in the atomic cross section table" << G4endl;
357 G4Exception("G4PenelopeRayleighModelMI::ComputeCrossSectionPerAtom()",
358 "em2041",FatalException,ed);
359 return 0;
360 }
361
362 G4double logene = G4Log(energy);
363 G4double logXS = atom->Value(logene);
364 cross = G4Exp(logXS);
365
366 if (fVerboseLevel > 2) {
367 G4cout << "Rayleigh cross section at " << energy/keV << " keV for Z="
368 << Z << " = " << cross/barn << " barn" << G4endl;
369 }
370 return cross;
371}
372
373//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
374
375void G4PenelopeRayleighModelMI::CalculateThetaAndAngFun()
376{
377 G4double theta = 0;
378 for(G4int k=0; k<fNtheta; k++) {
379 theta += fDTheta;
380 G4double value = (1+std::cos(theta)*std::cos(theta))*std::sin(theta);
381 fAngularFunction->PutValue(k,theta,value);
382 if (fVerboseLevel > 3)
383 G4cout << "theta[" << k << "]: " << fAngularFunction->Energy(k)
384 << ", angFun[" << k << "]: " << (*fAngularFunction)[k] << G4endl;
385 }
386}
387
388//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
389
390G4double G4PenelopeRayleighModelMI::CalculateQSquared(G4double angle, G4double energy)
391{
392 G4double lambda,x,q,q2 = 0;
393
394 lambda = hbarc*twopi/energy;
395 x = 1./lambda*std::sin(angle/2.);
396 q = 2.*h_Planck*x/(electron_mass_c2/c_light);
397
398 if (fVerboseLevel > 3) {
399 G4cout << "E: " << energy/keV << " keV, lambda: " << lambda/nm << " nm"
400 << ", x: " << x*nm << ", q: " << q << G4endl;
401 }
402 q2 = std::pow(q,2);
403 return q2;
404}
405
406//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
407
408//Overriding of parent's (G4VEmModel) method
410 const G4ParticleDefinition* p,
411 G4double energy,
412 G4double,
413 G4double)
414{
415 //check if we are in a Unit Test (only for the first time)
416 static G4bool amInAUnitTest = false;
417 if (G4ProductionCutsTable::GetProductionCutsTable()->GetTableSize() == 0 && !amInAUnitTest)
418 {
419 amInAUnitTest = true;
421 ed << "The ProductionCuts table is empty " << G4endl;
422 ed << "This should happen only in Unit Tests" << G4endl;
423 G4Exception("G4PenelopeRayleighModelMI::CrossSectionPerVolume()",
424 "em2019",JustWarning,ed);
425 }
426 //If the material does not have a MIFF, continue with the old-style calculation
427 G4String matname = material->GetName();
428 if (amInAUnitTest)
429 {
430 //No need to lock, as this is always called in a master
431 const G4ElementVector* theElementVector = material->GetElementVector();
432 //protect file reading via autolock
433 for (std::size_t j=0;j<material->GetNumberOfElements();++j) {
434 G4int iZ = theElementVector->at(j)->GetZasInt();
435 if (!fLogAtomicCrossSection[iZ]) {
436 ReadDataFile(iZ);
437 }
438 }
439 if (fIsMIActive)
440 ReadMolInterferenceData(matname);
441 if (!fLogFormFactorTable->count(material))
442 BuildFormFactorTable(material);
443 if (!(fSamplingTable->count(material)))
444 InitializeSamplingAlgorithm(material);
445 if (!fPMaxTable->count(material))
446 GetPMaxTable(material);
447 }
448 G4bool useMIFF = fIsMIActive && (fMolInterferenceData->count(matname) || matname.find("MedMat") != std::string::npos);
449 if (!useMIFF)
450 {
451 if (fVerboseLevel > 2)
452 G4cout << "Rayleigh CS of: " << matname << " calculated through CSperAtom!" << G4endl;
453 return G4VEmModel::CrossSectionPerVolume(material,p,energy);
454 }
455
456 // If we are here, it means that we have to integrate the cross section
457 if (fVerboseLevel > 2)
458 G4cout << "Rayleigh CS of: " << matname
459 << " calculated through integration of the DCS" << G4endl;
460
461 G4double cs = 0;
462
463 //force null cross-section if below the low-energy edge of the table
464 if (energy < LowEnergyLimit())
465 return cs;
466
467 //if the material is a CRYSTAL, forbid this process
468 if (material->IsExtended() && material->GetName() != "CustomMat") {
469 G4ExtendedMaterial* extendedmaterial = (G4ExtendedMaterial*)material;
470 G4CrystalExtension* crystalExtension = (G4CrystalExtension*)extendedmaterial->RetrieveExtension("crystal");
471 if (crystalExtension != 0) {
472 G4cout << "The material has a crystalline structure, a dedicated diffraction model is used!" << G4endl;
473 return 0;
474 }
475 }
476
477 //GET MATERIAL INFORMATION
478 G4double atomDensity = material->GetTotNbOfAtomsPerVolume();
479 std::size_t nElements = material->GetNumberOfElements();
480 const G4ElementVector* elementVector = material->GetElementVector();
481 const G4double* fractionVector = material->GetFractionVector();
482
483 //Stoichiometric factors
484 std::vector<G4double> *StoichiometricFactors = new std::vector<G4double>;
485 for (std::size_t i=0;i<nElements;++i) {
486 G4double fraction = fractionVector[i];
487 G4double atomicWeigth = (*elementVector)[i]->GetA()/(g/mole);
488 StoichiometricFactors->push_back(fraction/atomicWeigth);
489 }
490 G4double MaxStoichiometricFactor = 0.;
491 for (std::size_t i=0;i<nElements;++i) {
492 if ((*StoichiometricFactors)[i] > MaxStoichiometricFactor)
493 MaxStoichiometricFactor = (*StoichiometricFactors)[i];
494 }
495 for (std::size_t i=0;i<nElements;++i) {
496 (*StoichiometricFactors)[i] /= MaxStoichiometricFactor;
497 }
498
499 //Equivalent atoms per molecule
500 G4double atPerMol = 0;
501 for (std::size_t i=0;i<nElements;++i)
502 atPerMol += (*StoichiometricFactors)[i];
503 G4double moleculeDensity = 0.;
504 if (atPerMol) moleculeDensity = atomDensity/atPerMol;
505
506 if (fVerboseLevel > 2)
507 G4cout << "Material " << material->GetName() << " has " << atPerMol << " atoms "
508 << "per molecule and " << moleculeDensity/(cm*cm*cm) << " molecule/cm3" << G4endl;
509
510 //Equivalent molecular weight (dimensionless)
511 G4double MolWeight = 0.;
512 for (std::size_t i=0;i<nElements;++i)
513 MolWeight += (*StoichiometricFactors)[i]*(*elementVector)[i]->GetA()/(g/mole);
514
515 if (fVerboseLevel > 2)
516 G4cout << "Molecular weight of " << matname << ": " << MolWeight << " g/mol" << G4endl;
517
518 G4double IntegrandFun[fNtheta];
519 for (G4int k=0; k<fNtheta; k++) {
520 G4double theta = fAngularFunction->Energy(k); //the x-value is called "Energy", but is an angle
521 G4double F2 = GetFSquared(material,CalculateQSquared(theta,energy));
522 IntegrandFun[k] = (*fAngularFunction)[k]*F2;
523 }
524
525 G4double constant = pi*classic_electr_radius*classic_electr_radius;
526 cs = constant*IntegrateFun(IntegrandFun,fNtheta,fDTheta);
527
528 //Now cs is the cross section per molecule, let's calculate the cross section per volume
529 G4double csvolume = cs*moleculeDensity;
530
531 //print CS and mfp
532 if (fVerboseLevel > 2)
533 G4cout << "Rayleigh CS of " << matname << " at " << energy/keV
534 << " keV: " << cs/barn << " barn"
535 << ", mean free path: " << 1./csvolume/mm << " mm" << G4endl;
536
537 delete StoichiometricFactors;
538 //return CS
539 return csvolume;
540}
541
542//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
543
544void G4PenelopeRayleighModelMI::BuildFormFactorTable(const G4Material* material)
545{
546 if (fVerboseLevel > 3)
547 G4cout << "Calling BuildFormFactorTable() of G4PenelopeRayleighModelMI" << G4endl;
548
549 //GET MATERIAL INFORMATION
550 std::size_t nElements = material->GetNumberOfElements();
551 const G4ElementVector* elementVector = material->GetElementVector();
552 const G4double* fractionVector = material->GetFractionVector();
553
554 //Stoichiometric factors
555 std::vector<G4double> *StoichiometricFactors = new std::vector<G4double>;
556 for (std::size_t i=0;i<nElements;++i) {
557 G4double fraction = fractionVector[i];
558 G4double atomicWeigth = (*elementVector)[i]->GetA()/(g/mole);
559 StoichiometricFactors->push_back(fraction/atomicWeigth);
560 }
561 G4double MaxStoichiometricFactor = 0.;
562 for (std::size_t i=0;i<nElements;++i) {
563 if ((*StoichiometricFactors)[i] > MaxStoichiometricFactor)
564 MaxStoichiometricFactor = (*StoichiometricFactors)[i];
565 }
566 if (MaxStoichiometricFactor<1e-16) {
568 ed << "Inconsistent data of atomic composition for " << material->GetName() << G4endl;
569 G4Exception("G4PenelopeRayleighModelMI::BuildFormFactorTable()",
570 "em2042",FatalException,ed);
571 }
572 for (std::size_t i=0;i<nElements;++i)
573 (*StoichiometricFactors)[i] /= MaxStoichiometricFactor;
574
575 //Equivalent molecular weight (dimensionless)
576 G4double MolWeight = 0.;
577 for (std::size_t i=0;i<nElements;++i)
578 MolWeight += (*StoichiometricFactors)[i]*(*elementVector)[i]->GetA()/(g/mole);
579
580 //CREATE THE FORM FACTOR TABLE
581 //First, the form factors are retrieved [F/sqrt(W)].
582 //Then, they are squared and multiplied for MolWeight -> F2 [dimensionless].
583 //This makes difference for CS calculation, but not for theta sampling.
584 G4PhysicsFreeVector* theFFVec = new G4PhysicsFreeVector(fLogQSquareGrid.size(),
585 /*spline=*/true);
586
587 G4String matname = material->GetName();
588 G4String aFileNameFF = "";
589
590 //retrieve MIdata (fFileNameFF)
591 G4MIData* dataMI = GetMIData(material);
592 if (dataMI)
593 aFileNameFF = dataMI->GetFilenameFF();
594
595 //read the MIFF from a file passed by the user
596 if (fIsMIActive && aFileNameFF != "") {
597 if (fVerboseLevel)
598 G4cout << "Read MIFF for " << matname << " from custom file: " << aFileNameFF << G4endl;
599
600 ReadMolInterferenceData(matname,aFileNameFF);
601 G4PhysicsFreeVector* Fvector = fMolInterferenceData->find(matname)->second;
602
603 for (std::size_t k=0;k<fLogQSquareGrid.size();++k) {
604 G4double q = std::pow(G4Exp(fLogQSquareGrid[k]),0.5);
605 G4double f = Fvector->Value(q);
606 G4double ff2 = f*f*MolWeight;
607 if (ff2)
608 theFFVec->PutValue(k,fLogQSquareGrid[k],G4Log(ff2));
609 }
610 }
611 //retrieve the MIFF from the database or use the IAM
612 else {
613 //medical material: composition of fat, water, bonematrix, mineral
614 if (fIsMIActive && matname.find("MedMat") != std::string::npos) {
615 if (fVerboseLevel)
616 G4cout << "Build MIFF from components for " << matname << G4endl;
617
618 //get the material composition from its name
619 G4int ki, kf=6, ktot=19;
620 G4double comp[4];
621 G4String compstring = matname.substr(kf+1, ktot);
622 for (std::size_t j=0; j<4; ++j) {
623 ki = kf+1;
624 kf = ki+4;
625 compstring = matname.substr(ki, 4);
626 comp[j] = atof(compstring.c_str());
627 if (fVerboseLevel > 2)
628 G4cout << " -- MedMat comp[" << j+1 << "]: " << comp[j] << G4endl;
629 }
630
631 const char* path = G4FindDataDir("G4LEDATA");
632 if (!path) {
633 G4String excep = "G4LEDATA environment variable not set!";
634 G4Exception("G4PenelopeRayleighModelMI::BuildFormFactorTable()",
635 "em0006",FatalException,excep);
636 }
637
638 if (!fMolInterferenceData->count("Fat_MI"))
639 ReadMolInterferenceData("Fat_MI");
640 G4PhysicsFreeVector* fatFF = fMolInterferenceData->find("Fat_MI")->second;
641
642 if (!fMolInterferenceData->count("Water_MI"))
643 ReadMolInterferenceData("Water_MI");
644 G4PhysicsFreeVector* waterFF = fMolInterferenceData->find("Water_MI")->second;
645
646 if (!fMolInterferenceData->count("BoneMatrix_MI"))
647 ReadMolInterferenceData("BoneMatrix_MI");
648 G4PhysicsFreeVector* bonematrixFF = fMolInterferenceData->find("BoneMatrix_MI")->second;
649
650 if (!fMolInterferenceData->count("Mineral_MI"))
651 ReadMolInterferenceData("Mineral_MI");
652 G4PhysicsFreeVector* mineralFF = fMolInterferenceData->find("Mineral_MI")->second;
653
654 //get and combine the molecular form factors with interference effect
655 for (std::size_t k=0;k<fLogQSquareGrid.size();++k) {
656 G4double ff2 = 0;
657 G4double q = std::pow(G4Exp(fLogQSquareGrid[k]),0.5);
658 G4double ffat = fatFF->Value(q);
659 G4double fwater = waterFF->Value(q);
660 G4double fbonematrix = bonematrixFF->Value(q);
661 G4double fmineral = mineralFF->Value(q);
662 ff2 = comp[0]*ffat*ffat+comp[1]*fwater*fwater+
663 comp[2]*fbonematrix*fbonematrix+comp[3]*fmineral*fmineral;
664 ff2 *= MolWeight;
665 if (ff2) theFFVec->PutValue(k,fLogQSquareGrid[k],G4Log(ff2));
666 }
667 }
668 //other materials with MIFF (from the database)
669 else if (fIsMIActive && fMolInterferenceData->count(matname)) {
670 if (fVerboseLevel)
671 G4cout << "Read MIFF from database " << matname << G4endl;
672 G4PhysicsFreeVector* FF = fMolInterferenceData->find(matname)->second;
673 for (std::size_t k=0;k<fLogQSquareGrid.size();++k) {
674 G4double ff2 = 0;
675 G4double q = std::pow(G4Exp(fLogQSquareGrid[k]),0.5);
676 G4double f = FF->Value(q);
677 ff2 = f*f*MolWeight;
678 if (ff2) theFFVec->PutValue(k,fLogQSquareGrid[k],G4Log(ff2));
679 }
680 }
681 //IAM
682 else {
683 if (fVerboseLevel)
684 G4cout << "FF of " << matname << " calculated according to the IAM" << G4endl;
685 for (std::size_t k=0;k<fLogQSquareGrid.size();++k) {
686 G4double ff2 = 0;
687 for (std::size_t i=0;i<nElements;++i) {
688 G4int iZ = (*elementVector)[i]->GetZasInt();
689 G4PhysicsFreeVector* theAtomVec = fAtomicFormFactor[iZ];
690 G4double q = std::pow(G4Exp(fLogQSquareGrid[k]),0.5);
691 G4double f = theAtomVec->Value(q);
692 ff2 += f*f*(*StoichiometricFactors)[i];
693 }
694 if (ff2) theFFVec->PutValue(k,fLogQSquareGrid[k],G4Log(ff2));
695 }
696 }
697 }
698 theFFVec->FillSecondDerivatives();
699 fLogFormFactorTable->insert(std::make_pair(material,theFFVec));
700
701 if (fVerboseLevel > 3)
702 DumpFormFactorTable(material);
703 delete StoichiometricFactors;
704
705 return;
706}
707
708//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
709
710void G4PenelopeRayleighModelMI::SampleSecondaries(std::vector<G4DynamicParticle*>*,
711 const G4MaterialCutsCouple* couple,
712 const G4DynamicParticle* aDynamicGamma,
713 G4double,
714 G4double)
715{
716 // Sampling of the Rayleigh final state (namely, scattering angle of the photon)
717 // from the Penelope2008 model. The scattering angle is sampled from the atomic
718 // cross section dOmega/d(cosTheta) from Born ("Atomic Phyisics", 1969), disregarding
719 // anomalous scattering effects. The Form Factor F(Q) function which appears in the
720 // analytical cross section is retrieved via the method GetFSquared(); atomic data
721 // are tabulated for F(Q). Form factor for compounds is calculated according to
722 // the additivity rule. The sampling from the F(Q) is made via a Rational Inverse
723 // Transform with Aliasing (RITA) algorithm; RITA parameters are calculated once
724 // for each material and managed by G4PenelopeSamplingData objects.
725 // The sampling algorithm (rejection method) has efficiency 67% at low energy, and
726 // increases with energy. For E=100 keV the efficiency is 100% and 86% for
727 // hydrogen and uranium, respectively.
728
729 if (fVerboseLevel > 3)
730 G4cout << "Calling SamplingSecondaries() of G4PenelopeRayleighModelMI" << G4endl;
731
732 G4double photonEnergy0 = aDynamicGamma->GetKineticEnergy();
733
734 if (photonEnergy0 <= fIntrinsicLowEnergyLimit) {
735 fParticleChange->ProposeTrackStatus(fStopAndKill);
736 fParticleChange->SetProposedKineticEnergy(0.);
737 fParticleChange->ProposeLocalEnergyDeposit(photonEnergy0);
738 return;
739 }
740
741 G4ParticleMomentum photonDirection0 = aDynamicGamma->GetMomentumDirection();
742 const G4Material* theMat = couple->GetMaterial();
743
744 //1) Verify if tables are ready
745 //Either Initialize() was not called, or we are in a slave and InitializeLocal() was
746 //not invoked
747 if (!fPMaxTable || !fSamplingTable || !fLogFormFactorTable) {
748 //create a **thread-local** version of the table. Used only for G4EmCalculator and
749 //Unit Tests
750 fLocalTable = true;
751 if (!fLogFormFactorTable)
752 fLogFormFactorTable = new std::map<const G4Material*,G4PhysicsFreeVector*>;
753 if (!fPMaxTable)
754 fPMaxTable = new std::map<const G4Material*,G4PhysicsFreeVector*>;
755 if (!fSamplingTable)
756 fSamplingTable = new std::map<const G4Material*,G4PenelopeSamplingData*>;
757 if (fIsMIActive && !fMolInterferenceData)
758 fMolInterferenceData = new std::map<G4String,G4PhysicsFreeVector*>;
759 }
760
761 if (!fSamplingTable->count(theMat)) {
762 //If we are here, it means that Initialize() was inkoved, but the MaterialTable was
763 //not filled up. This can happen in a UnitTest
764 if (fVerboseLevel > 0) {
765 //Issue a G4Exception (warning) only in verbose mode
767 ed << "Unable to find the fSamplingTable data for " <<
768 theMat->GetName() << G4endl;
769 ed << "This can happen only in Unit Tests" << G4endl;
770 G4Exception("G4PenelopeRayleighModelMI::SampleSecondaries()",
771 "em2019",JustWarning,ed);
772 }
773 const G4ElementVector* theElementVector = theMat->GetElementVector();
774 //protect file reading via autolock
775 G4AutoLock lock(&PenelopeRayleighModelMutex);
776 for (std::size_t j=0;j<theMat->GetNumberOfElements();++j) {
777 G4int iZ = theElementVector->at(j)->GetZasInt();
778 if (!fLogAtomicCrossSection[iZ]) {
779 lock.lock();
780 ReadDataFile(iZ);
781 lock.unlock();
782 }
783 }
784 lock.lock();
785
786 //1) If the table has not been built for the material, do it!
787 if (!fLogFormFactorTable->count(theMat))
788 BuildFormFactorTable(theMat);
789
790 //2) retrieve or build the sampling table
791 if (!(fSamplingTable->count(theMat)))
792 InitializeSamplingAlgorithm(theMat);
793
794 //3) retrieve or build the pMax data
795 if (!fPMaxTable->count(theMat))
796 GetPMaxTable(theMat);
797
798 lock.unlock();
799 }
800
801 //Ok, restart the job
802 G4PenelopeSamplingData* theDataTable = fSamplingTable->find(theMat)->second;
803 G4PhysicsFreeVector* thePMax = fPMaxTable->find(theMat)->second;
804 G4double cosTheta = 1.0;
805
806 //OK, ready to go!
807 G4double qmax = 2.0*photonEnergy0/electron_mass_c2; //this is non-dimensional now
808
809 if (qmax < 1e-10) { //very low momentum transfer
810 G4bool loopAgain=false;
811 do {
812 loopAgain = false;
813 cosTheta = 1.0-2.0*G4UniformRand();
814 G4double G = 0.5*(1+cosTheta*cosTheta);
815 if (G4UniformRand()>G)
816 loopAgain = true;
817 } while(loopAgain);
818 }
819 else { //larger momentum transfer
820 std::size_t nData = theDataTable->GetNumberOfStoredPoints();
821 G4double LastQ2inTheTable = theDataTable->GetX(nData-1);
822 G4double q2max = std::min(qmax*qmax,LastQ2inTheTable);
823
824 G4bool loopAgain = false;
825 G4double MaxPValue = thePMax->Value(photonEnergy0);
826 G4double xx=0;
827
828 //Sampling by rejection method. The rejection function is
829 //G = 0.5*(1+cos^2(theta))
830 do {
831 loopAgain = false;
832 G4double RandomMax = G4UniformRand()*MaxPValue;
833 xx = theDataTable->SampleValue(RandomMax);
834
835 //xx is a random value of q^2 in (0,q2max),sampled according to
836 //F(Q^2) via the RITA algorithm
837 if (xx > q2max)
838 loopAgain = true;
839 cosTheta = 1.0-2.0*xx/q2max;
840 G4double G = 0.5*(1+cosTheta*cosTheta);
841 if (G4UniformRand()>G)
842 loopAgain = true;
843 } while(loopAgain);
844 }
845
846 G4double sinTheta = std::sqrt(1-cosTheta*cosTheta);
847
848 //Scattered photon angles. ( Z - axis along the parent photon)
849 G4double phi = twopi * G4UniformRand() ;
850 G4double dirX = sinTheta*std::cos(phi);
851 G4double dirY = sinTheta*std::sin(phi);
852 G4double dirZ = cosTheta;
853
854 //Update G4VParticleChange for the scattered photon
855 G4ThreeVector photonDirection1(dirX, dirY, dirZ);
856
857 photonDirection1.rotateUz(photonDirection0);
858 fParticleChange->ProposeMomentumDirection(photonDirection1) ;
859 fParticleChange->SetProposedKineticEnergy(photonEnergy0) ;
860
861 return;
862}
863
864//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
865
866void G4PenelopeRayleighModelMI::ReadDataFile(const G4int Z)
867{
868 if (fVerboseLevel > 2) {
869 G4cout << "G4PenelopeRayleighModelMI::ReadDataFile()" << G4endl;
870 G4cout << "Going to read Rayleigh data files for Z=" << Z << G4endl;
871 }
872
873 const char* path = G4FindDataDir("G4LEDATA");
874 if (!path) {
875 G4String excep = "G4LEDATA environment variable not set!";
876 G4Exception("G4PenelopeRayleighModelMI::ReadDataFile()",
877 "em0006",FatalException,excep);
878 return;
879 }
880
881 //Read first the cross section file (all the files have 250 points)
882 std::ostringstream ost;
883 if (Z>9)
884 ost << path << "/penelope/rayleigh/pdgra" << Z << ".p08";
885 else
886 ost << path << "/penelope/rayleigh/pdgra0" << Z << ".p08";
887 std::ifstream file(ost.str().c_str());
888
889 if (!file.is_open()) {
890 G4String excep = "Data file " + G4String(ost.str()) + " not found!";
891 G4Exception("G4PenelopeRayleighModelMI::ReadDataFile()",
892 "em0003",FatalException,excep);
893 }
894
895 G4int readZ = 0;
896 std::size_t nPoints = 0;
897 file >> readZ >> nPoints;
898
899 if (readZ != Z || nPoints <= 0 || nPoints >= 5000) {
901 ed << "Corrupted data file for Z=" << Z << G4endl;
902 G4Exception("G4PenelopeRayleighModelMI::ReadDataFile()",
903 "em0005",FatalException,ed);
904 return;
905 }
906
907 fLogAtomicCrossSection[Z] = new G4PhysicsFreeVector((std::size_t)nPoints);
908 G4double ene=0,f1=0,f2=0,xs=0;
909 for (std::size_t i=0;i<nPoints;++i) {
910 file >> ene >> f1 >> f2 >> xs;
911 //dimensional quantities
912 ene *= eV;
913 xs *= cm2;
914 fLogAtomicCrossSection[Z]->PutValue(i,G4Log(ene),G4Log(xs));
915 if (file.eof() && i != (nPoints-1)) { //file ended too early
917 ed << "Corrupted data file for Z=" << Z << G4endl;
918 ed << "Found less than " << nPoints << " entries" << G4endl;
919 G4Exception("G4PenelopeRayleighModelMI::ReadDataFile()",
920 "em0005",FatalException,ed);
921 }
922 }
923 file.close();
924
925 //Then, read the extended momentum transfer file
926 std::ostringstream ost2;
927 ost2 << path << "/penelope/rayleigh/MIFF/qext.dat";
928 file.open(ost2.str().c_str());
929
930 if (!file.is_open()) {
931 G4String excep = "Data file " + G4String(ost2.str()) + " not found!";
932 G4Exception("G4PenelopeRayleighModelMI::ReadDataFile()",
933 "em0003",FatalException,excep);
934 }
935 G4bool fillQGrid = false;
936 if (!fLogQSquareGrid.size()) {
937 fillQGrid = true;
938 nPoints = 1142;
939 }
940 G4double qext = 0;
941 if (fillQGrid) { //fLogQSquareGrid filled only one time
942 for (std::size_t i=0;i<nPoints;++i) {
943 file >> qext;
944 fLogQSquareGrid.push_back(2.0*G4Log(qext));
945 }
946 }
947 file.close();
948
949 //Finally, read the form factor file
950 std::ostringstream ost3;
951 if (Z>9)
952 ost3 << path << "/penelope/rayleigh/pdaff" << Z << ".p08";
953 else
954 ost3 << path << "/penelope/rayleigh/pdaff0" << Z << ".p08";
955 file.open(ost3.str().c_str());
956
957 if (!file.is_open()) {
958 G4String excep = "Data file " + G4String(ost3.str()) + " not found!";
959 G4Exception("G4PenelopeRayleighModelMI::ReadDataFile()",
960 "em0003",FatalException,excep);
961 }
962
963 file >> readZ >> nPoints;
964
965 if (readZ != Z || nPoints <= 0 || nPoints >= 5000) {
967 ed << "Corrupted data file for Z=" << Z << G4endl;
968 G4Exception("G4PenelopeRayleighModelMI::ReadDataFile()",
969 "em0005",FatalException,ed);
970 return;
971 }
972
973 fAtomicFormFactor[Z] = new G4PhysicsFreeVector((std::size_t)nPoints);
974 G4double q=0,ff=0,incoh=0;
975 for (std::size_t i=0;i<nPoints;++i) {
976 file >> q >> ff >> incoh; //q and ff are dimensionless (q is in units of (m_e*c))
977 fAtomicFormFactor[Z]->PutValue(i,q,ff);
978 if (file.eof() && i != (nPoints-1)) { //file ended too early
980 ed << "Corrupted data file for Z=" << Z << G4endl;
981 ed << "Found less than " << nPoints << " entries" << G4endl;
982 G4Exception("G4PenelopeRayleighModelMI::ReadDataFile()",
983 "em0005",FatalException,ed);
984 }
985 }
986 file.close();
987 return;
988}
989
990//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
991
992void G4PenelopeRayleighModelMI::ReadMolInterferenceData(const G4String& matname,
993 const G4String& FFfilename)
994{
995 if (fVerboseLevel > 2) {
996 G4cout << "G4PenelopeRayleighModelMI::ReadMolInterferenceData() for material " <<
997 matname << G4endl;
998 }
999 G4bool isLocalFile = (FFfilename != "NULL");
1000
1001 const char* path = G4FindDataDir("G4LEDATA");
1002 if (!path) {
1003 G4String excep = "G4LEDATA environment variable not set!";
1004 G4Exception("G4PenelopeRayleighModelMI::ReadMolInterferenceData()",
1005 "em0006",FatalException,excep);
1006 return;
1007 }
1008
1009 if (!(fKnownMaterials->count(matname)) && !isLocalFile) //material not found
1010 return;
1011
1012 G4String aFileName = (isLocalFile) ? FFfilename : fKnownMaterials->find(matname)->second;
1013
1014 //if the material has a MIFF, read it from the database
1015 if (aFileName != "") {
1016 if (fVerboseLevel > 2)
1017 G4cout << "ReadMolInterferenceData(). Read material: " << matname << ", filename: " <<
1018 aFileName << " " <<
1019 (isLocalFile ? "(local)" : "(database)") << G4endl;
1020 std::ifstream file;
1021 std::ostringstream ostIMFF;
1022 if (isLocalFile)
1023 ostIMFF << aFileName;
1024 else
1025 ostIMFF << path << "/penelope/rayleigh/MIFF/" << aFileName;
1026 file.open(ostIMFF.str().c_str());
1027
1028 if (!file.is_open()) {
1029 G4String excep = "Data file " + G4String(ostIMFF.str()) + " not found!";
1030 G4Exception("G4PenelopeRayleighModelMI::ReadMolInterferenceData()",
1031 "em1031",FatalException,excep);
1032 return;
1033 }
1034
1035 //check the number of points in the file
1036 std::size_t nPoints = 0;
1037 G4double x=0,y=0;
1038 while (file.good()) {
1039 file >> x >> y;
1040 nPoints++;
1041 }
1042 file.close();
1043 nPoints--;
1044 if (fVerboseLevel > 3)
1045 G4cout << "Number of nPoints: " << nPoints << G4endl;
1046
1047 //read the file
1048 file.open(ostIMFF.str().c_str());
1049 G4PhysicsFreeVector* theFFVec = new G4PhysicsFreeVector((std::size_t)nPoints);
1050 G4double q=0,ff=0;
1051 for (std::size_t i=0; i<nPoints; ++i) {
1052 file >> q >> ff;
1053
1054 //q and ff are dimensionless (q is in units of (m_e*c))
1055 theFFVec->PutValue(i,q,ff);
1056
1057 //file ended too early
1058 if (file.eof() && i != (nPoints-1)) {
1060 ed << "Corrupted data file" << G4endl;
1061 ed << "Found less than " << nPoints << " entries" << G4endl;
1062 G4Exception("G4PenelopeRayleighModelMI::ReadMolInterferenceData()",
1063 "em1005",FatalException,ed);
1064 }
1065 }
1066 if (!fMolInterferenceData) {
1067 G4Exception("G4PenelopeRayleighModelMI::ReadMolInterferenceData()",
1068 "em2145",FatalException,
1069 "Unable to allocate the Molecular Interference data table");
1070 delete theFFVec;
1071 return;
1072 }
1073 file.close();
1074 fMolInterferenceData->insert(std::make_pair(matname,theFFVec));
1075 }
1076 return;
1077}
1078
1079//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1080
1081G4double G4PenelopeRayleighModelMI::GetFSquared(const G4Material* mat, const G4double QSquared)
1082{
1083 G4double f2 = 0;
1084 //Input value QSquared could be zero: protect the log() below against
1085 //the FPE exception
1086
1087 //If Q<1e-10, set Q to 1e-10
1088 G4double logQSquared = (QSquared>1e-10) ? G4Log(QSquared) : -23.;
1089 //last value of the table
1090 G4double maxlogQ2 = fLogQSquareGrid[fLogQSquareGrid.size()-1];
1091
1092 //now it should be all right
1093 G4PhysicsFreeVector* theVec = fLogFormFactorTable->find(mat)->second;
1094
1095 if (!theVec) {
1097 ed << "Unable to retrieve F squared table for " << mat->GetName() << G4endl;
1098 G4Exception("G4PenelopeRayleighModelMI::GetFSquared()",
1099 "em2046",FatalException,ed);
1100 return 0;
1101 }
1102
1103 if (logQSquared < -20) { //Q < 1e-9
1104 G4double logf2 = (*theVec)[0]; //first value of the table
1105 f2 = G4Exp(logf2);
1106 }
1107 else if (logQSquared > maxlogQ2)
1108 f2 =0;
1109 else {
1110 //log(Q^2) vs. log(F^2)
1111 G4double logf2 = theVec->Value(logQSquared);
1112 f2 = G4Exp(logf2);
1113 }
1114
1115 if (fVerboseLevel > 3) {
1116 G4cout << "G4PenelopeRayleighModelMI::GetFSquared() in " << mat->GetName() << G4endl;
1117 G4cout << "Q^2 = " << QSquared << " (units of 1/(m_e*c)); F^2 = " << f2 << G4endl;
1118 }
1119 return f2;
1120}
1121
1122//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1123
1124void G4PenelopeRayleighModelMI::InitializeSamplingAlgorithm(const G4Material* mat)
1125{
1126 G4double q2min = 0;
1127 G4double q2max = 0;
1128 const std::size_t np = 150; //hard-coded in Penelope
1129 for (std::size_t i=1;i<fLogQSquareGrid.size();++i)
1130 {
1131 G4double Q2 = G4Exp(fLogQSquareGrid[i]);
1132 if (GetFSquared(mat,Q2) > 1e-35)
1133 {
1134 q2max = G4Exp(fLogQSquareGrid[i-1]);
1135 }
1136 }
1137 std::size_t nReducedPoints = np/4;
1138
1139 //check for errors
1140 if (np < 16)
1141 {
1142 G4Exception("G4PenelopeRayleighModelMI::InitializeSamplingAlgorithm()",
1143 "em2047",FatalException,
1144 "Too few points to initialize the sampling algorithm");
1145 }
1146 if (q2min > (q2max-1e-10))
1147 {
1148 G4cout << "q2min= " << q2min << " q2max= " << q2max << G4endl;
1149 G4Exception("G4PenelopeRayleighModelMI::InitializeSamplingAlgorithm()",
1150 "em2048",FatalException,
1151 "Too narrow grid to initialize the sampling algorithm");
1152 }
1153
1154 //This is subroutine RITAI0 of Penelope
1155 //Create an object of type G4PenelopeRayleighSamplingData --> store in a map::Material*
1156
1157 //temporary vectors --> Then everything is stored in G4PenelopeSamplingData
1158 G4DataVector* x = new G4DataVector();
1159
1160 /*******************************************************************************
1161 Start with a grid of NUNIF points uniformly spaced in the interval q2min,q2max
1162 ********************************************************************************/
1163 std::size_t NUNIF = std::min(std::max(((std::size_t)8),nReducedPoints),np/2);
1164 const G4int nip = 51; //hard-coded in Penelope
1165
1166 G4double dx = (q2max-q2min)/((G4double) NUNIF-1);
1167 x->push_back(q2min);
1168 for (std::size_t i=1;i<NUNIF-1;++i)
1169 {
1170 G4double app = q2min + i*dx;
1171 x->push_back(app); //increase
1172 }
1173 x->push_back(q2max);
1174
1175 if (fVerboseLevel> 3)
1176 G4cout << "Vector x has " << x->size() << " points, while NUNIF = " << NUNIF << G4endl;
1177
1178 //Allocate temporary storage vectors
1179 G4DataVector* area = new G4DataVector();
1180 G4DataVector* a = new G4DataVector();
1181 G4DataVector* b = new G4DataVector();
1182 G4DataVector* c = new G4DataVector();
1183 G4DataVector* err = new G4DataVector();
1184
1185 for (std::size_t i=0;i<NUNIF-1;++i) //build all points but the last
1186 {
1187 //Temporary vectors for this loop
1188 G4DataVector* pdfi = new G4DataVector();
1189 G4DataVector* pdfih = new G4DataVector();
1190 G4DataVector* sumi = new G4DataVector();
1191
1192 G4double dxi = ((*x)[i+1]-(*x)[i])/(G4double (nip-1));
1193 G4double pdfmax = 0;
1194 for (G4int k=0;k<nip;k++)
1195 {
1196 G4double xik = (*x)[i]+k*dxi;
1197 G4double pdfk = std::max(GetFSquared(mat,xik),0.);
1198 pdfi->push_back(pdfk);
1199 pdfmax = std::max(pdfmax,pdfk);
1200 if (k < (nip-1))
1201 {
1202 G4double xih = xik + 0.5*dxi;
1203 G4double pdfIK = std::max(GetFSquared(mat,xih),0.);
1204 pdfih->push_back(pdfIK);
1205 pdfmax = std::max(pdfmax,pdfIK);
1206 }
1207 }
1208
1209 //Simpson's integration
1210 G4double cons = dxi*0.5*(1./3.);
1211 sumi->push_back(0.);
1212 for (G4int k=1;k<nip;k++)
1213 {
1214 G4double previous = (*sumi)[k-1];
1215 G4double next = previous + cons*((*pdfi)[k-1]+4.0*(*pdfih)[k-1]+(*pdfi)[k]);
1216 sumi->push_back(next);
1217 }
1218
1219 G4double lastIntegral = (*sumi)[sumi->size()-1];
1220 area->push_back(lastIntegral);
1221 //Normalize cumulative function
1222 G4double factor = 1.0/lastIntegral;
1223 for (std::size_t k=0;k<sumi->size();++k)
1224 (*sumi)[k] *= factor;
1225
1226 //When the PDF vanishes at one of the interval end points, its value is modified
1227 if ((*pdfi)[0] < 1e-35)
1228 (*pdfi)[0] = 1e-5*pdfmax;
1229 if ((*pdfi)[pdfi->size()-1] < 1e-35)
1230 (*pdfi)[pdfi->size()-1] = 1e-5*pdfmax;
1231
1232 G4double pli = (*pdfi)[0]*factor;
1233 G4double pui = (*pdfi)[pdfi->size()-1]*factor;
1234 G4double B_temp = 1.0-1.0/(pli*pui*dx*dx);
1235 G4double A_temp = (1.0/(pli*dx))-1.0-B_temp;
1236 G4double C_temp = 1.0+A_temp+B_temp;
1237 if (C_temp < 1e-35)
1238 {
1239 a->push_back(0.);
1240 b->push_back(0.);
1241 c->push_back(1.);
1242 }
1243 else
1244 {
1245 a->push_back(A_temp);
1246 b->push_back(B_temp);
1247 c->push_back(C_temp);
1248 }
1249
1250 //OK, now get ERR(I), the integral of the absolute difference between the rational interpolation
1251 //and the true pdf, extended over the interval (X(I),X(I+1))
1252 G4int icase = 1; //loop code
1253 G4bool reLoop = false;
1254 err->push_back(0.);
1255 do
1256 {
1257 reLoop = false;
1258 (*err)[i] = 0.; //zero variable
1259 for (G4int k=0;k<nip;k++)
1260 {
1261 G4double rr = (*sumi)[k];
1262 G4double pap = (*area)[i]*(1.0+((*a)[i]+(*b)[i]*rr)*rr)*(1.0+((*a)[i]+(*b)[i]*rr)*rr)/
1263 ((1.0-(*b)[i]*rr*rr)*(*c)[i]*((*x)[i+1]-(*x)[i]));
1264 if (k == 0 || k == nip-1)
1265 (*err)[i] += 0.5*std::fabs(pap-(*pdfi)[k]);
1266 else
1267 (*err)[i] += std::fabs(pap-(*pdfi)[k]);
1268 }
1269 (*err)[i] *= dxi;
1270
1271 //If err(I) is too large, the pdf is approximated by a uniform distribution
1272 if ((*err)[i] > 0.1*(*area)[i] && icase == 1)
1273 {
1274 (*b)[i] = 0;
1275 (*a)[i] = 0;
1276 (*c)[i] = 1.;
1277 icase = 2;
1278 reLoop = true;
1279 }
1280 }while(reLoop);
1281
1282 delete pdfi;
1283 delete pdfih;
1284 delete sumi;
1285 } //end of first loop over i
1286
1287 //Now assign last point
1288 (*x)[x->size()-1] = q2max;
1289 a->push_back(0.);
1290 b->push_back(0.);
1291 c->push_back(0.);
1292 err->push_back(0.);
1293 area->push_back(0.);
1294
1295 if (x->size() != NUNIF || a->size() != NUNIF ||
1296 err->size() != NUNIF || area->size() != NUNIF)
1297 {
1299 ed << "Problem in building the Table for Sampling: array dimensions do not match" << G4endl;
1300 G4Exception("G4PenelopeRayleighModelMI::InitializeSamplingAlgorithm()",
1301 "em2049",FatalException,ed);
1302 }
1303
1304 /*******************************************************************************
1305 New grid points are added by halving the sub-intervals with the largest absolute error
1306 This is done up to np=150 points in the grid
1307 ********************************************************************************/
1308 do
1309 {
1310 G4double maxError = 0.0;
1311 std::size_t iErrMax = 0;
1312 for (std::size_t i=0;i<err->size()-2;++i)
1313 {
1314 //maxError is the lagest of the interval errors err[i]
1315 if ((*err)[i] > maxError)
1316 {
1317 maxError = (*err)[i];
1318 iErrMax = i;
1319 }
1320 }
1321
1322 //OK, now I have to insert one new point in the position iErrMax
1323 G4double newx = 0.5*((*x)[iErrMax]+(*x)[iErrMax+1]);
1324
1325 x->insert(x->begin()+iErrMax+1,newx);
1326 //Add place-holders in the other vectors
1327 area->insert(area->begin()+iErrMax+1,0.);
1328 a->insert(a->begin()+iErrMax+1,0.);
1329 b->insert(b->begin()+iErrMax+1,0.);
1330 c->insert(c->begin()+iErrMax+1,0.);
1331 err->insert(err->begin()+iErrMax+1,0.);
1332
1333 //Now calculate the other parameters
1334 for (std::size_t i=iErrMax;i<=iErrMax+1;++i)
1335 {
1336 //Temporary vectors for this loop
1337 G4DataVector* pdfi = new G4DataVector();
1338 G4DataVector* pdfih = new G4DataVector();
1339 G4DataVector* sumi = new G4DataVector();
1340
1341 G4double dxLocal = (*x)[i+1]-(*x)[i];
1342 G4double dxi = ((*x)[i+1]-(*x)[i])/(G4double (nip-1));
1343 G4double pdfmax = 0;
1344 for (G4int k=0;k<nip;k++)
1345 {
1346 G4double xik = (*x)[i]+k*dxi;
1347 G4double pdfk = std::max(GetFSquared(mat,xik),0.);
1348 pdfi->push_back(pdfk);
1349 pdfmax = std::max(pdfmax,pdfk);
1350 if (k < (nip-1))
1351 {
1352 G4double xih = xik + 0.5*dxi;
1353 G4double pdfIK = std::max(GetFSquared(mat,xih),0.);
1354 pdfih->push_back(pdfIK);
1355 pdfmax = std::max(pdfmax,pdfIK);
1356 }
1357 }
1358
1359 //Simpson's integration
1360 G4double cons = dxi*0.5*(1./3.);
1361 sumi->push_back(0.);
1362 for (G4int k=1;k<nip;k++)
1363 {
1364 G4double previous = (*sumi)[k-1];
1365 G4double next = previous + cons*((*pdfi)[k-1]+4.0*(*pdfih)[k-1]+(*pdfi)[k]);
1366 sumi->push_back(next);
1367 }
1368 G4double lastIntegral = (*sumi)[sumi->size()-1];
1369 (*area)[i] = lastIntegral;
1370
1371 //Normalize cumulative function
1372 G4double factor = 1.0/lastIntegral;
1373 for (std::size_t k=0;k<sumi->size();++k)
1374 (*sumi)[k] *= factor;
1375
1376 //When the PDF vanishes at one of the interval end points, its value is modified
1377 if ((*pdfi)[0] < 1e-35)
1378 (*pdfi)[0] = 1e-5*pdfmax;
1379 if ((*pdfi)[pdfi->size()-1] < 1e-35)
1380 (*pdfi)[pdfi->size()-1] = 1e-5*pdfmax;
1381
1382 G4double pli = (*pdfi)[0]*factor;
1383 G4double pui = (*pdfi)[pdfi->size()-1]*factor;
1384 G4double B_temp = 1.0-1.0/(pli*pui*dxLocal*dxLocal);
1385 G4double A_temp = (1.0/(pli*dxLocal))-1.0-B_temp;
1386 G4double C_temp = 1.0+A_temp+B_temp;
1387 if (C_temp < 1e-35)
1388 {
1389 (*a)[i]= 0.;
1390 (*b)[i] = 0.;
1391 (*c)[i] = 1;
1392 }
1393 else
1394 {
1395 (*a)[i]= A_temp;
1396 (*b)[i] = B_temp;
1397 (*c)[i] = C_temp;
1398 }
1399 //OK, now get ERR(I), the integral of the absolute difference between the rational interpolation
1400 //and the true pdf, extended over the interval (X(I),X(I+1))
1401 G4int icase = 1; //loop code
1402 G4bool reLoop = false;
1403 do
1404 {
1405 reLoop = false;
1406 (*err)[i] = 0.; //zero variable
1407 for (G4int k=0;k<nip;k++)
1408 {
1409 G4double rr = (*sumi)[k];
1410 G4double pap = (*area)[i]*(1.0+((*a)[i]+(*b)[i]*rr)*rr)*(1.0+((*a)[i]+(*b)[i]*rr)*rr)/
1411 ((1.0-(*b)[i]*rr*rr)*(*c)[i]*((*x)[i+1]-(*x)[i]));
1412 if (k == 0 || k == nip-1)
1413 (*err)[i] += 0.5*std::fabs(pap-(*pdfi)[k]);
1414 else
1415 (*err)[i] += std::fabs(pap-(*pdfi)[k]);
1416 }
1417 (*err)[i] *= dxi;
1418
1419 //If err(I) is too large, the pdf is approximated by a uniform distribution
1420 if ((*err)[i] > 0.1*(*area)[i] && icase == 1)
1421 {
1422 (*b)[i] = 0;
1423 (*a)[i] = 0;
1424 (*c)[i] = 1.;
1425 icase = 2;
1426 reLoop = true;
1427 }
1428 }while(reLoop);
1429 delete pdfi;
1430 delete pdfih;
1431 delete sumi;
1432 }
1433 }while(x->size() < np);
1434
1435 if (x->size() != np || a->size() != np ||
1436 err->size() != np || area->size() != np)
1437 {
1438 G4Exception("G4PenelopeRayleighModelMI::InitializeSamplingAlgorithm()",
1439 "em2050",FatalException,
1440 "Problem in building the extended Table for Sampling: array dimensions do not match ");
1441 }
1442
1443 /*******************************************************************************
1444 Renormalization
1445 ********************************************************************************/
1446 G4double ws = 0;
1447 for (std::size_t i=0;i<np-1;++i)
1448 ws += (*area)[i];
1449 ws = 1.0/ws;
1450 G4double errMax = 0;
1451 for (std::size_t i=0;i<np-1;++i)
1452 {
1453 (*area)[i] *= ws;
1454 (*err)[i] *= ws;
1455 errMax = std::max(errMax,(*err)[i]);
1456 }
1457
1458 //Vector with the normalized cumulative distribution
1459 G4DataVector* PAC = new G4DataVector();
1460 PAC->push_back(0.);
1461 for (std::size_t i=0;i<np-1;++i)
1462 {
1463 G4double previous = (*PAC)[i];
1464 PAC->push_back(previous+(*area)[i]);
1465 }
1466 (*PAC)[PAC->size()-1] = 1.;
1467
1468 /*******************************************************************************
1469 Pre-calculated limits for the initial binary search for subsequent sampling
1470 ********************************************************************************/
1471 std::vector<std::size_t> *ITTL = new std::vector<std::size_t>;
1472 std::vector<std::size_t> *ITTU = new std::vector<std::size_t>;
1473
1474 //Just create place-holders
1475 for (std::size_t i=0;i<np;++i)
1476 {
1477 ITTL->push_back(0);
1478 ITTU->push_back(0);
1479 }
1480
1481 G4double bin = 1.0/(np-1);
1482 (*ITTL)[0]=0;
1483 for (std::size_t i=1;i<(np-1);++i)
1484 {
1485 G4double ptst = i*bin;
1486 G4bool found = false;
1487 for (std::size_t j=(*ITTL)[i-1];j<np && !found;++j)
1488 {
1489 if ((*PAC)[j] > ptst)
1490 {
1491 (*ITTL)[i] = j-1;
1492 (*ITTU)[i-1] = j;
1493 found = true;
1494 }
1495 }
1496 }
1497 (*ITTU)[ITTU->size()-2] = ITTU->size()-1;
1498 (*ITTU)[ITTU->size()-1] = ITTU->size()-1;
1499 (*ITTL)[ITTL->size()-1] = ITTU->size()-2;
1500
1501 if (ITTU->size() != np || ITTU->size() != np)
1502 {
1503 G4Exception("G4PenelopeRayleighModelMI::InitializeSamplingAlgorithm()",
1504 "em2051",FatalException,
1505 "Problem in building the Limit Tables for Sampling: array dimensions do not match");
1506 }
1507
1508 /********************************************************************************
1509 Copy tables
1510 ********************************************************************************/
1512 for (std::size_t i=0;i<np;++i)
1513 {
1514 theTable->AddPoint((*x)[i],(*PAC)[i],(*a)[i],(*b)[i],(*ITTL)[i],(*ITTU)[i]);
1515 }
1516 if (fVerboseLevel > 2)
1517 {
1518 G4cout << "*************************************************************************" <<
1519 G4endl;
1520 G4cout << "Sampling table for Penelope Rayleigh scattering in " << mat->GetName() << G4endl;
1521 theTable->DumpTable();
1522 }
1523 fSamplingTable->insert(std::make_pair(mat,theTable));
1524
1525 //Clean up temporary vectors
1526 delete x;
1527 delete a;
1528 delete b;
1529 delete c;
1530 delete err;
1531 delete area;
1532 delete PAC;
1533 delete ITTL;
1534 delete ITTU;
1535
1536 //DONE!
1537 return;
1538}
1539
1540//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1541
1542void G4PenelopeRayleighModelMI::GetPMaxTable(const G4Material* mat)
1543{
1544 if (!fPMaxTable)
1545 {
1546 G4cout << "G4PenelopeRayleighModelMI::BuildPMaxTable" << G4endl;
1547 G4cout << "Going to instanziate the fPMaxTable !" << G4endl;
1548 G4cout << "That should _not_ be here! " << G4endl;
1549 fPMaxTable = new std::map<const G4Material*,G4PhysicsFreeVector*>;
1550 }
1551 //check if the table is already there
1552 if (fPMaxTable->count(mat))
1553 return;
1554
1555 //otherwise build it
1556 if (!fSamplingTable)
1557 {
1558 G4Exception("G4PenelopeRayleighModelMI::GetPMaxTable()",
1559 "em2052",FatalException,
1560 "SamplingTable is not properly instantiated");
1561 return;
1562 }
1563
1564 //This should not be: the sampling table is built before the p-table
1565 if (!fSamplingTable->count(mat))
1566 {
1568 ed << "Sampling table for material " << mat->GetName() << " not found";
1569 G4Exception("G4PenelopeRayleighModelMI::GetPMaxTable()",
1570 "em2052",FatalException,
1571 ed);
1572 return;
1573 }
1574
1575 G4PenelopeSamplingData *theTable = fSamplingTable->find(mat)->second;
1576 std::size_t tablePoints = theTable->GetNumberOfStoredPoints();
1577 std::size_t nOfEnergyPoints = fLogEnergyGridPMax.size();
1578 G4PhysicsFreeVector* theVec = new G4PhysicsFreeVector(nOfEnergyPoints);
1579
1580 const std::size_t nip = 51; //hard-coded in Penelope
1581
1582 for (std::size_t ie=0;ie<fLogEnergyGridPMax.size();++ie)
1583 {
1584 G4double energy = G4Exp(fLogEnergyGridPMax[ie]);
1585 G4double Qm = 2.0*energy/electron_mass_c2; //this is non-dimensional now
1586 G4double Qm2 = Qm*Qm;
1587 G4double firstQ2 = theTable->GetX(0);
1588 G4double lastQ2 = theTable->GetX(tablePoints-1);
1589 G4double thePMax = 0;
1590
1591 if (Qm2 > firstQ2)
1592 {
1593 if (Qm2 < lastQ2)
1594 {
1595 //bisection to look for the index of Qm
1596 std::size_t lowerBound = 0;
1597 std::size_t upperBound = tablePoints-1;
1598 while (lowerBound <= upperBound)
1599 {
1600 std::size_t midBin = (lowerBound + upperBound)/2;
1601 if( Qm2 < theTable->GetX(midBin))
1602 { upperBound = midBin-1; }
1603 else
1604 { lowerBound = midBin+1; }
1605 }
1606 //upperBound is the output (but also lowerBounf --> should be the same!)
1607 G4double Q1 = theTable->GetX(upperBound);
1608 G4double Q2 = Qm2;
1609 G4double DQ = (Q2-Q1)/((G4double)(nip-1));
1610 G4double theA = theTable->GetA(upperBound);
1611 G4double theB = theTable->GetB(upperBound);
1612 G4double thePAC = theTable->GetPAC(upperBound);
1613 G4DataVector* fun = new G4DataVector();
1614 for (std::size_t k=0;k<nip;++k)
1615 {
1616 G4double qi = Q1 + k*DQ;
1617 G4double tau = (qi-Q1)/
1618 (theTable->GetX(upperBound+1)-Q1);
1619 G4double con1 = 2.0*theB*tau;
1620 G4double ci = 1.0+theA+theB;
1621 G4double con2 = ci-theA*tau;
1622 G4double etap = 0;
1623 if (std::fabs(con1) > 1.0e-16*std::fabs(con2))
1624 etap = con2*(1.0-std::sqrt(1.0-2.0*tau*con1/(con2*con2)))/con1;
1625 else
1626 etap = tau/con2;
1627 G4double theFun = (theTable->GetPAC(upperBound+1)-thePAC)*
1628 (1.0+(theA+theB*etap)*etap)*(1.0+(theA+theB*etap)*etap)/
1629 ((1.0-theB*etap*etap)*ci*(theTable->GetX(upperBound+1)-Q1));
1630 fun->push_back(theFun);
1631 }
1632 //Now intergrate numerically the fun Cavalieri-Simpson's method
1633 G4DataVector* sum = new G4DataVector;
1634 G4double CONS = DQ*(1./12.);
1635 G4double HCONS = 0.5*CONS;
1636 sum->push_back(0.);
1637 G4double secondPoint = (*sum)[0] +
1638 (5.0*(*fun)[0]+8.0*(*fun)[1]-(*fun)[2])*CONS;
1639 sum->push_back(secondPoint);
1640 for (std::size_t hh=2;hh<nip-1;++hh)
1641 {
1642 G4double previous = (*sum)[hh-1];
1643 G4double next = previous+(13.0*((*fun)[hh-1]+(*fun)[hh])-
1644 (*fun)[hh+1]-(*fun)[hh-2])*HCONS;
1645 sum->push_back(next);
1646 }
1647 G4double last = (*sum)[nip-2]+(5.0*(*fun)[nip-1]+8.0*(*fun)[nip-2]-
1648 (*fun)[nip-3])*CONS;
1649 sum->push_back(last);
1650 thePMax = thePAC + (*sum)[sum->size()-1]; //last point
1651 delete fun;
1652 delete sum;
1653 }
1654 else
1655 {
1656 thePMax = 1.0;
1657 }
1658 }
1659 else
1660 {
1661 thePMax = theTable->GetPAC(0);
1662 }
1663
1664 //Write number in the table
1665 theVec->PutValue(ie,energy,thePMax);
1666 }
1667
1668 fPMaxTable->insert(std::make_pair(mat,theVec));
1669 return;
1670}
1671
1672//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1673
1675{
1676 G4cout << "*****************************************************************" << G4endl;
1677 G4cout << "G4PenelopeRayleighModelMI: Form Factor Table for " << mat->GetName() << G4endl;
1678 //try to use the same format as Penelope-Fortran, namely Q (/m_e*c) and F
1679 G4cout << "Q/(m_e*c) F(Q) " << G4endl;
1680 G4cout << "*****************************************************************" << G4endl;
1681 if (!fLogFormFactorTable->count(mat))
1682 BuildFormFactorTable(mat);
1683
1684 G4PhysicsFreeVector* theVec = fLogFormFactorTable->find(mat)->second;
1685 for (std::size_t i=0;i<theVec->GetVectorLength();++i)
1686 {
1687 G4double logQ2 = theVec->GetLowEdgeEnergy(i);
1688 G4double Q = G4Exp(0.5*logQ2);
1689 G4double logF2 = (*theVec)[i];
1690 G4double F = G4Exp(0.5*logF2);
1691 G4cout << Q << " " << F << G4endl;
1692 }
1693 //DONE
1694 return;
1695}
1696
1697//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...
1698
1699void G4PenelopeRayleighModelMI::SetParticle(const G4ParticleDefinition* p)
1700{
1701 if(!fParticle) {
1702 fParticle = p;
1703 }
1704}
1705
1706//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...
1707void G4PenelopeRayleighModelMI::LoadKnownMIFFMaterials()
1708{
1709 fKnownMaterials->insert(std::pair<G4String,G4String>("Fat_MI","FF_fat_Tartari2002.dat"));
1710 fKnownMaterials->insert(std::pair<G4String,G4String>("Water_MI","FF_water_Tartari2002.dat"));
1711 fKnownMaterials->insert(std::pair<G4String,G4String>("BoneMatrix_MI","FF_bonematrix_Tartari2002.dat"));
1712 fKnownMaterials->insert(std::pair<G4String,G4String>("Mineral_MI","FF_mineral_Tartari2002.dat"));
1713 fKnownMaterials->insert(std::pair<G4String,G4String>("adipose_MI","FF_adipose_Poletti2002.dat"));
1714 fKnownMaterials->insert(std::pair<G4String,G4String>("glandular_MI","FF_glandular_Poletti2002.dat"));
1715 fKnownMaterials->insert(std::pair<G4String,G4String>("breast5050_MI","FF_human_breast_Peplow1998.dat"));
1716 fKnownMaterials->insert(std::pair<G4String,G4String>("carcinoma_MI","FF_carcinoma_Kidane1999.dat"));
1717 fKnownMaterials->insert(std::pair<G4String,G4String>("muscle_MI","FF_pork_muscle_Peplow1998.dat"));
1718 fKnownMaterials->insert(std::pair<G4String,G4String>("kidney_MI","FF_pork_kidney_Peplow1998.dat"));
1719 fKnownMaterials->insert(std::pair<G4String,G4String>("liver_MI","FF_pork_liver_Peplow1998.dat"));
1720 fKnownMaterials->insert(std::pair<G4String,G4String>("heart_MI","FF_pork_heart_Peplow1998.dat"));
1721 fKnownMaterials->insert(std::pair<G4String,G4String>("blood_MI","FF_beef_blood_Peplow1998.dat"));
1722 fKnownMaterials->insert(std::pair<G4String,G4String>("grayMatter_MI","FF_gbrain_DeFelici2008.dat"));
1723 fKnownMaterials->insert(std::pair<G4String,G4String>("whiteMatter_MI","FF_wbrain_DeFelici2008.dat"));
1724 fKnownMaterials->insert(std::pair<G4String,G4String>("bone_MI","FF_bone_King2011.dat"));
1725 fKnownMaterials->insert(std::pair<G4String,G4String>("FatLowX_MI","FF_fat_Tartari2002_joint_lowXdata_ESRF2003.dat"));
1726 fKnownMaterials->insert(std::pair<G4String,G4String>("BoneMatrixLowX_MI","FF_bonematrix_Tartari2002_joint_lowXdata.dat"));
1727 fKnownMaterials->insert(std::pair<G4String,G4String>("PMMALowX_MI", "FF_PMMA_Tartari2002_joint_lowXdata_ESRF2003.dat"));
1728 fKnownMaterials->insert(std::pair<G4String,G4String>("dryBoneLowX_MI","FF_drybone_Tartari2002_joint_lowXdata_ESRF2003.dat"));
1729 fKnownMaterials->insert(std::pair<G4String,G4String>("CIRS30-70_MI","FF_CIRS30-70_Poletti2002.dat"));
1730 fKnownMaterials->insert(std::pair<G4String,G4String>("CIRS50-50_MI","FF_CIRS50-50_Poletti2002.dat"));
1731 fKnownMaterials->insert(std::pair<G4String,G4String>("CIRS70-30_MI","FF_CIRS70-30_Poletti2002.dat"));
1732 fKnownMaterials->insert(std::pair<G4String,G4String>("RMI454_MI", "FF_RMI454_Poletti2002.dat"));
1733 fKnownMaterials->insert(std::pair<G4String,G4String>("PMMA_MI","FF_PMMA_Tartari2002.dat"));
1734 fKnownMaterials->insert(std::pair<G4String,G4String>("Lexan_MI","FF_lexan_Peplow1998.dat"));
1735 fKnownMaterials->insert(std::pair<G4String,G4String>("Kapton_MI","FF_kapton_Peplow1998.dat"));
1736 fKnownMaterials->insert(std::pair<G4String,G4String>("Nylon_MI","FF_nylon_Kosanetzky1987.dat"));
1737 fKnownMaterials->insert(std::pair<G4String,G4String>("Polyethylene_MI","FF_polyethylene_Kosanetzky1987.dat"));
1738 fKnownMaterials->insert(std::pair<G4String,G4String>("Polystyrene_MI","FF_polystyrene_Kosanetzky1987.dat"));
1739 fKnownMaterials->insert(std::pair<G4String,G4String>("Formaline_MI","FF_formaline_Peplow1998.dat"));
1740 fKnownMaterials->insert(std::pair<G4String,G4String>("Acetone_MI","FF_acetone_Cozzini2010.dat"));
1741 fKnownMaterials->insert(std::pair<G4String,G4String>("Hperoxide_MI","FF_Hperoxide_Cozzini2010.dat"));
1742}
1743
1744//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1745
1746G4double G4PenelopeRayleighModelMI::IntegrateFun(G4double y[], G4int n, G4double dTheta)
1747{
1748 G4double integral = 0.;
1749 for (G4int k=0; k<n-1; k++) {
1750 integral += (y[k]+y[k+1]);
1751 }
1752 integral *= dTheta*0.5;
1753 return integral;
1754}
1755
1756//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1757G4MIData* G4PenelopeRayleighModelMI::GetMIData(const G4Material* material)
1758{
1759 if (material->IsExtended()) {
1760 G4ExtendedMaterial* aEM = (G4ExtendedMaterial*)material;
1761 G4MIData* dataMI = (G4MIData*)aEM->RetrieveExtension("MI");
1762 return dataMI;
1763 } else {
1764 return nullptr;
1765 }
1766}
std::vector< const G4Element * > G4ElementVector
const char * G4FindDataDir(const char *)
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
std::ostringstream G4ExceptionDescription
Definition: G4Exception.hh:40
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:180
G4double G4Log(G4double x)
Definition: G4Log.hh:227
#define G4MUTEX_INITIALIZER
Definition: G4Threading.hh:85
std::mutex G4Mutex
Definition: G4Threading.hh:81
@ fStopAndKill
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
const G4int Z[17]
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
Hep3Vector & rotateUz(const Hep3Vector &)
Definition: ThreeVector.cc:33
const G4ThreeVector & GetMomentumDirection() const
G4double GetKineticEnergy() const
static G4EmParameters * Instance()
G4int Verbose() const
G4VMaterialExtension * RetrieveExtension(const G4String &name)
const G4String & GetFilenameFF()
Definition: G4MIData.hh:52
const G4Material * GetMaterial() const
const G4ElementVector * GetElementVector() const
Definition: G4Material.hh:185
G4double GetTotNbOfAtomsPerVolume() const
Definition: G4Material.hh:204
virtual G4bool IsExtended() const
Definition: G4Material.cc:842
const G4double * GetFractionVector() const
Definition: G4Material.hh:189
size_t GetNumberOfElements() const
Definition: G4Material.hh:181
const G4String & GetName() const
Definition: G4Material.hh:172
void SetProposedKineticEnergy(G4double proposedKinEnergy)
void ProposeMomentumDirection(const G4ThreeVector &Pfinal)
G4double ComputeCrossSectionPerAtom(const G4ParticleDefinition *, G4double kinEnergy, G4double Z, G4double A=0, G4double cut=0, G4double emax=DBL_MAX) override
void InitialiseLocal(const G4ParticleDefinition *, G4VEmModel *masterModel) override
void SampleSecondaries(std::vector< G4DynamicParticle * > *, const G4MaterialCutsCouple *, const G4DynamicParticle *, G4double tmin, G4double maxEnergy) override
G4double CrossSectionPerVolume(const G4Material *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0., G4double maxEnergy=DBL_MAX) override
void Initialise(const G4ParticleDefinition *, const G4DataVector &) override
void DumpFormFactorTable(const G4Material *)
G4PenelopeRayleighModelMI(const G4ParticleDefinition *p=nullptr, const G4String &processName="PenRayleighMI")
G4double GetA(size_t index)
G4double GetPAC(size_t index)
void AddPoint(G4double x0, G4double pac0, G4double a0, G4double b0, size_t ITTL0, size_t ITTU0)
G4double GetX(size_t index)
G4double SampleValue(G4double rndm)
G4double GetB(size_t index)
void PutValue(const std::size_t index, const G4double e, const G4double value)
G4double GetLowEdgeEnergy(const std::size_t index) const
G4double Energy(const std::size_t index) const
G4double Value(const G4double energy, std::size_t &lastidx) const
std::size_t GetVectorLength() const
void FillSecondDerivatives(const G4SplineType=G4SplineType::Base, const G4double dir1=0.0, const G4double dir2=0.0)
const G4MaterialCutsCouple * GetMaterialCutsCouple(G4int i) const
std::size_t GetTableSize() const
static G4ProductionCutsTable * GetProductionCutsTable()
void SetHighEnergyLimit(G4double)
Definition: G4VEmModel.hh:746
G4ParticleChangeForGamma * GetParticleChangeForGamma()
Definition: G4VEmModel.cc:124
G4double LowEnergyLimit() const
Definition: G4VEmModel.hh:641
G4bool IsMaster() const
Definition: G4VEmModel.hh:725
virtual G4double CrossSectionPerVolume(const G4Material *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
Definition: G4VEmModel.cc:181
G4double HighEnergyLimit() const
Definition: G4VEmModel.hh:634
void ProposeTrackStatus(G4TrackStatus status)
void ProposeLocalEnergyDeposit(G4double anEnergyPart)
G4double energy(const ThreeVector &p, const G4double m)