// // ******************************************************************** // * 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: G4SandiaTable.cc 76289 2013-11-08 13:07:00Z gcosmo $ // //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo.... // // 10.06.97 created. V. Grichine // 18.11.98 simplified public interface; new methods for materials. mma // 31.01.01 redesign of ComputeMatSandiaMatrix(). mma // 16.02.01 adapted for STL. mma // 22.02.01 GetsandiaCofForMaterial(energy) return 0 below lowest interval mma // 03.04.01 fnulcof returned if energy < emin // 10.07.01 Migration to STL. M. Verderi. // 03.02.04 Update distructor V.Ivanchenko // 05.03.04 New methods for old sorting algorithm for PAI model. V.Grichine // 26.10.11 new scheme for G4Exception (mma) // 22.05.13 preparation of material table without dynamical arrays. V. Grichine // //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo.... #include "G4SandiaTable.hh" #include "G4StaticSandiaData.hh" #include "G4Material.hh" #include "G4MaterialTable.hh" // #include "G4MaterialCutsCouple.hh" #include "G4PhysicalConstants.hh" #include "G4SystemOfUnits.hh" const G4double G4SandiaTable::funitc[5] = { CLHEP::keV, CLHEP::cm2*CLHEP::keV/CLHEP::g, CLHEP::cm2*CLHEP::keV*CLHEP::keV/CLHEP::g, CLHEP::cm2*CLHEP::keV*CLHEP::keV*CLHEP::keV/CLHEP::g, CLHEP::cm2*CLHEP::keV*CLHEP::keV*CLHEP::keV*CLHEP::keV/CLHEP::g }; const G4double G4SandiaTable::fnulcof[] = {0.0}; G4int G4SandiaTable::fCumulInterval[] = {0}; //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo.... G4SandiaTable::G4SandiaTable(G4Material* material) : fMaterial(material) { fMatSandiaMatrix = 0; fMatSandiaMatrixPAI = 0; fPhotoAbsorptionCof = 0; fMatNbOfIntervals = 0; fMaxInterval = 0; fVerbose = 0; //build the CumulInterval array if(0 == fCumulInterval[0]) { fCumulInterval[0] = 1; for (G4int Z=1; Z<101; ++Z) { fCumulInterval[Z] = fCumulInterval[Z-1] + fNbOfIntervals[Z]; } } fMaxInterval = 0; fSandiaCofPerAtom.resize(4,0.0); fLowerI1 = false; //compute macroscopic Sandia coefs for a material ComputeMatSandiaMatrix(); // mma } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo.... // Fake default constructor - sets only member data and allocates memory // for usage restricted to object persistency G4SandiaTable::G4SandiaTable(__void__&) : fMaterial(0),fMatSandiaMatrix(0), fMatSandiaMatrixPAI(0),fPhotoAbsorptionCof(0) { fMaxInterval = 0; fMatNbOfIntervals = 0; fLowerI1 = false; fVerbose = 0; fSandiaCofPerAtom.resize(4,0.0); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo.... G4SandiaTable::~G4SandiaTable() { if(fMatSandiaMatrix) { //fMatSandiaMatrix->clearAndDestroy(); delete fMatSandiaMatrix; } if(fMatSandiaMatrixPAI) { //fMatSandiaMatrixPAI->clearAndDestroy(); delete fMatSandiaMatrixPAI; } if(fPhotoAbsorptionCof) { delete [] fPhotoAbsorptionCof; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo.... void G4SandiaTable::GetSandiaCofPerAtom(G4int Z, G4double energy, std::vector& coeff) { assert(4 <= coeff.size()); G4double Emin = fSandiaTable[fCumulInterval[Z-1]][0]*keV; G4double Iopot = fIonizationPotentials[Z]*eV; if (Iopot > Emin) Emin = Iopot; G4int interval = fNbOfIntervals[Z] - 1; G4int row = fCumulInterval[Z-1] + interval; while ((interval>0) && (energy= Emin) { G4double AoverAvo = Z*amu/fZtoAratio[Z]; coeff[0]=AoverAvo*funitc[1]*fSandiaTable[row][1]; coeff[1]=AoverAvo*funitc[2]*fSandiaTable[row][2]; coeff[2]=AoverAvo*funitc[3]*fSandiaTable[row][3]; coeff[3]=AoverAvo*funitc[4]*fSandiaTable[row][4]; } else { coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo.... G4double G4SandiaTable::GetZtoA(G4int Z) { assert (Z>0 && Z<101); return fZtoAratio[Z]; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... ....oooOO0OOooo.... void G4SandiaTable::ComputeMatSandiaMatrix() { //get list of elements const G4int NbElm = fMaterial->GetNumberOfElements(); const G4ElementVector* ElementVector = fMaterial->GetElementVector(); G4int* Z = new G4int[NbElm]; //Atomic number //determine the maximum number of energy-intervals for this material G4int MaxIntervals = 0; G4int elm; for ( elm = 0; elm < NbElm; elm++ ) { Z[elm] = (G4int)(*ElementVector)[elm]->GetZ(); MaxIntervals += fNbOfIntervals[Z[elm]]; } //copy the Energy bins in a tmp1 array //(take care of the Ionization Potential of each element) G4double* tmp1 = new G4double[MaxIntervals]; G4double IonizationPot; G4int interval1 = 0; for ( elm = 0; elm < NbElm; elm++ ) { IonizationPot = GetIonizationPot(Z[elm]); for (G4int row = fCumulInterval[Z[elm]-1]; row < fCumulInterval[Z[elm]]; row++) { tmp1[interval1++] = std::max(fSandiaTable[row][0]*keV,IonizationPot); } } //sort the energies in strickly increasing values in a tmp2 array //(eliminate redondances) G4double* tmp2 = new G4double[MaxIntervals]; G4double Emin; G4int interval2 = 0; do { Emin = DBL_MAX; for ( G4int i1 = 0; i1 < MaxIntervals; i1++ ) { if (tmp1[i1] < Emin) Emin = tmp1[i1]; //find the minimum } if (Emin < DBL_MAX) tmp2[interval2++] = Emin; //copy Emin in tmp2 for ( G4int j1 = 0; j1 < MaxIntervals; j1++ ) { if (tmp1[j1] <= Emin) tmp1[j1] = DBL_MAX; //eliminate from tmp1 } } while (Emin < DBL_MAX); //create the sandia matrix for this material fMatSandiaMatrix = new G4OrderedTable(); G4int interval; for (interval = 0; interval < interval2; interval++ ) { fMatSandiaMatrix->push_back( new G4DataVector(5,0.) ); } //ready to compute the Sandia coefs for the material const G4double* NbOfAtomsPerVolume = fMaterial->GetVecNbOfAtomsPerVolume(); static const G4double prec = 1.e-03*eV; G4double coef, oldsum(0.), newsum(0.); fMatNbOfIntervals = 0; for ( interval = 0; interval < interval2; interval++ ) { Emin = (*(*fMatSandiaMatrix)[fMatNbOfIntervals])[0] = tmp2[interval]; for ( G4int k = 1; k < 5; k++ ) { (*(*fMatSandiaMatrix)[fMatNbOfIntervals])[k] = 0.; } newsum = 0.; for ( elm = 0; elm < NbElm; elm++ ) { GetSandiaCofPerAtom(Z[elm], Emin+prec, fSandiaCofPerAtom); for ( G4int j = 1; j < 5; j++ ) { coef = NbOfAtomsPerVolume[elm]*fSandiaCofPerAtom[j-1]; (*(*fMatSandiaMatrix)[fMatNbOfIntervals])[j] += coef; newsum += std::fabs(coef); } } //check for null or redondant intervals if (newsum != oldsum) { oldsum = newsum; fMatNbOfIntervals++;} } delete [] Z; delete [] tmp1; delete [] tmp2; // fMaxInterval = fMatNbOfIntervals; // vmg 16.02.11 if ( fVerbose > 0 && fMaterial->GetName() == "G4_Ar" ) { G4cout<<"mma, G4SandiaTable::ComputeMatSandiaMatrix(), mat = " <GetName()<GetSandiaCofForMaterial(i,1) <<"\t"<GetSandiaCofForMaterial(i,2) <<"\t"<GetSandiaCofForMaterial(i,3) <<"\t"<GetSandiaCofForMaterial(i,4)<GetNumberOfElements(); const G4ElementVector* ElementVector = fMaterial->GetElementVector(); std::vector Z(noElm); //Atomic number for ( elm = 0; elm < noElm; elm++ ) { Z[elm] = (G4int)(*ElementVector)[elm]->GetZ(); MaxIntervals += fNbOfIntervals[Z[elm]]; } fMaxInterval = MaxIntervals + 2; // fMaxInterval = MaxIntervals + 1; // fMaxInterval = MaxIntervals; if ( fVerbose > 0 ) { G4cout<<"fMaxInterval = "< fSandiaTable[k1][0] ) { continue; // no ionization for energies smaller than I1 (first } // ionisation potential) break; } G4int flag = 0; for( c1 = 1; c1 < c; c1++ ) { if( fPhotoAbsorptionCof0[c1] == I1 ) // this value already has existed { flag = 1; break; } } if(flag == 0) { fPhotoAbsorptionCof0[c] = I1; c++; } for( k2 = k1; k2 < n2; k2++ ) { flag = 0; for( c1 = 1; c1 < c; c1++ ) { if( fPhotoAbsorptionCof0[c1] == fSandiaTable[k2][0] ) { flag = 1; break; } } if(flag == 0) { fPhotoAbsorptionCof0[c] = fSandiaTable[k2][0]; c++; } } } // end for(i) // sort out for( i = 1; i < c; i++ ) { for( j = i + 1; j < c; j++ ) { if( fPhotoAbsorptionCof0[i] > fPhotoAbsorptionCof0[j] ) { G4double tmp = fPhotoAbsorptionCof0[i]; fPhotoAbsorptionCof0[i] = fPhotoAbsorptionCof0[j]; fPhotoAbsorptionCof0[j] = tmp; } } if ( fVerbose > 0 && fMaterial->GetName() == "G4_Ar" ) { G4cout<GetDensity(); for (i = 0; i < fMaxInterval; i++) // -> G4units { fPhotoAbsorptionCof0[i+1] *= funitc[0]; fPhotoAbsorptionCof1[i+1] *= funitc[1]*density; fPhotoAbsorptionCof2[i+1] *= funitc[2]*density; fPhotoAbsorptionCof3[i+1] *= funitc[3]*density; fPhotoAbsorptionCof4[i+1] *= funitc[4]*density; } if(fLowerI1) { if( fMaterial->GetName() == "G4_WATER") { fMaxInterval += fH2OlowerInt; for (i = 0; i < fMaxInterval; i++) // init vector table { fMatSandiaMatrixPAI->push_back( new G4DataVector(5,0.) ); } for (i = 0; i < fH2OlowerInt; i++) { (*(*fMatSandiaMatrixPAI)[i])[0] = fH2OlowerI1[i][0]; (*(*fMatSandiaMatrixPAI)[i])[1] = fH2OlowerI1[i][1]; // *density; (*(*fMatSandiaMatrixPAI)[i])[2] = fH2OlowerI1[i][2]; // *density; (*(*fMatSandiaMatrixPAI)[i])[3] = fH2OlowerI1[i][3]; // *density; (*(*fMatSandiaMatrixPAI)[i])[4] = fH2OlowerI1[i][4]; // *density; } for (i = fH2OlowerInt; i < fMaxInterval; i++) { (*(*fMatSandiaMatrixPAI)[i])[0] = fPhotoAbsorptionCof0[i+1-fH2OlowerInt]; (*(*fMatSandiaMatrixPAI)[i])[1] = fPhotoAbsorptionCof1[i+1-fH2OlowerInt]; // *density; (*(*fMatSandiaMatrixPAI)[i])[2] = fPhotoAbsorptionCof2[i+1-fH2OlowerInt]; // *density; (*(*fMatSandiaMatrixPAI)[i])[3] = fPhotoAbsorptionCof3[i+1-fH2OlowerInt]; // *density; (*(*fMatSandiaMatrixPAI)[i])[4] = fPhotoAbsorptionCof4[i+1-fH2OlowerInt]; // *density; } } } else { for (i = 0; i < fMaxInterval; i++) // init vector table { fMatSandiaMatrixPAI->push_back( new G4DataVector(5,0.) ); } for (i = 0; i < fMaxInterval; i++) { (*(*fMatSandiaMatrixPAI)[i])[0] = fPhotoAbsorptionCof0[i+1]; (*(*fMatSandiaMatrixPAI)[i])[1] = fPhotoAbsorptionCof1[i+1]; // *density; (*(*fMatSandiaMatrixPAI)[i])[2] = fPhotoAbsorptionCof2[i+1]; // *density; (*(*fMatSandiaMatrixPAI)[i])[3] = fPhotoAbsorptionCof3[i+1]; // *density; (*(*fMatSandiaMatrixPAI)[i])[4] = fPhotoAbsorptionCof4[i+1]; // *density; } } // fMaxInterval--; // to avoid duplicate at 500 keV or extra zeros in last interval if ( fVerbose > 0 ) { G4cout<<"vmg, G4SandiaTable::ComputeMatSandiaMatrixPAI(), mat = " <GetName()<GetSandiaMatTablePAI(i,1) <<"\t"<GetSandiaMatTablePAI(i,2) <<"\t"<GetSandiaMatTablePAI(i,3) <<"\t"<GetSandiaMatTablePAI(i,4)<= 0 && matIndex < numberOfMat) { fMaterial = (*theMaterialTable)[matIndex]; // ComputeMatTable(); } else { G4Exception("G4SandiaTable::G4SandiaTable(G4int matIndex)", "mat401", FatalException, "wrong matIndex"); } } ///////////////////////////////////////////////////////////////////////////// G4SandiaTable::G4SandiaTable() { fMaterial = 0; fMatNbOfIntervals = 0; fMatSandiaMatrix = 0; fMatSandiaMatrixPAI = 0; fPhotoAbsorptionCof = 0; fMaxInterval = 0; fVerbose = 0; fLowerI1 = false; fSandiaCofPerAtom.resize(4,0.0); } //////////////////////////////////////////////////////////////////// void G4SandiaTable::Initialize(G4Material* mat) { fMaterial = mat; ComputeMatSandiaMatrixPAI(); } ///////////////////////////////////////////////////////////////////// /* void G4SandiaTable::Initialize(G4MaterialCutsCouple* matcc) { fMaterial = matcc->GetMaterial(); ComputeMatSandiaMatrixPAI(); } */ /////////////////////////////////////////////////////////////////////// void G4SandiaTable::Initialize(G4int matIndex) { const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable(); G4int numberOfMat = G4Material::GetNumberOfMaterials(); if ( matIndex >= 0 && matIndex < numberOfMat ) { fMaterial = (*theMaterialTable)[matIndex]; ComputeMatTable(); } else { G4Exception("G4SandiaTable::Initialize(G4int matIndex)", "mat401", FatalException, "wrong matIndex"); } } //////////////////////////////////////////////////////////////////////////////.. G4int G4SandiaTable::GetMaxInterval() const { return fMaxInterval; } /////////////////////////////////////////////////////////////////////////////////.. G4double** G4SandiaTable::GetPointerToCof() { if(!fPhotoAbsorptionCof) { ComputeMatTable(); } return fPhotoAbsorptionCof; } //////////////////////////////////////////////////////////////////////////////.. void G4SandiaTable::SandiaSwap( G4double** da , G4int i, G4int j ) { G4double tmp = da[i][0] ; da[i][0] = da[j][0] ; da[j][0] = tmp ; } /////////////////////////////////////////////////////////////////////////////////.. G4double G4SandiaTable::GetPhotoAbsorpCof(G4int i, G4int j) const { return fPhotoAbsorptionCof[i][j]*funitc[j]; } //////////////////////////////////////////////////////////////////////////////////.. // // Bubble sorting of left energy interval in SandiaTable in ascening order // void G4SandiaTable::SandiaSort(G4double** da, G4int sz) { for(G4int i = 1;i < sz; i++ ) { for(G4int j = i + 1;j < sz; j++ ) { if(da[i][0] > da[j][0]) SandiaSwap(da,i,j); } } } ///////////////////////////////////////////////////////////////////////////////////////.. // // SandiaIntervals // G4int G4SandiaTable::SandiaIntervals(G4int Z[], G4int el ) { G4int c, i, flag = 0, n1 = 1; G4int j, c1, k1, k2; G4double I1; fMaxInterval = 0; for( i = 0; i < el; i++ ) fMaxInterval += fNbOfIntervals[ Z[i] ]; fMaxInterval += 2; if( fVerbose > 0 ) { G4cout<<"begin sanInt, fMaxInterval = "< fSandiaTable[k1][0] ) { continue; // no ionization for energies smaller than I1 (first } // ionisation potential) break; } flag = 0; for( c1 = 1; c1 < c; c1++ ) { if( fPhotoAbsorptionCof[c1][0] == I1 ) // this value already has existed { flag = 1; break; } } if( flag == 0 ) { fPhotoAbsorptionCof[c][0] = I1; c++; } for( k2 = k1; k2 < n2; k2++ ) { flag = 0; for( c1 = 1; c1 < c; c1++ ) { if( fPhotoAbsorptionCof[c1][0] == fSandiaTable[k2][0] ) { flag = 1; break; } } if( flag == 0 ) { fPhotoAbsorptionCof[c][0] = fSandiaTable[k2][0]; if( fVerbose > 0 ) { G4cout<<"sanInt, c = "<GetSandiaCofForMaterial(i,1) <<"\t"<GetSandiaCofForMaterial(i,2) <<"\t"<GetSandiaCofForMaterial(i,3) <<"\t"<GetSandiaCofForMaterial(i,4)<