// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // $Id: G4PenelopeBremsstrahlungFS.cc,v 1.1 2010-12-20 14:11:37 pandola Exp $ // GEANT4 tag $Name: not supported by cvs2svn $ // // Author: Luciano Pandola // // History: // -------- // 23 Nov 2010 L Pandola First complete implementation // 02 May 2011 L.Pandola Remove dependency on CLHEP::HepMatrix // 24 May 2011 L. Pandola Renamed (make v2008 as default Penelope) // //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... #include "G4PenelopeBremsstrahlungFS.hh" #include "G4PhysicsFreeVector.hh" #include "G4PhysicsLogVector.hh" #include "G4PhysicsTable.hh" #include "G4Material.hh" #include "Randomize.hh" //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4PenelopeBremsstrahlungFS::G4PenelopeBremsstrahlungFS() : theReducedXSTable(0),theEffectiveZSq(0),theSamplingTable(0), thePBcut(0) { G4double tempvector[nBinsX] = {1.0e-12,0.025e0,0.05e0,0.075e0,0.1e0,0.15e0,0.2e0,0.25e0, 0.3e0,0.35e0,0.4e0,0.45e0,0.5e0,0.55e0,0.6e0,0.65e0,0.7e0, 0.75e0,0.8e0,0.85e0,0.9e0,0.925e0,0.95e0,0.97e0,0.99e0, 0.995e0,0.999e0,0.9995e0,0.9999e0,0.99995e0,0.99999e0,1.0e0}; for (size_t ix=0;ix; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4PenelopeBremsstrahlungFS::~G4PenelopeBremsstrahlungFS() { ClearTables(); //Clear manually theElementData std::map::iterator i; if (theElementData) { for (i=theElementData->begin(); i != theElementData->end(); i++) delete i->second; delete theElementData; theElementData = 0; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo... void G4PenelopeBremsstrahlungFS::ClearTables() { std::map< std::pair ,G4PhysicsTable*>::iterator j; if (theReducedXSTable) { for (j=theReducedXSTable->begin(); j != theReducedXSTable->end(); j++) { G4PhysicsTable* tab = j->second; tab->clearAndDestroy(); delete tab; } delete theReducedXSTable; theReducedXSTable = 0; } if (theSamplingTable) { for (j=theSamplingTable->begin(); j != theSamplingTable->end(); j++) { G4PhysicsTable* tab = j->second; tab->clearAndDestroy(); delete tab; } delete theSamplingTable; theSamplingTable = 0; } std::map< std::pair ,G4PhysicsFreeVector*>::iterator kk; if (thePBcut) { for (kk=thePBcut->begin(); kk != thePBcut->end(); kk++) delete kk->second; delete thePBcut; thePBcut = 0; } if (theEffectiveZSq) { delete theEffectiveZSq; theEffectiveZSq = 0; } return; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4PenelopeBremsstrahlungFS::GetEffectiveZSquared(const G4Material* material) { if (!theEffectiveZSq) { G4ExceptionDescription ed; ed << "The container for the values is not initialized" << G4endl; G4Exception("G4PenelopeBremsstrahlungFS::GetEffectiveZSquared()", "em2007",FatalException,ed); return 0; } //found in the table: return it if (theEffectiveZSq->count(material)) return theEffectiveZSq->find(material)->second; else { G4ExceptionDescription ed; ed << "The value of is not properly set for material " << material->GetName() << G4endl; //requires running of BuildScaledXSTable() G4Exception("G4PenelopeBremsstrahlungFS::GetEffectiveZSquared()", "em2008",FatalException,ed); } return 0; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4PenelopeBremsstrahlungFS::BuildScaledXSTable(const G4Material* material, G4double cut) { //Corresponds to subroutines EBRaW and EBRaR of PENELOPE /* This method generates the table of the scaled energy-loss cross section from bremsstrahlung emission for the given material. Original data are read from file. The table is normalized according to the Berger-Seltzer cross section. */ //********************************************************************* //Determine the equivalent atomic number //********************************************************************* std::vector *StechiometricFactors = new std::vector; G4int nElements = material->GetNumberOfElements(); const G4ElementVector* elementVector = material->GetElementVector(); const G4double* fractionVector = material->GetFractionVector(); for (G4int i=0;iGetA()/(g/mole); StechiometricFactors->push_back(fraction/atomicWeigth); } //Find max G4double MaxStechiometricFactor = 0.; for (G4int i=0;i MaxStechiometricFactor) MaxStechiometricFactor = (*StechiometricFactors)[i]; } //Normalize for (G4int i=0;iGetZ(); sumz2 += (*StechiometricFactors)[i]*Z*Z; sums += (*StechiometricFactors)[i]; } G4double ZBR2 = sumz2/sums; theEffectiveZSq->insert(std::make_pair(material,ZBR2)); //********************************************************************* // loop on elements and read data files //********************************************************************* G4DataVector* tempData = new G4DataVector(nBinsE); G4DataVector* tempMatrix = new G4DataVector(nBinsE*nBinsX,0.); for (G4int iel=0;ielGetZ(); G4int iZ = (G4int) Z; G4double wgt = (*StechiometricFactors)[iel]*Z*Z/ZBR2; // //the element is not already loaded if (!theElementData->count(iZ)) { ReadDataFile(iZ); if (!theElementData->count(iZ)) { G4ExceptionDescription ed; ed << "Error in G4PenelopeBremsstrahlungFS::BuildScaledXSTable" << G4endl; ed << "Unable to retrieve data for element " << iZ << G4endl; G4Exception("G4PenelopeBremsstrahlungFS::BuildScaledXSTable()", "em2009",FatalException,ed); } } G4DataVector* atomData = theElementData->find(iZ)->second; for (size_t ie=0;ie 1.0) { G4ExceptionDescription ed; ed << "G4PenelopeBremsstrahlungFS. Corrupted data files?" << G4endl; G4cout << "TST= " << TST << "; fnorm = " << fnorm << G4endl; G4cout << "rsum = " << rsum << G4endl; G4cout << "fact = " << fact << G4endl; G4cout << ie << " " << theEGrid[ie]/keV << " " << (*tempData)[ie]/barn << G4endl; G4Exception("G4PenelopeBremsstrahlungFS::BuildScaledXSTable()", "em2010",FatalException,ed); } for (size_t ix=0;ixpush_back(new G4PhysicsFreeVector(nBinsE+1)); for (size_t ix=0;ixPutValue(ie+1,logene,std::log(aValue)); } //Add fake point at 1 eV using an extrapolation with the derivative //at the first valid point (Penelope approach) G4double derivative = ((*theVec)[2]-(*theVec)[1])/(theVec->Energy(2) - theVec->Energy(1)); G4double log1eV = std::log(1*eV); G4double val1eV = (*theVec)[1]+derivative*(log1eV-theVec->Energy(1)); //fake point at very low energy theVec->PutValue(0,log1eV,val1eV); } std::pair theKey = std::make_pair(material,cut); theReducedXSTable->insert(std::make_pair(theKey,thePhysicsTable)); delete StechiometricFactors; delete tempData; delete tempMatrix; return; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4PenelopeBremsstrahlungFS::ReadDataFile(G4int Z) { char* path = getenv("G4LEDATA"); if (!path) { G4String excep = "G4PenelopeBremsstrahlungFS - G4LEDATA environment variable not set!"; G4Exception("G4PenelopeBremsstrahlungFS::ReadDataFile()", "em0006",FatalException,excep); return; } /* Read the cross section file */ std::ostringstream ost; if (Z>9) ost << path << "/penelope/bremsstrahlung/pdebr" << Z << ".p08"; else ost << path << "/penelope/bremsstrahlung/pdebr0" << Z << ".p08"; std::ifstream file(ost.str().c_str()); if (!file.is_open()) { G4String excep = "G4PenelopeBremsstrahlungFS - data file " + G4String(ost.str()) + " not found!"; G4Exception("G4PenelopeBremsstrahlungFS::ReadDataFile()", "em0003",FatalException,excep); return; } G4int readZ =0; file >> readZ; //check the right file is opened. if (readZ != Z) { G4ExceptionDescription ed; ed << "Corrupted data file for Z=" << Z << G4endl; G4Exception("G4PenelopeBremsstrahlungFS::ReadDataFile()", "em0005",FatalException,ed); return; } G4DataVector* theMatrix = new G4DataVector(nBinsE*(nBinsX+1),0.); //initialized with zeros for (size_t ie=0;ie> myDouble; //energy (eV) if (!theEGrid[ie]) //fill only the first time theEGrid[ie] = myDouble*eV; // for (size_t ix=0;ix> myDouble; (*theMatrix)[ie*(nBinsX+1)+ix] = myDouble*millibarn; } file >> myDouble; //total cross section (*theMatrix)[ie*(nBinsX+1)+nBinsX] = myDouble*millibarn; } if (theElementData) theElementData->insert(std::make_pair(Z,theMatrix)); else delete theMatrix; file.close(); return; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4PenelopeBremsstrahlungFS::GetMomentumIntegral(G4double* y, G4double xup,G4int momOrder) //x is always the gridX { //Corresponds to the function RLMOM of Penelope //This method performs the calculation of the integral of (x^momOrder)*y over the interval //from x[0] to xup, obtained by linear interpolation on a table of y. //The independent variable is assumed to take positive values only. // size_t size = nBinsX; const G4double eps = 1e-35; //Check that the call is valid if (momOrder<-1 || size<2 || theXGrid[0]<0) { G4Exception("G4PenelopeBremsstrahlungFS::GetMomentumIntegral()", "em2011",FatalException,"Invalid call"); } for (size_t i=1;i1e-14*std::fabs(dy)) { G4double b=dy/dx; G4double a=y1-b*x1; if (momOrder == -1) ds = a*std::log(xtc/x1)+b*(xtc-x1); else if (momOrder == 0) //speed it up, not using pow() ds = a*(xtc-x1) + 0.5*b*(xtc*xtc-x1*x1); else ds = a*(std::pow(xtc,momOrder+1)-std::pow(x1,momOrder+1))/((G4double) (momOrder + 1)) + b*(std::pow(xtc,momOrder+2)-std::pow(x1,momOrder+2))/((G4double) (momOrder + 2)); } else ds = 0.5*(y1+y2)*(xtc-x1)*std::pow(xtc,momOrder); result += ds; if (!loopAgain) return result; } return result; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4PhysicsTable* G4PenelopeBremsstrahlungFS::GetScaledXSTable(const G4Material* mat, G4double cut) { //check if the container exists (if not, create it) if (!theReducedXSTable) theReducedXSTable = new std::map< std::pair , G4PhysicsTable*>; if (!theEffectiveZSq) theEffectiveZSq = new std::map; //check if it already contains the entry std::pair theKey = std::make_pair(mat,cut); if (!(theReducedXSTable->count(theKey))) //not found BuildScaledXSTable(mat,cut); if (!(theReducedXSTable->count(theKey))) { G4Exception("G4PenelopeBremsstrahlungFS::GetScaledXSTable()", "em2013",FatalException,"Unable to retrieve the cross section table"); } return theReducedXSTable->find(theKey)->second; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4PenelopeBremsstrahlungFS::InitializeEnergySampling(const G4Material* material, G4double cut) { std::pair theKey = std::make_pair(material,cut); G4PhysicsTable* thePhysicsTable = new G4PhysicsTable(); // the table will contain 57 G4PhysicsFreeVectors with different // values of E. G4PhysicsFreeVector* thePBvec = new G4PhysicsFreeVector(nBinsE); //I reserve space of the vectors. for (size_t i=0;ipush_back(new G4PhysicsFreeVector(nBinsX)); //Retrieve existing table using the method GetScaledXSTable() //This will create the table ex-novo, if it does not exist for //some reason G4PhysicsTable* theTableReduced = GetScaledXSTable(material,cut); for (size_t ie=0;iePutValue(0,theXGrid[0],value); for (size_t ix=1;ixPutValue(ix,theXGrid[ix],value); } //fill the PB vector G4double xc = cut/theEGrid[ie]; //Fill a temp data vector G4double* tempData = new G4double[nBinsX]; for (size_t ix=0;ixPutValue(ie,theEGrid[ie],pbval); delete[] tempData; } theSamplingTable->insert(std::make_pair(theKey,thePhysicsTable)); thePBcut->insert(std::make_pair(theKey,thePBvec)); return; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4PenelopeBremsstrahlungFS::SampleGammaEnergy(G4double energy,const G4Material* mat, G4double cut) { if (!theSamplingTable) theSamplingTable = new std::map< std::pair , G4PhysicsTable*>; if (!thePBcut) thePBcut = new std::map< std::pair , G4PhysicsFreeVector* >; std::pair theKey = std::make_pair(mat,cut); if (!(theSamplingTable->count(theKey))) { InitializeEnergySampling(mat,cut); if (!(theSamplingTable->count(theKey)) || !(thePBcut->count(theKey))) { G4ExceptionDescription ed; ed << "Unable to create the SamplingTable: " << theSamplingTable->count(theKey) << " " << thePBcut->count(theKey) << G4endl; G4Exception("G4PenelopeBremsstrahlungFS::SampleGammaEnergy()", "em2014",FatalException,ed); } } G4PhysicsTable* theTableInte = theSamplingTable->find(theKey)->second; G4PhysicsTable* theTableRed = theReducedXSTable->find(theKey)->second; //Find the energy bin using bi-partition size_t eBin = 0; if (energy < theEGrid[0]) eBin = 0; else if (energy > theEGrid[nBinsE-1]) eBin = nBinsE-1; else { size_t i=0; size_t j=nBinsE-1; while ((j-i)>1) { size_t k = (i+j)/2; if (energy > theEGrid[k]) i = k; else j = k; } eBin = i; } //Get the appropriate physics vector G4PhysicsFreeVector* theVec = (G4PhysicsFreeVector*) (*theTableInte)[eBin]; //Start the game G4double pbcut = (*(thePBcut->find(theKey)->second))[eBin]; G4double pCumulative = (*theVec)[nBinsX-1]; //last value G4double eGamma = 0; do { G4double pt = pbcut + G4UniformRand()*(pCumulative - pbcut); //find where it is size_t ibin = 0; if (pt < (*theVec)[0]) ibin = 0; else if (pt > (*theVec)[nBinsX-1]) { //We observed problems due to numerical rounding here (STT). //delta here is a tiny positive number G4double delta = pt-(*theVec)[nBinsX-1]; if (delta < pt*1e-10) // very small! Numerical rounding only { ibin = nBinsX-1; G4ExceptionDescription ed; ed << "Found that (pt > (*theVec)[nBinsX-1]) with pt = " << pt << " , (*theVec)[nBinsX-1] = " << (*theVec)[nBinsX-1] << " and delta = " << (pt-(*theVec)[nBinsX-1]) << G4endl; ed << "Possible symptom of problem with numerical precision" << G4endl; G4Exception("G4PenelopeBremsstrahlungFS::SampleGammaEnergy()", "em2015",JustWarning,ed); } else //real problem { G4ExceptionDescription ed; ed << "Crash at (pt > (*theVec)[nBinsX-1]) with pt = " << pt << " , (*theVec)[nBinsX-1]=" << (*theVec)[nBinsX-1] << " and nBinsX = " << nBinsX << G4endl; ed << "Material: " << mat->GetName() << ", energy = " << energy/keV << " keV" << G4endl; G4Exception("G4PenelopeBremsstrahlungFS::SampleGammaEnergy()", "em2015",FatalException,ed); } } else { size_t i=0; size_t j=nBinsX-1; while ((j-i)>1) { size_t k = (i+j)/2; if (pt > (*theVec)[k]) i = k; else j = k; } ibin = i; } G4double w1 = theXGrid[ibin]; G4double w2 = theXGrid[ibin+1]; G4PhysicsFreeVector* v1 = (G4PhysicsFreeVector*) (*theTableRed)[ibin]; G4PhysicsFreeVector* v2 = (G4PhysicsFreeVector*) (*theTableRed)[ibin+1]; //Remember: the table theReducedXSTable has a fake first point in energy //so, it contains one more bin than nBinsE. G4double pdf1 = std::exp((*v1)[eBin+1]); G4double pdf2 = std::exp((*v2)[eBin+1]); G4double deltaW = w2-w1; G4double dpdfb = pdf2-pdf1; G4double B = dpdfb/deltaW; G4double A = pdf1-B*w1; G4double wbcut = (cut < theEGrid[eBin]) ? cut/theEGrid[eBin] : 1.0; if (w1 < wbcut) w1 = wbcut; if (w2 < w1) { G4cout << "Warning in G4PenelopeBremsstrahlungFS::SampleX()" << G4endl; G4cout << "Conflicting end-point values" << G4endl; return w1*energy; } G4double pmax = std::max(A+B*w1,A+B*w2); G4bool loopAgain = false; do { loopAgain = false; eGamma = w1* std::pow((w2/w1),G4UniformRand()); if (G4UniformRand()*pmax > (A+B*eGamma)) loopAgain = true; }while(loopAgain); eGamma *= energy; }while(eGamma < cut); //repeat if sampled sub-cut! return eGamma; }