// // ******************************************************************** // * 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: G4EmModelManager.cc,v 1.46 2008/10/13 14:56:56 vnivanch Exp $ // GEANT4 tag $Name: geant4-09-02-ref-02 $ // // ------------------------------------------------------------------- // // GEANT4 Class file // // // File name: G4EmModelManager // // Author: Vladimir Ivanchenko // // Creation date: 07.05.2002 // // Modifications: // // 23-12-02 V.Ivanchenko change interface in order to move // to cut per region // 20-01-03 Migrade to cut per region (V.Ivanchenko) // 24-01-03 Make models region aware (V.Ivanchenko) // 13-02-03 The set of models is defined for region (V.Ivanchenko) // 06-03-03 Fix in energy intervals for models (V.Ivanchenko) // 13-04-03 Add startFromNull (V.Ivanchenko) // 13-05-03 Add calculation of precise range (V.Ivanchenko) // 16-07-03 Replace G4Material by G4MaterialCutCouple in dE/dx and CrossSection // calculation (V.Ivanchenko) // 21-07-03 Add UpdateEmModel method (V.Ivanchenko) // 03-11-03 Substitute STL vector for G4RegionModels (V.Ivanchenko) // 26-01-04 Fix in energy range conditions (V.Ivanchenko) // 24-03-05 Remove check or IsInCharge (V.Ivanchenko) // 08-04-05 Major optimisation of internal interfaces (V.Ivantchenko) // 18-08-05 Fix cut for e+e- pair production (V.Ivanchenko) // 29-11-05 Add protection for arithmetic operations with cut=DBL_MAX (V.Ivanchenko) // 20-01-06 Introduce G4EmTableType and reducing number of methods (VI) // 13-05-06 Add GetModel by index method (VI) // 15-03-07 Add maxCutInRange (V.Ivanchenko) // 12-04-07 Add verbosity at destruction (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" //....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; iDefineForRegion(r); nEmModels++; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4EmModelManager::UpdateEmModel(const G4String& nam, G4double emin, G4double emax) { if (nEmModels) { 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* m = 0; if(i >= 0 && i < nEmModels) {m = 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 m; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... const G4DataVector* G4EmModelManager::Initialise(const G4ParticleDefinition* p, const G4ParticleDefinition* sp, G4double theMinSubRange, G4int val) { verboseLevel = val; if(1 < verboseLevel) { G4cout << "G4EmModelManager::Initialise() for " << p->GetParticleName() << G4endl; } // Are models defined? if(!nEmModels) { G4Exception("G4EmModelManager::Initialise without any model defined"); } particle = p; secondaryParticle = sp; minSubRange = theMinSubRange; Clear(); 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; jGetTableSize(); idxOfRegionModels = new G4int[numOfCouples+1]; idxOfRegionModels[numOfCouples] = 0; setOfRegionModels = new G4RegionModels*[nRegions]; std::vector modelAtRegion(nEmModels); std::vector modelOrd(nEmModels); G4DataVector eLow(nEmModels); G4DataVector eHigh(nEmModels); G4int nmax = nEmModels; // 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 << G4endl; } if (n == 0) n++; else { tmin = std::min(tmin, eHigh[n-1]); if(tmin >= tmax) push = false; else { // high energy model if(tmin == eHigh[n-1] && tmax > eHigh[n-1]) n++; else if (tmax > eHigh[n-1]) { // compare order of models for(G4int k = n-1; k>=0; k--) { if (ord >= modelOrd[k]) { tmin = std::max(tmin, eHigh[k]); if(k < n-1) n = k + 2; break; } else if (tmin > eLow[k]) { eHigh[k] = tmin; n = k + 2; break; } else if (tmin == eLow[k]) { n = k + 1; break; } } if(tmin < eLow[0]) n = 1; idx = n - 1; // low energy model } else { tmax = std::max(tmax, eLow[0]); insert = true; push = false; idx = 0; if(tmax <= eLow[0]) tmax = eLow[0]; else { for(G4int k=0; k= modelOrd[k]) { if(k == 0) { if(tmin < eLow[0]) tmax = eLow[0]; else insert = false; break; } else { insert = false; break; } } else if(tmax < eHigh[k]) { idx = k; if(k > 0) tmin = eLow[k]; eLow[k] = tmax; break; } else if(tmax == eHigh[k]) { insert = false; push = true; idx = k; if(k > 0) tmin = eLow[k]; else tmin = std::min(tmin,eLow[0]); break; } else { modelAtRegion[k] = ii; modelOrd[k] = ord; if(k == 0) eLow[idx] = std::min(tmin,eLow[0]); } } } if(insert && idx < n) n++; else insert = false; } } } if(n > nmax) { nmax = n; modelAtRegion.resize(nmax); modelOrd.resize(nmax); eLow.resize(nmax); eHigh.resize(nmax); } if(insert) { for(G4int k=n-2; k>=idx; k--) { modelAtRegion[k+1] = modelAtRegion[k]; modelOrd[k+1] = modelOrd[k]; eLow[k+1] = eLow[k]; eHigh[k+1] = eHigh[k]; } } if (push || insert) { modelAtRegion[idx] = ii; modelOrd[idx] = ord; eLow[idx] = tmin; eHigh[idx] = tmax; } } } } else { n = 1; models.push_back(0); modelAtRegion.push_back(nEmModels); eLow.push_back(0.0); eHigh.push_back(DBL_MAX); } eLow[0] = 0.0; if(n >= nmax) eLow.resize(nmax+1); eLow[n] = eHigh[n-1]; if(1 < verboseLevel) { G4cout << "New G4RegionModels set with " << n << " models for region <"; if (region) G4cout << region->GetName(); G4cout << "> Elow(MeV)= "; for(G4int ii=0; ii<=n; ii++) {G4cout << eLow[ii]/MeV << " ";} G4cout << G4endl; } G4RegionModels* rm = new G4RegionModels(n, modelAtRegion, eLow, region); setOfRegionModels[reg] = rm; } // Access to materials and build cuts for(G4int i=0; iGetMaterialCutsCouple(i); const G4Material* material = couple->GetMaterial(); const G4ProductionCuts* pcuts = couple->GetProductionCuts(); G4int reg = nRegions; 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 = DBL_MAX; G4double subcut = DBL_MAX; if(secondaryParticle) { size_t idx = 1; if( secondaryParticle == theGamma ) idx = 0; cut = (*theCoupleTable->GetEnergyCutsVector(idx))[i]; if( secondaryParticle == thePositron && cut < DBL_MAX ) cut += (*theCoupleTable->GetEnergyCutsVector(2))[i] + 2.0*electron_mass_c2; // compute subcut if( cut < DBL_MAX ) subcut = minSubRange*cut; if(pcuts->GetProductionCut(idx) < maxCutInRange) { G4double tcutmax = theCoupleTable->ConvertRangeToEnergy(secondaryParticle, material,maxSubCutInRange); if(tcutmax < subcut) subcut = tcutmax; } } G4int nm = setOfRegionModels[reg]->NumberOfModels(); for(G4int j=0; jModelIndex(j)]; G4double tcutmin = model->MinEnergyCut(particle, couple); if(cut < tcutmin) cut = tcutmin; if(subcut < tcutmin) subcut = tcutmin; if(1 < verboseLevel) { G4cout << "The model # " << j << "; tcutmin(MeV)= " << tcutmin/MeV << "; tcut(MeV)= " << cut/MeV << "; tsubcut(MeV)= " << subcut/MeV << " for " << particle->GetParticleName() << G4endl; } } theCuts.push_back(cut); theSubCuts.push_back(subcut); } for(G4int jj=0; jjInitialise(particle, theCuts); if(flucModels[jj]) flucModels[jj]->InitialiseMe(particle); } if(1 < verboseLevel) { G4cout << "G4EmModelManager for " << particle->GetParticleName() << " is initialised; nRegions= " << nRegions << G4endl; } return &theCuts; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4EmModelManager::FillDEDXVector(G4PhysicsVector* aVector, const G4MaterialCutsCouple* couple, G4EmTableType tType) { G4double e; size_t i = couple->GetIndex(); G4double cut = theCuts[i]; G4double subcut = 0.0; if(fTotal == tType) cut = DBL_MAX; else if(fSubRestricted == tType) subcut = theSubCuts[i]; if(1 < verboseLevel) { G4cout << "G4EmModelManager::FillDEDXVector() for " << couple->GetMaterial()->GetName() << " cut(MeV)= " << cut << " subcut(MeV)= " << subcut << " Type " << tType << " for " << particle->GetParticleName() << G4endl; } G4int reg = idxOfRegionModels[i]; const G4RegionModels* regModels = setOfRegionModels[reg]; G4int nmod = regModels->NumberOfModels(); // vectors to provide continues dE/dx G4DataVector factor(nmod); G4DataVector eLow(nmod+1); G4DataVector dedxLow(nmod); G4DataVector dedxHigh(nmod); if(1 < verboseLevel) { G4cout << "There are " << nmod << " models for " << couple->GetMaterial()->GetName() << " at the region #" << reg << G4endl; } // calculate factors to provide continuity of energy loss factor[0] = 1.0; G4int j; G4int totBinsLoss = aVector->GetVectorLength(); dedxLow[0] = 0.0; eLow[0] = 0.0; e = regModels->LowEdgeEnergy(1); eLow[1] = e; G4VEmModel* model = models[regModels->ModelIndex(0)]; dedxHigh[0] = 0.0; if(model && cut > subcut) { dedxHigh[0] = model->ComputeDEDX(couple,particle,e,cut); if(subcut > 0.0) { dedxHigh[0] -= model->ComputeDEDX(couple,particle,e,subcut); } } if(nmod > 1) { for(j=1; jLowEdgeEnergy(j); eLow[j] = e; G4int idx = regModels->ModelIndex(j); dedxLow[j] = models[idx]->ComputeDEDX(couple,particle,e,cut); if(subcut > 0.0) { dedxLow[j] -= models[idx]->ComputeDEDX(couple,particle,e,subcut); } if(subcut == cut) dedxLow[j] = 0.0; e = regModels->LowEdgeEnergy(j+1); eLow[j+1] = e; dedxHigh[j] = models[idx]->ComputeDEDX(couple,particle,e,cut); if(subcut > 0.0) { dedxHigh[j] -= models[idx]->ComputeDEDX(couple,particle,e,subcut); } if(subcut == cut) dedxHigh[j] = 0.0; } if(1 < verboseLevel) { G4cout << " model #0" << " dedx(" << eLow[0] << ")= " << dedxLow[0] << " dedx(" << eLow[1] << ")= " << dedxHigh[0] << G4endl; } for(j=1; j 0.0) { factor[j] = (dedxHigh[j-1]/dedxLow[j] - 1.0)*eLow[j]; } else factor[j] = 0.0; if(1 < verboseLevel) { G4cout << " model #" << j << " dedx(" << eLow[j] << ")= " << dedxLow[j] << " dedx(" << eLow[j+1] << ")= " << dedxHigh[j] << " factor= " << factor[j]/eLow[j] << G4endl; } } if(2 < verboseLevel) { G4cout << "Loop over " << totBinsLoss << " bins start " << G4endl; } } // Calculate energy losses vector for(j=0; jGetLowEdgeEnergy(j); G4double fac = 1.0; // Choose a model of energy losses G4int k = 0; if (nmod > 1 && e > eLow[1]) { do { k++; fac *= (1.0 + factor[k]/e); } while (k+1 < nmod && e > eLow[k+1]); } model = models[regModels->ModelIndex(k)]; G4double dedx = 0.0; G4double dedx0 = 0.0; if(model && cut > subcut) { dedx = model->ComputeDEDX(couple,particle,e,cut); dedx0 = dedx; if(subcut > 0.0) dedx -= model->ComputeDEDX(couple,particle,e,subcut); dedx *= fac; } if(dedx < 0.0) dedx = 0.0; if(2 < verboseLevel) { G4cout << "Material= " << couple->GetMaterial()->GetName() << " E(MeV)= " << e/MeV << " dEdx(MeV/mm)= " << dedx*mm/MeV << " dEdx0(MeV/mm)= " << dedx0*mm/MeV << " fac= " << fac << G4endl; } aVector->PutValue(j, dedx); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4EmModelManager::FillLambdaVector(G4PhysicsVector* aVector, const G4MaterialCutsCouple* couple, G4bool startFromNull, G4EmTableType tType) { G4double e; size_t i = couple->GetIndex(); G4double cut = theCuts[i]; G4double tmax = DBL_MAX; if (fSubRestricted == tType) { tmax = cut; cut = theSubCuts[i]; } if(1 < verboseLevel) { G4cout << "G4EmModelManager::FillLambdaVector() for particle " << particle->GetParticleName() << " in " << couple->GetMaterial()->GetName() << " Ecut(MeV)= " << cut << " Emax(MeV)= " << tmax << " Type " << tType << G4endl; } G4int reg = idxOfRegionModels[i]; const G4RegionModels* regModels = setOfRegionModels[reg]; G4int nmod = regModels->NumberOfModels(); // vectors to provide continues dE/dx G4DataVector factor(nmod); G4DataVector eLow(nmod+1); G4DataVector sigmaLow(nmod); G4DataVector sigmaHigh(nmod); if(2 < verboseLevel) { G4cout << "There are " << nmod << " models for " << couple->GetMaterial()->GetName() << G4endl; } // calculate factors to provide continuity of energy loss factor[0] = 1.0; G4int j; G4int totBinsLambda = aVector->GetVectorLength(); sigmaLow[0] = 0.0; eLow[0] = 0.0; e = regModels->LowEdgeEnergy(1); eLow[1] = e; G4VEmModel* model = models[regModels->ModelIndex(0)]; sigmaHigh[0] = 0.0; if(model) sigmaHigh[0] = model->CrossSection(couple,particle,e,cut,tmax); if(2 < verboseLevel) { G4cout << "### For material " << couple->GetMaterial()->GetName() << " " << nmod << " models" << " Ecut(MeV)= " << cut/MeV << " Emax(MeV)= " << e/MeV << " nbins= " << totBinsLambda << G4endl; G4cout << " model #0 eUp= " << e << " sigmaUp= " << sigmaHigh[0] << G4endl; } if(nmod > 1) { for(j=1; jLowEdgeEnergy(j); eLow[j] = e; G4int idx = regModels->ModelIndex(j); sigmaLow[j] = models[idx]->CrossSection(couple,particle,e,cut,tmax); e = regModels->LowEdgeEnergy(j+1); eLow[j+1] = e; sigmaHigh[j] = models[idx]->CrossSection(couple,particle,e,cut,tmax); } if(1 < verboseLevel) { G4cout << " model #0" << " sigma(" << eLow[0] << ")= " << sigmaLow[0] << " sigma(" << eLow[1] << ")= " << sigmaHigh[0] << G4endl; } for(j=1; j 0.0) { factor[j] = (sigmaHigh[j-1]/sigmaLow[j] - 1.0)*eLow[j]; } else factor[j] = 0.0; if(1 < verboseLevel) { G4cout << " model #" << j << " sigma(" << eLow[j] << ")= " << sigmaLow[j] << " sigma(" << eLow[j+1] << ")= " << sigmaHigh[j] << " factor= " << factor[j]/eLow[j] << G4endl; } } } // Calculate lambda vector for(j=0; jGetLowEdgeEnergy(j); // Choose a model of energy losses G4int k = 0; G4double fac = 1.0; if (nmod > 1 && e > eLow[1]) { do { k++; fac *= (1.0 + factor[k]/e); } while ( k+1 < nmod && e > eLow[k+1] ); } model = models[regModels->ModelIndex(k)]; G4double cross = 0.0; if(model) cross = model->CrossSection(couple,particle,e,cut,tmax)*fac; if(j==0 && startFromNull) cross = 0.0; if(2 < verboseLevel) { G4cout << "FillLambdaVector: " << j << ". e(MeV)= " << e/MeV << " cross(1/mm)= " << cross*mm << " fac= " << fac << " k= " << k << " model= " << regModels->ModelIndex(k) << G4endl; } if(cross < 0.0) cross = 0.0; aVector->PutValue(j, cross); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4EmModelManager::DumpModelList(G4int verb) { if(verb == 0) return; for(G4int i=0; iRegion(); if(verb > 1 || nRegions > 1) { } G4int n = r->NumberOfModels(); if(verb > 1 || n > 0) { G4cout << " ===== EM models for the G4Region " << reg->GetName() << " ======" << G4endl;; for(G4int j=0; jModelIndex(j)]; G4cout << std::setw(20); G4cout << m->GetName() << " : Emin= " << std::setw(10) << G4BestUnit(r->LowEdgeEnergy(j),"Energy") << " Emax= " << G4BestUnit(r->LowEdgeEnergy(j+1),"Energy") << G4endl; } } } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....