// // ******************************************************************** // * 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. * // ******************************************************************** // // // ------------------------------------------------------------------- // // GEANT4 Class file // // // File name: G4EmModelManager // // Author: Vladimir Ivanchenko // // Creation date: 07.05.2002 // // Modifications: V.Ivanchenko // // Class Description: // // It is the unified energy loss process it calculates the continuous // energy loss for charged particles using a set of Energy Loss // models valid for different energy regions. There are a possibility // to create and access to dE/dx and range tables, or to calculate // that information on fly. // ------------------------------------------------------------------- // //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... #include "G4EmModelManager.hh" #include "G4SystemOfUnits.hh" #include "G4PhysicsTable.hh" #include "G4PhysicsVector.hh" #include "G4VMscModel.hh" //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4RegionModels::G4RegionModels(G4int nMod, std::vector& indx, G4DataVector& lowE, const G4Region* reg) { nModelsForRegion = nMod; theListOfModelIndexes = new G4int [nModelsForRegion]; lowKineticEnergy = new G4double [nModelsForRegion+1]; for (G4int i=0; i 0) { for(size_t i=0; iDefineForRegion(r); ++nEmModels; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4EmModelManager::UpdateEmModel(const G4String& nam, G4double emin, G4double emax) { if (nEmModels > 0) { for(G4int i=0; iGetName()) { models[i]->SetLowEnergyLimit(emin); models[i]->SetHighEnergyLimit(emax); break; } } } G4cout << "G4EmModelManager::UpdateEmModel WARNING: no model <" << nam << "> is found out" << G4endl; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VEmModel* G4EmModelManager::GetModel(G4int i, G4bool ver) { G4VEmModel* model = nullptr; if(i < nEmModels) { model = models[i]; } else if(verboseLevel > 0 && ver) { G4cout << "G4EmModelManager::GetModel WARNING: " << "index " << i << " is wrong Nmodels= " << nEmModels; if(particle) { G4cout << " for " << particle->GetParticleName(); } G4cout<< G4endl; } return model; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VEmModel* G4EmModelManager::GetRegionModel(G4int k, size_t idx) { G4RegionModels* rm = setOfRegionModels[idxOfRegionModels[idx]]; G4VEmModel* mod = models[rm->ModelIndex(k)]; return mod; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4int G4EmModelManager::NumberOfRegionModels(size_t idx) const { G4RegionModels* rm = setOfRegionModels[idxOfRegionModels[idx]]; return rm->NumberOfModels(); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... const G4DataVector* G4EmModelManager::Initialise(const G4ParticleDefinition* p, const G4ParticleDefinition* secondaryParticle, G4double minSubRange, G4int val) { verboseLevel = val; G4String partname = p->GetParticleName(); if(1 < verboseLevel) { G4cout << "G4EmModelManager::Initialise() for " << partname << " Nmodels= " << nEmModels << G4endl; } // Are models defined? if(nEmModels < 1) { G4ExceptionDescription ed; ed << "No models found out for " << p->GetParticleName() << " !"; G4Exception("G4EmModelManager::Initialise","em0002", FatalException, ed); } particle = p; Clear(); // needed if run is not first G4RegionStore* regionStore = G4RegionStore::GetInstance(); const G4Region* world = regionStore->GetRegion("DefaultRegionForTheWorld", false); // Identify the list of regions with different set of models nRegions = 1; std::vector setr; setr.push_back(world); G4bool isWorld = false; for (G4int ii=0; ii1) { for (G4int j=1; jGetParticleName() << " !"; G4Exception("G4EmModelManager::Initialise","em0002", FatalException, ed); } G4ProductionCutsTable* theCoupleTable= G4ProductionCutsTable::GetProductionCutsTable(); size_t numOfCouples = theCoupleTable->GetTableSize(); // prepare vectors, shortcut for the case of only 1 model // or only one region if(nRegions > 1 && nEmModels > 1) { idxOfRegionModels.resize(numOfCouples,0); setOfRegionModels.resize((size_t)nRegions,0); } else { idxOfRegionModels.resize(1,0); setOfRegionModels.resize(1,0); } std::vector modelAtRegion(nEmModels); std::vector modelOrd(nEmModels); G4DataVector eLow(nEmModels+1); G4DataVector eHigh(nEmModels); if(1 < verboseLevel) { G4cout << " Nregions= " << nRegions << " Nmodels= " << nEmModels << G4endl; } // Order models for regions for (G4int reg=0; regLowEnergyLimit(); G4double tmax = model->HighEnergyLimit(); G4int ord = orderOfModels[ii]; G4bool push = true; G4bool insert = false; G4int idx = n; if(1 < verboseLevel) { G4cout << "Model #" << ii << " <" << model->GetName() << "> for region <"; if (region) G4cout << region->GetName(); G4cout << "> " << " tmin(MeV)= " << tmin/MeV << "; tmax(MeV)= " << tmax/MeV << "; order= " << ord << "; tminAct= " << model->LowEnergyActivationLimit()/MeV << "; tmaxAct= " << model->HighEnergyActivationLimit()/MeV << G4endl; } static const G4double limitdelta = 0.01*eV; if(n > 0) { // extend energy range to previous models tmin = std::min(tmin, eHigh[n-1]); tmax = std::max(tmax, eLow[0]); //G4cout << "tmin= " << tmin << " tmax= " // << tmax << " ord= " << ord <= modelOrd[k]) { if(tmin < eHigh[k] && tmin >= eLow[k]) { tmin = eHigh[k]; } if(tmax <= eHigh[k] && tmax > eLow[k]) { tmax = eLow[k]; } if(tmax > eHigh[k] && tmin < eLow[k]) { if(tmax - eHigh[k] > eLow[k] - tmin) { tmin = eHigh[k]; } else { tmax = eLow[k]; } } if( tmax - tmin <= limitdelta) { push = false; break; } } } // this model has lower order parameter than possible // other models, with which there may be intersections // so, appliction area of such models may be reduced // insert below the first model if (tmax <= eLow[0]) { push = false; insert = true; idx = 0; // resolve intersections } else if(tmin < eHigh[n-1]) { // last energy interval if(tmin > eLow[n-1] && tmax >= eHigh[n-1]) { eHigh[n-1] = tmin; // first energy interval } else if(tmin <= eLow[0] && tmax < eHigh[0]) { eLow[0] = tmax; push = false; insert = true; idx = 0; // loop over all models } else { for(G4int k=n-1; k>=0; --k) { if(tmin <= eLow[k] && tmax >= eHigh[k]) { // full overlap exclude previous model isUsed[modelAtRegion[k]] = 0; idx = k; if(k < n-1) { // shift upper models and change index for(G4int kk=k; kk eLow[k]) { eLow[k] = tmax; idx = k; insert = true; push = false; } else if(tmin < eHigh[k] && tmax >= eHigh[k]) { eHigh[k] = tmin; idx = k + 1; if(idx < n) { insert = true; push = false; } } else if(tmin > eLow[k] && tmax < eHigh[k]) { if(eHigh[k] - tmax > tmin - eLow[k]) { eLow[k] = tmax; idx = k; insert = true; push = false; } else { eHigh[k] = tmin; idx = k + 1; if(idx < n) { insert = true; push = false; } } } } } } } } } // provide space for the new model if(insert) { for(G4int k=n-1; k>=idx; --k) { modelAtRegion[k+1] = modelAtRegion[k]; modelOrd[k+1] = modelOrd[k]; eLow[k+1] = eLow[k]; eHigh[k+1] = eHigh[k]; } } //G4cout << "push= " << push << " insert= " << insert // << " idx= " << idx <=0; --k) { if(eHigh[k] - eLow[k] <= limitdelta) { isUsed[modelAtRegion[k]] = 0; if(k < n-1) { for(G4int kk=k; kkGetName(); } G4cout << "> Elow(MeV)= "; for(G4int iii=0; iii<=n; ++iii) {G4cout << eLow[iii]/MeV << " ";} G4cout << G4endl; } G4RegionModels* rm = new G4RegionModels(n, modelAtRegion, eLow, region); setOfRegionModels[reg] = rm; // shortcut if(1 == nEmModels) { break; } } currRegionModel = setOfRegionModels[0]; currModel = models[0]; // Access to materials and build cuts size_t idx = 1; if(secondaryParticle) { if( secondaryParticle == G4Gamma::Gamma() ) { idx = 0; } else if( secondaryParticle == G4Electron::Electron()) { idx = 1; } else if( secondaryParticle == G4Positron::Positron()) { idx = 2; } else { idx = 3; } } theCuts = static_cast(theCoupleTable->GetEnergyCutsVector(idx)); // for the second run the check on cuts should be repeated if(theCutsNew) { *theCutsNew = *theCuts; } if(minSubRange < 1.0) { if( !theSubCuts ) { theSubCuts = new G4DataVector(); } theSubCuts->resize(numOfCouples,DBL_MAX); } // G4cout << "========Start define cuts" << G4endl; // define cut values for(size_t i=0; iGetMaterialCutsCouple(i); const G4Material* material = couple->GetMaterial(); const G4ProductionCuts* pcuts = couple->GetProductionCuts(); G4int reg = 0; if(nRegions > 1 && nEmModels > 1) { reg = nRegions; // Loop checking, 03-Aug-2015, Vladimir Ivanchenko do {--reg;} while (reg>0 && pcuts != (setr[reg]->GetProductionCuts())); idxOfRegionModels[i] = reg; } if(1 < verboseLevel) { G4cout << "G4EmModelManager::Initialise() for " << material->GetName() << " indexOfCouple= " << i << " indexOfRegion= " << reg << G4endl; } G4double cut = (*theCuts)[i]; if(secondaryParticle) { // compute subcut if( cut < DBL_MAX && minSubRange < 1.0) { G4double subcut = minSubRange*cut; G4double rcut = std::min(minSubRange*pcuts->GetProductionCut(idx), maxSubCutInRange); G4double tcutmax = theCoupleTable->ConvertRangeToEnergy(secondaryParticle, material,rcut); if(tcutmax < subcut) { subcut = tcutmax; } (*theSubCuts)[i] = subcut; } // note that idxOfRegionModels[] not always filled G4int inn = 0; G4int nnm = 1; if(nRegions > 1 && nEmModels > 1) { inn = idxOfRegionModels[i]; } // check cuts and introduce upper limits //G4cout << "idx= " << i << " cut(keV)= " << cut/keV << G4endl; currRegionModel = setOfRegionModels[inn]; nnm = currRegionModel->NumberOfModels(); //G4cout << "idx= " << i << " Nmod= " << nnm << G4endl; for(G4int jj=0; jjGetName() << " Cut was changed from " << cut/keV << " keV to " << cutlim/keV << " keV " << " due to " << currModel->GetName() << G4endl; */ } } } } if(theCutsNew) { theCuts = theCutsNew; } // initialize models G4int nn = 0; severalModels = true; for(G4int jj=0; jjInitialise(particle, *theCuts); if(flucModels[jj]) { flucModels[jj]->InitialiseMe(particle); } } } if(1 == nn) { severalModels = false; } if(1 < verboseLevel) { G4cout << "G4EmModelManager for " << partname << " is initialised; nRegions= " << nRegions << " severalModels: " << severalModels << G4endl; } return theCuts; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4EmModelManager::FillDEDXVector(G4PhysicsVector* aVector, const G4MaterialCutsCouple* couple, G4EmTableType tType) { size_t i = couple->GetIndex(); G4double cut = (*theCuts)[i]; G4double emin = 0.0; if(fTotal == tType) { cut = DBL_MAX; } else if(fSubRestricted == tType) { emin = cut; if(theSubCuts) { emin = (*theSubCuts)[i]; } } if(1 < verboseLevel) { G4cout << "G4EmModelManager::FillDEDXVector() for " << couple->GetMaterial()->GetName() << " cut(MeV)= " << cut << " emin(MeV)= " << emin << " Type " << tType << " for " << particle->GetParticleName() << G4endl; } G4int reg = 0; if(nRegions > 1 && nEmModels > 1) { reg = idxOfRegionModels[i]; } const G4RegionModels* regModels = setOfRegionModels[reg]; G4int nmod = regModels->NumberOfModels(); // Calculate energy losses vector //G4cout << "nmod= " << nmod << G4endl; size_t totBinsLoss = aVector->GetVectorLength(); G4double del = 0.0; G4int k0 = 0; for(size_t j=0; jEnergy(j); // Choose a model of energy losses G4int k = 0; if (nmod > 1) { k = nmod; // Loop checking, 03-Aug-2015, Vladimir Ivanchenko do {--k;} while (k>0 && e <= regModels->LowEdgeEnergy(k)); //G4cout << "k= " << k << G4endl; if(k > 0 && k != k0) { k0 = k; G4double elow = regModels->LowEdgeEnergy(k); G4double dedx1 = ComputeDEDX(models[regModels->ModelIndex(k-1)], couple,elow,cut,emin); G4double dedx2 = ComputeDEDX(models[regModels->ModelIndex(k)], couple,elow,cut,emin); del = 0.0; if(dedx2 > 0.0) { del = (dedx1/dedx2 - 1.0)*elow; } //G4cout << "elow= " << elow // << " dedx1= " << dedx1 << " dedx2= " << dedx2 << G4endl; } } G4double dedx = ComputeDEDX(models[regModels->ModelIndex(k)],couple,e,cut,emin); dedx *= (1.0 + del/e); if(2 < verboseLevel) { G4cout << "Material= " << couple->GetMaterial()->GetName() << " E(MeV)= " << e/MeV << " dEdx(MeV/mm)= " << dedx*mm/MeV << " del= " << del*mm/MeV<< " k= " << k << " modelIdx= " << regModels->ModelIndex(k) << G4endl; } if(dedx < 0.0) { dedx = 0.0; } aVector->PutValue(j, dedx); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4EmModelManager::FillLambdaVector(G4PhysicsVector* aVector, const G4MaterialCutsCouple* couple, G4bool startFromNull, G4EmTableType tType) { size_t i = couple->GetIndex(); G4double cut = (*theCuts)[i]; G4double tmax = DBL_MAX; if (fSubRestricted == tType) { tmax = cut; if(theSubCuts) { cut = (*theSubCuts)[i]; } } G4int reg = 0; if(nRegions > 1 && nEmModels > 1) { reg = idxOfRegionModels[i]; } const G4RegionModels* regModels = setOfRegionModels[reg]; G4int nmod = regModels->NumberOfModels(); if(1 < verboseLevel) { G4cout << "G4EmModelManager::FillLambdaVector() for " << particle->GetParticleName() << " in " << couple->GetMaterial()->GetName() << " Emin(MeV)= " << aVector->Energy(0) << " Emax(MeV)= " << aVector->GetMaxEnergy() << " cut= " << cut << " Type " << tType << " nmod= " << nmod << " theSubCuts " << theSubCuts << G4endl; } // Calculate lambda vector size_t totBinsLambda = aVector->GetVectorLength(); G4double del = 0.0; G4int k0 = 0; G4int k = 0; G4VEmModel* mod = models[regModels->ModelIndex(0)]; for(size_t j=0; jEnergy(j); // Choose a model if (nmod > 1) { k = nmod; // Loop checking, 03-Aug-2015, Vladimir Ivanchenko do {--k;} while (k>0 && e <= regModels->LowEdgeEnergy(k)); if(k > 0 && k != k0) { k0 = k; G4double elow = regModels->LowEdgeEnergy(k); G4VEmModel* mod1 = models[regModels->ModelIndex(k-1)]; G4double xs1 = mod1->CrossSection(couple,particle,elow,cut,tmax); mod = models[regModels->ModelIndex(k)]; G4double xs2 = mod->CrossSection(couple,particle,elow,cut,tmax); del = 0.0; if(xs2 > 0.0) { del = (xs1/xs2 - 1.0)*elow; } //G4cout << "New model k=" << k << " E(MeV)= " << e/MeV // << " Elow(MeV)= " << elow/MeV << " del= " << del << G4endl; } } G4double cross = mod->CrossSection(couple,particle,e,cut,tmax); cross *= (1.0 + del/e); if(fIsCrossSectionPrim == tType) { cross *= e; } if(j==0 && startFromNull) { cross = 0.0; } if(2 < verboseLevel) { G4cout << "FillLambdaVector: " << j << ". e(MeV)= " << e/MeV << " cross(1/mm)= " << cross*mm << " del= " << del*mm << " k= " << k << " modelIdx= " << regModels->ModelIndex(k) << G4endl; } cross = std::max(cross, 0.0); aVector->PutValue(j, cross); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4EmModelManager::DumpModelList(std::ostream& out, G4int verb) { if(verb == 0) { return; } for(G4int i=0; iRegion(); G4int n = r->NumberOfModels(); if(n > 0) { out << " ===== EM models for the G4Region " << reg->GetName() << " ======" << G4endl; for(G4int j=0; jModelIndex(j)]; G4double emin = std::max(r->LowEdgeEnergy(j),model->LowEnergyActivationLimit()); G4double emax = std::min(r->LowEdgeEnergy(j+1),model->HighEnergyActivationLimit()); if(emax > emin) { out << std::setw(20); out << model->GetName() << " : Emin=" << std::setw(5) << G4BestUnit(emin,"Energy") << " Emax=" << std::setw(5) << G4BestUnit(emax,"Energy"); G4PhysicsTable* table = model->GetCrossSectionTable(); if(table) { size_t kk = table->size(); for(size_t k=0; kGetVectorLength() - 1; out << " Nbins=" << nn << " " << std::setw(3) << G4BestUnit(v->Energy(0),"Energy") << " - " << std::setw(3) << G4BestUnit(v->Energy(nn),"Energy"); break; } } } G4VEmAngularDistribution* an = model->GetAngularDistribution(); if(an) { out << " " << an->GetName(); } if(fluoFlag && model->DeexcitationFlag()) { out << " Fluo"; } out << G4endl; G4VMscModel* msc = dynamic_cast(model); if(msc != nullptr) msc->DumpParameters(out); } } } if(1 == nEmModels) { break; } } if(theCutsNew) { out << " ===== Limit on energy threshold has been applied " << G4endl; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....