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