// // ******************************************************************** // * 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: G4VEmProcess // // Author: Vladimir Ivanchenko on base of Laszlo Urban code // // Creation date: 01.10.2003 // // Modifications: by V.Ivanchenko // // Class Description: based class for discrete and rest/discrete EM processes // // ------------------------------------------------------------------- // //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... #include "G4VEmProcess.hh" #include "G4PhysicalConstants.hh" #include "G4SystemOfUnits.hh" #include "G4ProcessManager.hh" #include "G4LossTableManager.hh" #include "G4LossTableBuilder.hh" #include "G4Step.hh" #include "G4ParticleDefinition.hh" #include "G4VEmModel.hh" #include "G4DataVector.hh" #include "G4PhysicsTable.hh" #include "G4EmDataHandler.hh" #include "G4PhysicsLogVector.hh" #include "G4VParticleChange.hh" #include "G4ProductionCutsTable.hh" #include "G4Region.hh" #include "G4Gamma.hh" #include "G4Electron.hh" #include "G4Positron.hh" #include "G4PhysicsTableHelper.hh" #include "G4EmBiasingManager.hh" #include "G4GenericIon.hh" #include "G4Log.hh" #include //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VEmProcess::G4VEmProcess(const G4String& name, G4ProcessType type): G4VDiscreteProcess(name, type), secondaryParticle(nullptr), buildLambdaTable(true), numberOfModels(0), theLambdaTable(nullptr), theLambdaTablePrim(nullptr), integral(false), applyCuts(false), startFromNull(false), splineFlag(true), isIon(false), currentCouple(nullptr), isTheMaster(true), masterProc(nullptr), theData(nullptr), currentModel(nullptr), particle(nullptr), currentParticle(nullptr) { theParameters = G4EmParameters::Instance(); SetVerboseLevel(1); // Size of tables assuming spline minKinEnergy = 0.1*keV; maxKinEnergy = 100.0*TeV; nLambdaBins = 84; minKinEnergyPrim = DBL_MAX; actBinning = actSpline = actMinKinEnergy = actMaxKinEnergy = false; // default lambda factor lambdaFactor = 0.8; logLambdaFactor = G4Log(lambdaFactor); // default limit on polar angle biasFactor = fFactor = 1.0; // particle types theGamma = G4Gamma::Gamma(); theElectron = G4Electron::Electron(); thePositron = G4Positron::Positron(); theCuts = theCutsGamma = theCutsElectron = theCutsPositron = nullptr; pParticleChange = &fParticleChange; fParticleChange.SetSecondaryWeightByProcess(true); secParticles.reserve(5); baseMaterial = currentMaterial = nullptr; preStepLambda = preStepKinEnergy = 0.0; preStepLogKinEnergy = LOG_EKIN_MIN; mfpKinEnergy = DBL_MAX; massRatio = 1.0; currentCoupleIndex = basedCoupleIndex = 0; modelManager = new G4EmModelManager(); biasManager = nullptr; biasFlag = false; weightFlag = false; lManager = G4LossTableManager::Instance(); lManager->Register(this); G4LossTableBuilder* bld = lManager->GetTableBuilder(); theDensityFactor = bld->GetDensityFactors(); theDensityIdx = bld->GetCoupleIndexes(); secID = fluoID = augerID = biasID = -1; mainSecondaries = 100; if("phot" == GetProcessName() || "compt" == GetProcessName() || "e-_G4DNAIonisation" == GetProcessName() || "hydrogen_G4DNAIonisation" == GetProcessName() || "helium_G4DNAIonisation" == GetProcessName() || "alpha_G4DNAIonisation" == GetProcessName() || "alpha+_G4DNAIonisation" == GetProcessName() || "proton_G4DNAIonisation" == GetProcessName() || "GenericIon_G4DNAIonisation" == GetProcessName() ) { mainSecondaries = 1; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VEmProcess::~G4VEmProcess() { /* if(1 < verboseLevel) { G4cout << "G4VEmProcess destruct " << GetProcessName() << " " << this << " " << theLambdaTable <DeRegister(this); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::Clear() { currentCouple = nullptr; preStepLambda = 0.0; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VEmProcess::MinPrimaryEnergy(const G4ParticleDefinition*, const G4Material*) { return 0.0; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::AddEmModel(G4int order, G4VEmModel* p, const G4Region* region) { G4VEmFluctuationModel* fm = nullptr; modelManager->AddEmModel(order, p, fm, region); if(p) { p->SetParticleChange(pParticleChange); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::SetEmModel(G4VEmModel* ptr, G4int) { for(auto & em : emModels) { if(em == ptr) { return; } } emModels.push_back(ptr); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VEmModel* G4VEmProcess::EmModel(size_t index) const { return (index < emModels.size()) ? emModels[index] : nullptr; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::UpdateEmModel(const G4String& nam, G4double emin, G4double emax) { modelManager->UpdateEmModel(nam, emin, emax); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4int G4VEmProcess::GetNumberOfModels() const { return modelManager->NumberOfModels(); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4int G4VEmProcess::GetNumberOfRegionModels(size_t couple_index) const { return modelManager->NumberOfRegionModels(couple_index); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VEmModel* G4VEmProcess::GetRegionModel(G4int idx, size_t couple_index) const { return modelManager->GetRegionModel(idx, couple_index); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VEmModel* G4VEmProcess::GetModelByIndex(G4int idx, G4bool ver) const { return modelManager->GetModel(idx, ver); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::PreparePhysicsTable(const G4ParticleDefinition& part) { isTheMaster = lManager->IsMaster(); if(!particle) { SetParticle(&part); } if(part.GetParticleType() == "nucleus" && part.GetParticleSubType() == "generic") { G4String pname = part.GetParticleName(); if(pname != "deuteron" && pname != "triton" && pname != "alpha" && pname != "He3" && pname != "alpha+" && pname != "helium" && pname != "hydrogen") { particle = G4GenericIon::GenericIon(); isIon = true; } } if(1 < verboseLevel) { G4cout << "G4VEmProcess::PreparePhysicsTable() for " << GetProcessName() << " and particle " << part.GetParticleName() << " local particle " << particle->GetParticleName() << G4endl; } if(particle != &part) { return; } G4LossTableBuilder* bld = lManager->GetTableBuilder(); lManager->PreparePhysicsTable(&part, this, isTheMaster); Clear(); InitialiseProcess(particle); const G4ProductionCutsTable* theCoupleTable= G4ProductionCutsTable::GetProductionCutsTable(); size_t n = theCoupleTable->GetTableSize(); theEnergyOfCrossSectionMax.resize(n, 0.0); theCrossSectionMax.resize(n, DBL_MAX); // initialisation of the process if(!actMinKinEnergy) { minKinEnergy = theParameters->MinKinEnergy(); } if(!actMaxKinEnergy) { maxKinEnergy = theParameters->MaxKinEnergy(); } if(!actSpline) { splineFlag = theParameters->Spline(); } if(isTheMaster) { SetVerboseLevel(theParameters->Verbose()); if(!theData) { theData = new G4EmDataHandler(2); } } else { SetVerboseLevel(theParameters->WorkerVerbose()); } applyCuts = theParameters->ApplyCuts(); lambdaFactor = theParameters->LambdaFactor(); logLambdaFactor = G4Log(lambdaFactor); theParameters->DefineRegParamForEM(this); // initialisation of models numberOfModels = modelManager->NumberOfModels(); for(G4int i=0; iGetModel(i); if(0 == i) { currentModel = mod; } mod->SetPolarAngleLimit(theParameters->MscThetaLimit()); mod->SetMasterThread(isTheMaster); if(mod->HighEnergyLimit() > maxKinEnergy) { mod->SetHighEnergyLimit(maxKinEnergy); } } if(lManager->AtomDeexcitation()) { modelManager->SetFluoFlag(true); } theCuts = modelManager->Initialise(particle,secondaryParticle, 2.,verboseLevel); theCutsGamma = theCoupleTable->GetEnergyCutsVector(idxG4GammaCut); theCutsElectron = theCoupleTable->GetEnergyCutsVector(idxG4ElectronCut); theCutsPositron = theCoupleTable->GetEnergyCutsVector(idxG4PositronCut); // prepare tables if(buildLambdaTable && isTheMaster){ theLambdaTable = theData->MakeTable(0); bld->InitialiseBaseMaterials(theLambdaTable); } // high energy table if(isTheMaster && minKinEnergyPrim < maxKinEnergy){ theLambdaTablePrim = theData->MakeTable(1); bld->InitialiseBaseMaterials(theLambdaTablePrim); } bld->InitialiseBaseMaterials(); // forced biasing if(biasManager) { biasManager->Initialise(part,GetProcessName(),verboseLevel); biasFlag = false; } // defined ID of secondary particles G4String nam1 = GetProcessName(); secID = G4PhysicsModelCatalog::Register(nam1); if(100 > mainSecondaries) { G4String nam2 = nam1 + "_fluo" ; G4String nam3 = nam1 + "_auger"; G4String nam4 = nam1 + "_split"; fluoID = G4PhysicsModelCatalog::Register(nam2); augerID = G4PhysicsModelCatalog::Register(nam3); biasID = G4PhysicsModelCatalog::Register(nam4); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::BuildPhysicsTable(const G4ParticleDefinition& part) { if(!masterProc) { if(isTheMaster) { masterProc = this; } else { masterProc = static_cast(GetMasterProcess());} } G4String num = part.GetParticleName(); if(1 < verboseLevel) { G4cout << "### G4VEmProcess::BuildPhysicsTable() for " << GetProcessName() << " and particle " << num << " buildLambdaTable= " << buildLambdaTable << " isTheMaster= " << isTheMaster << " " << masterProc << G4endl; } if(particle == &part) { // worker initialisation if(!isTheMaster) { theLambdaTable = masterProc->LambdaTable(); theLambdaTablePrim = masterProc->LambdaTablePrim(); if(theLambdaTable) { FindLambdaMax(); } // local initialisation of models G4bool printing = true; numberOfModels = modelManager->NumberOfModels(); for(G4int i=0; iGetModelByIndex(i, printing); //G4cout << i << ". " << mod << " " << mod0 << " " // << particle->GetParticleName() << G4endl; mod->InitialiseLocal(particle, mod0); } // master thread } else { if(buildLambdaTable || minKinEnergyPrim < maxKinEnergy) { BuildLambdaTable(); } } } // explicitly defined printout by particle name if(1 < verboseLevel || (0 < verboseLevel && (num == "gamma" || num == "e-" || num == "e+" || num == "mu+" || num == "mu-" || num == "proton"|| num == "pi+" || num == "pi-" || num == "kaon+" || num == "kaon-" || num == "alpha" || num == "anti_proton" || num == "GenericIon"|| num == "alpha++" || num == "alpha+" || num == "helium" || num == "hydrogen"))) { StreamInfo(G4cout, part); } if(1 < verboseLevel) { G4cout << "### G4VEmProcess::BuildPhysicsTable() done for " << GetProcessName() << " and particle " << num << G4endl; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::BuildLambdaTable() { if(1 < verboseLevel) { G4cout << "G4EmProcess::BuildLambdaTable() for process " << GetProcessName() << " and particle " << particle->GetParticleName() << " " << this << G4endl; } // Access to materials const G4ProductionCutsTable* theCoupleTable= G4ProductionCutsTable::GetProductionCutsTable(); size_t numOfCouples = theCoupleTable->GetTableSize(); G4LossTableBuilder* bld = lManager->GetTableBuilder(); G4PhysicsLogVector* aVector = nullptr; G4PhysicsLogVector* aVectorPrim = nullptr; G4PhysicsLogVector* bVectorPrim = nullptr; G4double scale = theParameters->MaxKinEnergy()/theParameters->MinKinEnergy(); G4int nbin = theParameters->NumberOfBinsPerDecade()*G4lrint(std::log10(scale)); scale = G4Log(scale); if(actBinning) { nbin = std::max(nbin, nLambdaBins); } G4double emax1 = std::min(maxKinEnergy, minKinEnergyPrim); for(size_t i=0; iGetFlag(i)) { // create physics vector and fill it const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(i); // build main table if(buildLambdaTable) { delete (*theLambdaTable)[i]; // if start from zero then change the scale G4double emin = minKinEnergy; G4bool startNull = false; if(startFromNull) { G4double e = MinPrimaryEnergy(particle,couple->GetMaterial()); if(e >= emin) { emin = e; startNull = true; } } G4double emax = emax1; if(emax <= emin) { emax = 2*emin; } G4int bin = G4lrint(nbin*G4Log(emax/emin)/scale); if(bin < 3) { bin = 3; } aVector = new G4PhysicsLogVector(emin, emax, bin); aVector->SetSpline(splineFlag); modelManager->FillLambdaVector(aVector, couple, startNull); if(splineFlag) { aVector->FillSecondDerivatives(); } G4PhysicsTableHelper::SetPhysicsVector(theLambdaTable, i, aVector); } // build high energy table if(minKinEnergyPrim < maxKinEnergy) { delete (*theLambdaTablePrim)[i]; // start not from zero if(!bVectorPrim) { G4int bin = G4lrint(nbin*G4Log(maxKinEnergy/minKinEnergyPrim)/scale); if(bin < 3) { bin = 3; } aVectorPrim = new G4PhysicsLogVector(minKinEnergyPrim, maxKinEnergy, bin); bVectorPrim = aVectorPrim; } else { aVectorPrim = new G4PhysicsLogVector(*bVectorPrim); } // always use spline aVectorPrim->SetSpline(splineFlag); modelManager->FillLambdaVector(aVectorPrim, couple, false, fIsCrossSectionPrim); aVectorPrim->FillSecondDerivatives(); G4PhysicsTableHelper::SetPhysicsVector(theLambdaTablePrim, i, aVectorPrim); } } } if(buildLambdaTable) { FindLambdaMax(); } if(1 < verboseLevel) { G4cout << "Lambda table is built for " << particle->GetParticleName() << G4endl; } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::StreamInfo(std::ostream& out, const G4ParticleDefinition& part, G4bool rst) const { G4String indent = (rst ? " " : ""); out << std::setprecision(6); out << G4endl << indent << GetProcessName() << ": "; if (!rst) { out << " for " << part.GetParticleName(); if (integral) { out << ","; } } if(integral) { out << " integral:1 "; } if(applyCuts) { out << " applyCuts:1 "; } out << " SubType=" << GetProcessSubType(); if(biasFactor != 1.0) { out << " BiasingFactor= " << biasFactor; } out << " BuildTable=" << buildLambdaTable << G4endl; if(buildLambdaTable) { if(particle == &part) { size_t length = theLambdaTable->length(); for(size_t i=0; iEnergy(0); G4double emax = v->GetMaxEnergy(); G4int nbin = v->GetVectorLength() - 1; if(emin > minKinEnergy) { out << "threshold "; } else { out << G4BestUnit(emin,"Energy"); } out << " to " << G4BestUnit(emax,"Energy") << ", " << G4lrint(nbin/std::log10(emax/emin)) << " bins/decade, spline: " << splineFlag << G4endl; break; } } } else { out << " Used Lambda table of " << particle->GetParticleName() << G4endl; } } if(minKinEnergyPrim < maxKinEnergy) { if(particle == &part) { size_t length = theLambdaTablePrim->length(); for(size_t i=0; iEnergy(0),"Energy") << " to " << G4BestUnit(v->GetMaxEnergy(),"Energy") << " in " << v->GetVectorLength()-1 << " bins " << G4endl; break; } } } else { out << " Used LambdaPrime table of " << particle->GetParticleName() << G4endl; } } StreamProcessInfo(out); modelManager->DumpModelList(out, verboseLevel); if(verboseLevel > 2 && buildLambdaTable) { out << " LambdaTable address= " << theLambdaTable << G4endl; if(theLambdaTable && particle == &part) { out << (*theLambdaTable) << G4endl; } } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::StartTracking(G4Track* track) { // reset parameters for the new track theNumberOfInteractionLengthLeft = -1.0; mfpKinEnergy = DBL_MAX; if(isIon) { massRatio = proton_mass_c2/currentParticle->GetPDGMass(); } // forced biasing only for primary particles if(biasManager) { if(0 == track->GetParentID()) { // primary particle biasFlag = true; biasManager->ResetForcedInteraction(); } } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VEmProcess::PostStepGetPhysicalInteractionLength( const G4Track& track, G4double previousStepSize, G4ForceCondition* condition) { *condition = NotForced; G4double x = DBL_MAX; DefineMaterial(track.GetMaterialCutsCouple()); preStepKinEnergy = track.GetKineticEnergy(); preStepLogKinEnergy = track.GetDynamicParticle()->GetLogKineticEnergy(); G4double scaledEnergy = preStepKinEnergy*massRatio; SelectModel(scaledEnergy, currentCoupleIndex); if(!currentModel->IsActive(scaledEnergy)) { theNumberOfInteractionLengthLeft = -1.0; currentInteractionLength = DBL_MAX; return x; } // forced biasing only for primary particles if(biasManager) { if(0 == track.GetParentID()) { if(biasFlag && biasManager->ForcedInteractionRegion(currentCoupleIndex)) { return biasManager->GetStepLimit(currentCoupleIndex, previousStepSize); } } } // compute mean free path if(preStepKinEnergy < mfpKinEnergy) { if (integral) { ComputeIntegralLambda(preStepKinEnergy, preStepLogKinEnergy); } else { preStepLambda = GetCurrentLambda(preStepKinEnergy, preStepLogKinEnergy); } // zero cross section if(preStepLambda <= 0.0) { theNumberOfInteractionLengthLeft = -1.0; currentInteractionLength = DBL_MAX; } } // non-zero cross section if(preStepLambda > 0.0) { if (theNumberOfInteractionLengthLeft < 0.0) { // beggining of tracking (or just after DoIt of this process) theNumberOfInteractionLengthLeft = -G4Log( G4UniformRand() ); theInitialNumberOfInteractionLength = theNumberOfInteractionLengthLeft; } else if(currentInteractionLength < DBL_MAX) { theNumberOfInteractionLengthLeft -= previousStepSize/currentInteractionLength; theNumberOfInteractionLengthLeft = std::max(theNumberOfInteractionLengthLeft, 0.0); } // new mean free path and step limit for the next step currentInteractionLength = 1.0/preStepLambda; x = theNumberOfInteractionLengthLeft * currentInteractionLength; } return x; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::ComputeIntegralLambda(G4double e, G4double loge) { // condition to skip recomputation of cross section const G4double epeak = theEnergyOfCrossSectionMax[currentCoupleIndex]; if(e <= epeak && e/lambdaFactor >= mfpKinEnergy) { return; } // recomputation is needed if (e <= epeak) { preStepLambda = GetCurrentLambda(e, loge); mfpKinEnergy = e; } else { const G4double e1 = e*lambdaFactor; if (e1 > epeak) { preStepLambda = GetCurrentLambda(e, loge); mfpKinEnergy = e; const G4double preStepLambda1 = GetCurrentLambda(e1,loge+logLambdaFactor); if (preStepLambda1 > preStepLambda) { mfpKinEnergy = e1; preStepLambda = preStepLambda1; } } else { preStepLambda = fFactor*theCrossSectionMax[currentCoupleIndex]; mfpKinEnergy = epeak; } } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VParticleChange* G4VEmProcess::PostStepDoIt(const G4Track& track, const G4Step& step) { // In all cases clear number of interaction lengths theNumberOfInteractionLengthLeft = -1.0; mfpKinEnergy = DBL_MAX; fParticleChange.InitializeForPostStep(track); // Do not make anything if particle is stopped, the annihilation then // should be performed by the AtRestDoIt! if (track.GetTrackStatus() == fStopButAlive) { return &fParticleChange; } const G4double finalT = track.GetKineticEnergy(); const G4double logFinalT = track.GetDynamicParticle()->GetLogKineticEnergy(); // forced process - should happen only once per track if(biasFlag) { if(biasManager->ForcedInteractionRegion(currentCoupleIndex)) { biasFlag = false; } } // Integral approach if (integral) { G4double lx = GetLambda(finalT, currentCouple, logFinalT); if(preStepLambdaGetParticleName() << " and " << GetProcessName() << " E(MeV)= " << finalT/MeV << " preLambda= " << preStepLambda << " < " << lx << " (postLambda) " << G4endl; } if(preStepLambda*G4UniformRand() > lx) { ClearNumberOfInteractionLengthLeft(); return &fParticleChange; } } G4double scaledEnergy = finalT*massRatio; SelectModel(scaledEnergy, currentCoupleIndex); if(!currentModel->IsActive(scaledEnergy)) { return &fParticleChange; } // define new weight for primary and secondaries G4double weight = fParticleChange.GetParentWeight(); if(weightFlag) { weight /= biasFactor; fParticleChange.ProposeWeight(weight); } if(1 < verboseLevel) { G4cout << "G4VEmProcess::PostStepDoIt: Sample secondary; E= " << finalT/MeV << " MeV; model= (" << currentModel->LowEnergyLimit() << ", " << currentModel->HighEnergyLimit() << ")" << G4endl; } // sample secondaries secParticles.clear(); currentModel->SampleSecondaries(&secParticles, currentCouple, track.GetDynamicParticle(), (*theCuts)[currentCoupleIndex]); G4int num0 = secParticles.size(); // splitting or Russian roulette if(biasManager) { if(biasManager->SecondaryBiasingRegion(currentCoupleIndex)) { G4double eloss = 0.0; weight *= biasManager->ApplySecondaryBiasing( secParticles, track, currentModel, &fParticleChange, eloss, currentCoupleIndex, (*theCuts)[currentCoupleIndex], step.GetPostStepPoint()->GetSafety()); if(eloss > 0.0) { eloss += fParticleChange.GetLocalEnergyDeposit(); fParticleChange.ProposeLocalEnergyDeposit(eloss); } } } // save secondaries G4int num = secParticles.size(); if(num > 0) { fParticleChange.SetNumberOfSecondaries(num); G4double edep = fParticleChange.GetLocalEnergyDeposit(); G4double time = track.GetGlobalTime(); for (G4int i=0; iGetParticleDefinition(); G4double e = dp->GetKineticEnergy(); G4bool good = true; if(applyCuts) { if (p == theGamma) { if (e < (*theCutsGamma)[currentCoupleIndex]) { good = false; } } else if (p == theElectron) { if (e < (*theCutsElectron)[currentCoupleIndex]) { good = false; } } else if (p == thePositron) { if (electron_mass_c2 < (*theCutsGamma)[currentCoupleIndex] && e < (*theCutsPositron)[currentCoupleIndex]) { good = false; e += 2.0*electron_mass_c2; } } // added secondary if it is good } if (good) { G4Track* t = new G4Track(dp, time, track.GetPosition()); t->SetTouchableHandle(track.GetTouchableHandle()); if (biasManager) { t->SetWeight(weight * biasManager->GetWeight(i)); } else { t->SetWeight(weight); } pParticleChange->AddSecondary(t); // define type of secondary if(i < mainSecondaries) { t->SetCreatorModelIndex(secID); } else if(i < num0) { if(p == theGamma) { t->SetCreatorModelIndex(fluoID); } else { t->SetCreatorModelIndex(augerID); } } else { t->SetCreatorModelIndex(biasID); } /* G4cout << "Secondary(post step) has weight " << t->GetWeight() << ", Ekin= " << t->GetKineticEnergy()/MeV << " MeV " << GetProcessName() << " fluoID= " << fluoID << " augerID= " << augerID <GetProcessManager()->GetAtRestProcessVector()->size() > 0) { fParticleChange.ProposeTrackStatus(fStopButAlive); } else { fParticleChange.ProposeTrackStatus(fStopAndKill); } } return &fParticleChange; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4bool G4VEmProcess::StorePhysicsTable(const G4ParticleDefinition* part, const G4String& directory, G4bool ascii) { G4bool yes = true; if(!isTheMaster) { return yes; } if ( theLambdaTable && part == particle) { const G4String& nam = GetPhysicsTableFileName(part,directory,"Lambda",ascii); yes = theLambdaTable->StorePhysicsTable(nam,ascii); if ( yes ) { G4cout << "Physics table is stored for " << particle->GetParticleName() << " and process " << GetProcessName() << " in the directory <" << directory << "> " << G4endl; } else { G4cout << "Fail to store Physics Table for " << particle->GetParticleName() << " and process " << GetProcessName() << " in the directory <" << directory << "> " << G4endl; } } if ( theLambdaTablePrim && part == particle) { const G4String& name = GetPhysicsTableFileName(part,directory,"LambdaPrim",ascii); yes = theLambdaTablePrim->StorePhysicsTable(name,ascii); if ( yes ) { G4cout << "Physics table prim is stored for " << particle->GetParticleName() << " and process " << GetProcessName() << " in the directory <" << directory << "> " << G4endl; } else { G4cout << "Fail to store Physics Table Prim for " << particle->GetParticleName() << " and process " << GetProcessName() << " in the directory <" << directory << "> " << G4endl; } } return yes; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo..... G4bool G4VEmProcess::RetrievePhysicsTable(const G4ParticleDefinition* part, const G4String& directory, G4bool ascii) { if(1 < verboseLevel) { G4cout << "G4VEmProcess::RetrievePhysicsTable() for " << part->GetParticleName() << " and process " << GetProcessName() << G4endl; } G4bool yes = true; if((!buildLambdaTable && minKinEnergyPrim > maxKinEnergy) || particle != part) { return yes; } const G4String particleName = part->GetParticleName(); if(buildLambdaTable) { const G4String& filename = GetPhysicsTableFileName(part,directory,"Lambda",ascii); yes = G4PhysicsTableHelper::RetrievePhysicsTable(theLambdaTable, filename,ascii); if ( yes ) { if (0 < verboseLevel) { G4cout << "Lambda table for " << particleName << " is Retrieved from <" << filename << ">" << G4endl; } if(theParameters->Spline()) { size_t n = theLambdaTable->length(); for(size_t i=0; iSetSpline(true); } } } } else { if (1 < verboseLevel) { G4cout << "Lambda table for " << particleName << " in file <" << filename << "> is not exist" << G4endl; } } } if(minKinEnergyPrim < maxKinEnergy) { const G4String& filename = GetPhysicsTableFileName(part,directory,"LambdaPrim",ascii); yes = G4PhysicsTableHelper::RetrievePhysicsTable(theLambdaTablePrim, filename,ascii); if ( yes ) { if (0 < verboseLevel) { G4cout << "Lambda table prim for " << particleName << " is Retrieved from <" << filename << ">" << G4endl; } if(theParameters->Spline()) { size_t n = theLambdaTablePrim->length(); for(size_t i=0; iSetSpline(true); } } } } else { if (1 < verboseLevel) { G4cout << "Lambda table prim for " << particleName << " in file <" << filename << "> is not exist" << G4endl; } } } return yes; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VEmProcess::CrossSectionPerVolume(G4double kineticEnergy, const G4MaterialCutsCouple* couple, G4double logKinEnergy) { // Cross section per atom is calculated DefineMaterial(couple); G4double cross = 0.0; if(buildLambdaTable) { cross = GetCurrentLambda(kineticEnergy, (logKinEnergy < DBL_MAX) ? logKinEnergy : G4Log(kineticEnergy)); } else { SelectModel(kineticEnergy, currentCoupleIndex); if(currentModel) { cross = fFactor*currentModel->CrossSectionPerVolume(currentMaterial, currentParticle, kineticEnergy); } } return std::max(cross, 0.0); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VEmProcess::GetMeanFreePath(const G4Track& track, G4double, G4ForceCondition* condition) { *condition = NotForced; return G4VEmProcess::MeanFreePath(track); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VEmProcess::MeanFreePath(const G4Track& track) { const G4double kinEnergy = track.GetKineticEnergy(); CurrentSetup(track.GetMaterialCutsCouple(), kinEnergy); const G4double xs = GetCurrentLambda(kinEnergy, track.GetDynamicParticle()->GetLogKineticEnergy()); return (0.0 < xs) ? 1.0/xs : DBL_MAX; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VEmProcess::ComputeCrossSectionPerAtom(G4double kinEnergy, G4double Z, G4double A, G4double cut) { SelectModel(kinEnergy, currentCoupleIndex); return (currentModel) ? currentModel->ComputeCrossSectionPerAtom(currentParticle, kinEnergy, Z, A, cut) : 0.0; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::FindLambdaMax() { if(1 < verboseLevel) { G4cout << "### G4VEmProcess::FindLambdaMax: " << particle->GetParticleName() << " and process " << GetProcessName() << " " << G4endl; } size_t n = theLambdaTable->length(); G4PhysicsVector* pv; G4double e, ss, emax, smax; size_t i; // first loop on existing vectors for (i=0; iGetVectorLength(); emax = DBL_MAX; smax = 0.0; if(nb > 0) { for (size_t j=0; jEnergy(j); ss = (*pv)(j); if(ss > smax) { smax = ss; emax = e; } } } theEnergyOfCrossSectionMax[i] = emax; theCrossSectionMax[i] = smax; if(1 < verboseLevel) { G4cout << "For " << particle->GetParticleName() << " Max CS at i= " << i << " emax(MeV)= " << emax/MeV << " lambda= " << smax << G4endl; } } } // second loop using base materials for (i=0; iSetSpline(theParameters->Spline()); return v; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... const G4Element* G4VEmProcess::GetCurrentElement() const { const G4Element* elm = (currentModel) ? currentModel->GetCurrentElement() : nullptr; return elm; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::SetCrossSectionBiasingFactor(G4double f, G4bool flag) { if(f > 0.0) { biasFactor = f; weightFlag = flag; if(1 < verboseLevel) { G4cout << "### SetCrossSectionBiasingFactor: for " << particle->GetParticleName() << " and process " << GetProcessName() << " biasFactor= " << f << " weightFlag= " << flag << G4endl; } } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::ActivateForcedInteraction(G4double length, const G4String& r, G4bool flag) { if(!biasManager) { biasManager = new G4EmBiasingManager(); } if(1 < verboseLevel) { G4cout << "### ActivateForcedInteraction: for " << particle->GetParticleName() << " and process " << GetProcessName() << " length(mm)= " << length/mm << " in G4Region <" << r << "> weightFlag= " << flag << G4endl; } weightFlag = flag; biasManager->ActivateForcedInteraction(length, r); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::ActivateSecondaryBiasing(const G4String& region, G4double factor, G4double energyLimit) { if (0.0 <= factor) { // Range cut can be applied only for e- if(0.0 == factor && secondaryParticle != G4Electron::Electron()) { return; } if(!biasManager) { biasManager = new G4EmBiasingManager(); } biasManager->ActivateSecondaryBiasing(region, factor, energyLimit); if(1 < verboseLevel) { G4cout << "### ActivateSecondaryBiasing: for " << " process " << GetProcessName() << " factor= " << factor << " in G4Region <" << region << "> energyLimit(MeV)= " << energyLimit/MeV << G4endl; } } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::SetLambdaBinning(G4int n) { if(5 < n && n < 10000000) { nLambdaBins = n; actBinning = true; } else { G4double e = (G4double)n; PrintWarning("SetLambdaBinning", e); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::SetMinKinEnergy(G4double e) { if(1.e-3*eV < e && e < maxKinEnergy) { nLambdaBins = G4lrint(nLambdaBins*G4Log(maxKinEnergy/e) /G4Log(maxKinEnergy/minKinEnergy)); minKinEnergy = e; actMinKinEnergy = true; } else { PrintWarning("SetMinKinEnergy", e); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::SetMaxKinEnergy(G4double e) { if(minKinEnergy < e && e < 1.e+6*TeV) { nLambdaBins = G4lrint(nLambdaBins*G4Log(e/minKinEnergy) /G4Log(maxKinEnergy/minKinEnergy)); maxKinEnergy = e; actMaxKinEnergy = true; } else { PrintWarning("SetMaxKinEnergy", e); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::SetMinKinEnergyPrim(G4double e) { if(theParameters->MinKinEnergy() <= e && e <= theParameters->MaxKinEnergy()) { minKinEnergyPrim = e; } else { PrintWarning("SetMinKinEnergyPrim", e); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4VEmProcess* G4VEmProcess::GetEmProcess(const G4String& nam) { return (nam == GetProcessName()) ? this : nullptr; } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... G4double G4VEmProcess::GetLambda(G4double kinEnergy, const G4MaterialCutsCouple* couple) { CurrentSetup(couple, kinEnergy); return GetCurrentLambda(kinEnergy, G4Log(kinEnergy)); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::PrintWarning(G4String tit, G4double val) { G4String ss = "G4VEmProcess::" + tit; G4ExceptionDescription ed; ed << "Parameter is out of range: " << val << " it will have no effect!\n" << " Process " << GetProcessName() << " nbins= " << theParameters->NumberOfBins() << " Emin(keV)= " << theParameters->MinKinEnergy()/keV << " Emax(GeV)= " << theParameters->MaxKinEnergy()/GeV; G4Exception(ss, "em0044", JustWarning, ed); } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.... void G4VEmProcess::ProcessDescription(std::ostream& out) const { if(particle) { StreamInfo(out, *particle, true); } } //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....