Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4VEnergyLossProcess.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// -------------------------------------------------------------------
27//
28// GEANT4 Class file
29//
30//
31// File name: G4VEnergyLossProcess
32//
33// Author: Vladimir Ivanchenko
34//
35// Creation date: 03.01.2002
36//
37// Modifications: Vladimir Ivanchenko
38//
39//
40// Class Description:
41//
42// It is the unified energy loss process it calculates the continuous
43// energy loss for charged particles using a set of Energy Loss
44// models valid for different energy regions. There are a possibility
45// to create and access to dE/dx and range tables, or to calculate
46// that information on fly.
47// -------------------------------------------------------------------
48//
49//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
50//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
51
54#include "G4SystemOfUnits.hh"
55#include "G4ProcessManager.hh"
56#include "G4LossTableManager.hh"
57#include "G4LossTableBuilder.hh"
58#include "G4Step.hh"
60#include "G4ParticleTable.hh"
61#include "G4EmParameters.hh"
62#include "G4EmUtility.hh"
63#include "G4EmTableUtil.hh"
64#include "G4VEmModel.hh"
66#include "G4DataVector.hh"
67#include "G4PhysicsLogVector.hh"
68#include "G4VParticleChange.hh"
69#include "G4Electron.hh"
70#include "G4ProcessManager.hh"
71#include "G4UnitsTable.hh"
72#include "G4Region.hh"
73#include "G4RegionStore.hh"
75#include "G4SafetyHelper.hh"
76#include "G4EmDataHandler.hh"
79#include "G4VSubCutProducer.hh"
80#include "G4EmBiasingManager.hh"
81#include "G4Log.hh"
82#include <iostream>
83
84//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
85
86namespace
87{
88 G4String tnames[7] =
89 {"DEDX","Ionisation","DEDXnr","CSDARange","Lambda","Range","InverseRange"};
90}
91
92
94 G4ProcessType type):
96{
97 theParameters = G4EmParameters::Instance();
99
100 // low energy limit
101 lowestKinEnergy = theParameters->LowestElectronEnergy();
102
103 // Size of tables
104 minKinEnergy = 0.1*CLHEP::keV;
105 maxKinEnergy = 100.0*CLHEP::TeV;
106 maxKinEnergyCSDA = 1.0*CLHEP::GeV;
107 nBins = 84;
108 nBinsCSDA = 35;
109
110 invLambdaFactor = 1.0/lambdaFactor;
111
112 // default linear loss limit
113 finalRange = 1.*CLHEP::mm;
114
115 // run time objects
117 fParticleChange.SetSecondaryWeightByProcess(true);
118 modelManager = new G4EmModelManager();
120 ->GetSafetyHelper();
121 aGPILSelection = CandidateForSelection;
122
123 // initialise model
124 lManager = G4LossTableManager::Instance();
125 lManager->Register(this);
126 isMaster = lManager->IsMaster();
127
128 G4LossTableBuilder* bld = lManager->GetTableBuilder();
129 theDensityFactor = bld->GetDensityFactors();
130 theDensityIdx = bld->GetCoupleIndexes();
131 theFluctuationFlags = bld->GetFluctuationFlags();
132
133 scTracks.reserve(10);
134 secParticles.reserve(12);
135 emModels = new std::vector<G4VEmModel*>;
136}
137
138//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
139
141{
142 if (isMaster) {
143 delete theEnergyOfCrossSectionMax;
144 if(nullptr != fXSpeaks) {
145 for(auto const & v : *fXSpeaks) { delete v; }
146 delete fXSpeaks;
147 }
148 }
149 delete modelManager;
150 delete biasManager;
151 delete scoffRegions;
152 delete emModels;
153 lManager->DeRegister(this);
154}
155
156//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
157
159 const G4Material*,
160 G4double cut)
161{
162 return cut;
163}
164
165//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
166
169 const G4Region* region)
170{
171 if(nullptr == ptr) { return; }
172 G4VEmFluctuationModel* afluc = (nullptr == fluc) ? fluctModel : fluc;
173 modelManager->AddEmModel(order, ptr, afluc, region);
175}
176
177//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
178
180{
181 if(nullptr == ptr) { return; }
182 if(!emModels->empty()) {
183 for(auto & em : *emModels) { if(em == ptr) { return; } }
184 }
185 emModels->push_back(ptr);
186}
187
188//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
189
191 G4double charge2ratio)
192{
193 massRatio = massratio;
194 logMassRatio = G4Log(massRatio);
195 fFactor = charge2ratio*biasFactor;
196 if(baseMat) { fFactor *= (*theDensityFactor)[currentCoupleIndex]; }
197 chargeSqRatio = charge2ratio;
198 reduceFactor = 1.0/(fFactor*massRatio);
199}
200
201//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
202
203void
205{
206 particle = G4EmTableUtil::CheckIon(this, &part, particle,
207 verboseLevel, isIon);
208
209 if( particle != &part ) {
210 if(!isIon) { lManager->RegisterExtraParticle(&part, this); }
211 if(1 < verboseLevel) {
212 G4cout << "### G4VEnergyLossProcess::PreparePhysicsTable()"
213 << " interrupted for " << GetProcessName() << " and "
214 << part.GetParticleName() << " isIon=" << isIon
215 << " spline=" << spline << G4endl;
216 }
217 return;
218 }
219
220 tablesAreBuilt = false;
221 if (GetProcessSubType() == fIonisation) { SetIonisation(true); }
222
223 G4LossTableBuilder* bld = lManager->GetTableBuilder();
224 lManager->PreparePhysicsTable(&part, this);
225
226 // Base particle and set of models can be defined here
227 InitialiseEnergyLossProcess(particle, baseParticle);
228
229 // parameters of the process
230 lossFluctuationFlag = theParameters->LossFluctuation();
231 useCutAsFinalRange = theParameters->UseCutAsFinalRange();
232 if(!actMinKinEnergy) { minKinEnergy = theParameters->MinKinEnergy(); }
233 if(!actMaxKinEnergy) { maxKinEnergy = theParameters->MaxKinEnergy(); }
234 if(!actBinning) { nBins = theParameters->NumberOfBins(); }
235 maxKinEnergyCSDA = theParameters->MaxEnergyForCSDARange();
236 nBinsCSDA = theParameters->NumberOfBinsPerDecade()
237 *G4lrint(std::log10(maxKinEnergyCSDA/minKinEnergy));
238 if(!actLinLossLimit) { linLossLimit = theParameters->LinearLossLimit(); }
239 lambdaFactor = theParameters->LambdaFactor();
240 invLambdaFactor = 1.0/lambdaFactor;
241 if(isMaster) { SetVerboseLevel(theParameters->Verbose()); }
242 else { SetVerboseLevel(theParameters->WorkerVerbose()); }
243 // integral option may be disabled
244 if(!theParameters->Integral()) { fXSType = fEmNoIntegral; }
245
246 theParameters->DefineRegParamForLoss(this);
247
248 fRangeEnergy = 0.0;
249
250 G4double initialCharge = particle->GetPDGCharge();
251 G4double initialMass = particle->GetPDGMass();
252
253 theParameters->FillStepFunction(particle, this);
254
255 // parameters for scaling from the base particle
256 if (nullptr != baseParticle) {
257 massRatio = (baseParticle->GetPDGMass())/initialMass;
258 logMassRatio = G4Log(massRatio);
259 G4double q = initialCharge/baseParticle->GetPDGCharge();
260 chargeSqRatio = q*q;
261 if(chargeSqRatio > 0.0) { reduceFactor = 1.0/(chargeSqRatio*massRatio); }
262 }
263 lowestKinEnergy = (initialMass < CLHEP::MeV)
264 ? theParameters->LowestElectronEnergy()
265 : theParameters->LowestMuHadEnergy();
266
267 // Tables preparation
268 if (isMaster && nullptr == baseParticle) {
269 if (nullptr == theData) { theData = new G4EmDataHandler(7, particle->GetParticleName()); }
270
271 if (isIonisation && theDEDXTable != theIonisationTable) {
272 theData->CleanTable(0);
273 theDEDXTable = theIonisationTable;
274 theIonisationTable = nullptr;
275 }
276 theDEDXTable = theData->MakeTable(theDEDXTable, 0);
277 bld->InitialiseBaseMaterials(theDEDXTable);
278 theData->MakeTable(theIonisationTable, 1);
279
280 if (theParameters->BuildCSDARange()) {
281 theDEDXunRestrictedTable = theData->MakeTable(theDEDXunRestrictedTable, 2);
282 if(isIonisation) { theCSDARangeTable = theData->MakeTable(theCSDARangeTable, 3); }
283 }
284
285 theLambdaTable = theData->MakeTable(theLambdaTable, 4);
286 if(isIonisation) {
287 theRangeTableForLoss = theData->MakeTable(theRangeTableForLoss, 5);
288 theInverseRangeTable = theData->MakeTable(theInverseRangeTable, 6);
289 }
290 }
291
292 // forced biasing
293 if(nullptr != biasManager) {
294 biasManager->Initialise(part,GetProcessName(),verboseLevel);
295 biasFlag = false;
296 }
297 baseMat = bld->GetBaseMaterialFlag();
298 numberOfModels = modelManager->NumberOfModels();
299 currentModel = modelManager->GetModel(0);
300 G4EmTableUtil::UpdateModels(this, modelManager, maxKinEnergy,
301 numberOfModels, secID, biasID,
302 mainSecondaries, baseMat, isMaster,
303 theParameters->UseAngularGeneratorForIonisation());
304 theCuts = modelManager->Initialise(particle, secondaryParticle,
306 // subcut processor
307 if(isIonisation) {
308 subcutProducer = lManager->SubCutProducer();
309 }
310
311 if(1 < verboseLevel) {
312 G4cout << "G4VEnergyLossProcess::PrepearPhysicsTable() is done "
313 << " for " << GetProcessName() << " and " << particle->GetParticleName()
314 << " isIon= " << isIon << " spline=" << spline;
315 if(baseParticle) {
316 G4cout << "; base: " << baseParticle->GetParticleName();
317 }
318 G4cout << G4endl;
319 G4cout << " chargeSqRatio= " << chargeSqRatio
320 << " massRatio= " << massRatio
321 << " reduceFactor= " << reduceFactor << G4endl;
322 if (nSCoffRegions > 0) {
323 G4cout << " SubCut secondary production is ON for regions: " << G4endl;
324 for (G4int i=0; i<nSCoffRegions; ++i) {
325 const G4Region* r = (*scoffRegions)[i];
326 G4cout << " " << r->GetName() << G4endl;
327 }
328 } else if(nullptr != subcutProducer) {
329 G4cout << " SubCut secondary production is ON for all regions" << G4endl;
330 }
331 }
332}
333
334//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
335
337{
338 if(1 < verboseLevel) {
339 G4cout << "### G4VEnergyLossProcess::BuildPhysicsTable() for "
340 << GetProcessName()
341 << " and particle " << part.GetParticleName()
342 << "; the first particle " << particle->GetParticleName();
343 if(baseParticle) {
344 G4cout << "; base: " << baseParticle->GetParticleName();
345 }
346 G4cout << G4endl;
347 G4cout << " TablesAreBuilt= " << tablesAreBuilt << " isIon= " << isIon
348 << " spline=" << spline << " ptr: " << this << G4endl;
349 }
350
351 if(&part == particle) {
352 if(isMaster) {
353 lManager->BuildPhysicsTable(particle, this);
354
355 } else {
356 const auto masterProcess =
357 static_cast<const G4VEnergyLossProcess*>(GetMasterProcess());
358
359 numberOfModels = modelManager->NumberOfModels();
360 G4EmTableUtil::BuildLocalElossProcess(this, masterProcess,
361 particle, numberOfModels);
362 tablesAreBuilt = true;
363 baseMat = masterProcess->UseBaseMaterial();
364 lManager->LocalPhysicsTables(particle, this);
365 }
366
367 // needs to be done only once
368 safetyHelper->InitialiseHelper();
369 }
370 // Added tracking cut to avoid tracking artifacts
371 // and identified deexcitation flag
372 if(isIonisation) {
373 atomDeexcitation = lManager->AtomDeexcitation();
374 if(nullptr != atomDeexcitation) {
375 if(atomDeexcitation->IsPIXEActive()) { useDeexcitation = true; }
376 }
377 }
378
379 // protection against double printout
380 if(theParameters->IsPrintLocked()) { return; }
381
382 // explicitly defined printout by particle name
383 G4String num = part.GetParticleName();
384 if(1 < verboseLevel ||
385 (0 < verboseLevel && (num == "e-" ||
386 num == "e+" || num == "mu+" ||
387 num == "mu-" || num == "proton"||
388 num == "pi+" || num == "pi-" ||
389 num == "kaon+" || num == "kaon-" ||
390 num == "alpha" || num == "anti_proton" ||
391 num == "GenericIon"|| num == "alpha+" ))) {
392 StreamInfo(G4cout, part);
393 }
394 if(1 < verboseLevel) {
395 G4cout << "### G4VEnergyLossProcess::BuildPhysicsTable() done for "
396 << GetProcessName()
397 << " and particle " << part.GetParticleName();
398 if(isIonisation) { G4cout << " isIonisation flag=1"; }
399 G4cout << " baseMat=" << baseMat << G4endl;
400 }
401}
402
403//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
404
406{
407 G4PhysicsTable* table = nullptr;
408 G4double emax = maxKinEnergy;
409 G4int bin = nBins;
410
411 if(fTotal == tType) {
412 emax = maxKinEnergyCSDA;
413 bin = nBinsCSDA;
414 table = theDEDXunRestrictedTable;
415 } else if(fRestricted == tType) {
416 table = theDEDXTable;
417 } else {
418 G4cout << "G4VEnergyLossProcess::BuildDEDXTable WARNING: wrong type "
419 << tType << G4endl;
420 }
421 if(1 < verboseLevel) {
422 G4cout << "G4VEnergyLossProcess::BuildDEDXTable() of type " << tType
423 << " for " << GetProcessName()
424 << " and " << particle->GetParticleName()
425 << "spline=" << spline << G4endl;
426 }
427 if(nullptr == table) { return table; }
428
429 G4LossTableBuilder* bld = lManager->GetTableBuilder();
430 G4EmTableUtil::BuildDEDXTable(this, particle, modelManager, bld,
431 table, minKinEnergy, emax, bin,
432 verboseLevel, tType, spline);
433 return table;
434}
435
436//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
437
439{
440 if(nullptr == theLambdaTable) { return theLambdaTable; }
441
442 G4double scale = theParameters->MaxKinEnergy()/theParameters->MinKinEnergy();
443 G4int nbin =
444 theParameters->NumberOfBinsPerDecade()*G4lrint(std::log10(scale));
445 scale = nbin/G4Log(scale);
446
447 G4LossTableBuilder* bld = lManager->GetTableBuilder();
448 G4EmTableUtil::BuildLambdaTable(this, particle, modelManager,
449 bld, theLambdaTable, theCuts,
450 minKinEnergy, maxKinEnergy, scale,
451 verboseLevel, spline);
452 return theLambdaTable;
453}
454
455//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
456
457void G4VEnergyLossProcess::StreamInfo(std::ostream& out,
458 const G4ParticleDefinition& part, G4bool rst) const
459{
460 G4String indent = (rst ? " " : "");
461 out << std::setprecision(6);
462 out << G4endl << indent << GetProcessName() << ": ";
463 if (!rst) out << " for " << part.GetParticleName();
464 out << " XStype:" << fXSType
465 << " SubType=" << GetProcessSubType() << G4endl
466 << " dE/dx and range tables from "
467 << G4BestUnit(minKinEnergy,"Energy")
468 << " to " << G4BestUnit(maxKinEnergy,"Energy")
469 << " in " << nBins << " bins" << G4endl
470 << " Lambda tables from threshold to "
471 << G4BestUnit(maxKinEnergy,"Energy")
472 << ", " << theParameters->NumberOfBinsPerDecade()
473 << " bins/decade, spline: " << spline
474 << G4endl;
475 if(nullptr != theRangeTableForLoss && isIonisation) {
476 out << " StepFunction=(" << dRoverRange << ", "
477 << finalRange/mm << " mm)"
478 << ", integ: " << fXSType
479 << ", fluct: " << lossFluctuationFlag
480 << ", linLossLim= " << linLossLimit
481 << G4endl;
482 }
484 modelManager->DumpModelList(out, verboseLevel);
485 if(nullptr != theCSDARangeTable && isIonisation) {
486 out << " CSDA range table up"
487 << " to " << G4BestUnit(maxKinEnergyCSDA,"Energy")
488 << " in " << nBinsCSDA << " bins" << G4endl;
489 }
490 if(nSCoffRegions>0 && isIonisation) {
491 out << " Subcutoff sampling in " << nSCoffRegions
492 << " regions" << G4endl;
493 }
494 if(2 < verboseLevel) {
495 for(std::size_t i=0; i<7; ++i) {
496 auto ta = theData->Table(i);
497 out << " " << tnames[i] << " address: " << ta << G4endl;
498 if(nullptr != ta) { out << *ta << G4endl; }
499 }
500 }
501}
502
503//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
504
506{
507 if(nullptr == scoffRegions) {
508 scoffRegions = new std::vector<const G4Region*>;
509 }
510 // the region is in the list
511 if(!scoffRegions->empty()) {
512 for (auto & reg : *scoffRegions) {
513 if (reg == r) { return; }
514 }
515 }
516 // new region
517 scoffRegions->push_back(r);
518 ++nSCoffRegions;
519}
520
521//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
522
523G4bool G4VEnergyLossProcess::IsRegionForCubcutProcessor(const G4Track& aTrack)
524{
525 if(0 == nSCoffRegions) { return true; }
526 const G4Region* r = aTrack.GetVolume()->GetLogicalVolume()->GetRegion();
527 for(auto & reg : *scoffRegions) {
528 if(r == reg) { return true; }
529 }
530 return false;
531}
532
533//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
534
536{
537 // reset parameters for the new track
540 preStepLambda = 0.0;
541 currentCouple = nullptr;
542
543 // reset ion
544 if(isIon) {
545 const G4double newmass = track->GetParticleDefinition()->GetPDGMass();
546 massRatio = (nullptr == baseParticle) ? CLHEP::proton_mass_c2/newmass
547 : baseParticle->GetPDGMass()/newmass;
548 logMassRatio = G4Log(massRatio);
549 }
550 // forced biasing only for primary particles
551 if(nullptr != biasManager) {
552 if(0 == track->GetParentID()) {
553 biasFlag = true;
554 biasManager->ResetForcedInteraction();
555 }
556 }
557}
558
559//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
560
562 const G4Track& track, G4double, G4double, G4double&,
563 G4GPILSelection* selection)
564{
565 G4double x = DBL_MAX;
566 *selection = aGPILSelection;
567 if(isIonisation && currentModel->IsActive(preStepScaledEnergy)) {
568 GetScaledRangeForScaledEnergy(preStepScaledEnergy, LogScaledEkin(track));
569 x = (useCutAsFinalRange) ? std::min(finalRange,
570 currentCouple->GetProductionCuts()->GetProductionCut(1)) : finalRange;
571 x = (fRange > x) ? fRange*dRoverRange + x*(1.0 - dRoverRange)*(2.0 - x/fRange)
572 : fRange;
573 /*
574 G4cout<<"AlongStepGPIL: " << GetProcessName()<<": e="<<preStepKinEnergy
575 << " fRange=" << fRange << " finR=" << finR <<" stepLimit="<<x<<G4endl;
576 */
577 }
578 return x;
579}
580
581//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
582
584 const G4Track& track,
585 G4double previousStepSize,
587{
588 // condition is set to "Not Forced"
590 G4double x = DBL_MAX;
591
592 // initialisation of material, mass, charge, model
593 // at the beginning of the step
594 DefineMaterial(track.GetMaterialCutsCouple());
598
599 if(!currentModel->IsActive(preStepScaledEnergy)) {
602 preStepLambda = 0.0;
604 return x;
605 }
606
607 // change effective charge of a charged particle on fly
608 if(isIon) {
609 const G4double q2 = currentModel->ChargeSquareRatio(track);
610 fFactor = q2*biasFactor;
611 if(baseMat) { fFactor *= (*theDensityFactor)[currentCoupleIndex]; }
612 reduceFactor = 1.0/(fFactor*massRatio);
613 if (lossFluctuationFlag) {
614 auto fluc = currentModel->GetModelOfFluctuations();
615 fluc->SetParticleAndCharge(track.GetParticleDefinition(), q2);
616 }
617 }
618
619 // forced biasing only for primary particles
620 if(biasManager) {
621 if(0 == track.GetParentID() && biasFlag &&
622 biasManager->ForcedInteractionRegion((G4int)currentCoupleIndex)) {
623 return biasManager->GetStepLimit((G4int)currentCoupleIndex, previousStepSize);
624 }
625 }
626
627 ComputeLambdaForScaledEnergy(preStepScaledEnergy, track);
628
629 // zero cross section
630 if(preStepLambda <= 0.0) {
633 } else {
634
635 // non-zero cross section
637
638 // beggining of tracking (or just after DoIt of this process)
641
642 } else if(currentInteractionLength < DBL_MAX) {
643
644 // subtract NumberOfInteractionLengthLeft using previous step
646 previousStepSize/currentInteractionLength;
647
650 }
651
652 // new mean free path and step limit
655 }
656#ifdef G4VERBOSE
657 if (verboseLevel>2) {
658 G4cout << "G4VEnergyLossProcess::PostStepGetPhysicalInteractionLength ";
659 G4cout << "[ " << GetProcessName() << "]" << G4endl;
660 G4cout << " for " << track.GetParticleDefinition()->GetParticleName()
661 << " in Material " << currentMaterial->GetName()
662 << " Ekin(MeV)= " << preStepKinEnergy/MeV
663 << " track material: " << track.GetMaterial()->GetName()
664 <<G4endl;
665 G4cout << "MeanFreePath = " << currentInteractionLength/cm << "[cm]"
666 << "InteractionLength= " << x/cm <<"[cm] " <<G4endl;
667 }
668#endif
669 return x;
670}
671
672//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
673
674void
675G4VEnergyLossProcess::ComputeLambdaForScaledEnergy(G4double e, const G4Track& track)
676{
677 // cross section increased with energy
678 if(fXSType == fEmIncreasing) {
679 if(e*invLambdaFactor < mfpKinEnergy) {
680 preStepLambda = GetLambdaForScaledEnergy(e, LogScaledEkin(track));
681 mfpKinEnergy = (preStepLambda > 0.0) ? e : 0.0;
682 }
683
684 // cross section has one peak
685 } else if(fXSType == fEmOnePeak) {
686 const G4double epeak = (*theEnergyOfCrossSectionMax)[basedCoupleIndex];
687 if(e <= epeak) {
688 if(e*invLambdaFactor < mfpKinEnergy) {
689 preStepLambda = GetLambdaForScaledEnergy(e, LogScaledEkin(track));
690 mfpKinEnergy = (preStepLambda > 0.0) ? e : 0.0;
691 }
692 } else if(e < mfpKinEnergy) {
693 const G4double e1 = std::max(epeak, e*lambdaFactor);
694 mfpKinEnergy = e1;
695 preStepLambda = GetLambdaForScaledEnergy(e1);
696 }
697
698 // cross section has more than one peaks
699 } else if(fXSType == fEmTwoPeaks) {
700 G4TwoPeaksXS* xs = (*fXSpeaks)[basedCoupleIndex];
701 const G4double e1peak = xs->e1peak;
702
703 // below the 1st peak
704 if(e <= e1peak) {
705 if(e*invLambdaFactor < mfpKinEnergy) {
706 preStepLambda = GetLambdaForScaledEnergy(e, LogScaledEkin(track));
707 mfpKinEnergy = (preStepLambda > 0.0) ? e : 0.0;
708 }
709 return;
710 }
711 const G4double e1deep = xs->e1deep;
712 // above the 1st peak, below the deep
713 if(e <= e1deep) {
714 if(mfpKinEnergy >= e1deep || e <= mfpKinEnergy) {
715 const G4double e1 = std::max(e1peak, e*lambdaFactor);
716 mfpKinEnergy = e1;
717 preStepLambda = GetLambdaForScaledEnergy(e1);
718 }
719 return;
720 }
721 const G4double e2peak = xs->e2peak;
722 // above the deep, below 2nd peak
723 if(e <= e2peak) {
724 if(e*invLambdaFactor < mfpKinEnergy) {
725 mfpKinEnergy = e;
726 preStepLambda = GetLambdaForScaledEnergy(e, LogScaledEkin(track));
727 }
728 return;
729 }
730 const G4double e2deep = xs->e2deep;
731 // above the 2nd peak, below the deep
732 if(e <= e2deep) {
733 if(mfpKinEnergy >= e2deep || e <= mfpKinEnergy) {
734 const G4double e1 = std::max(e2peak, e*lambdaFactor);
735 mfpKinEnergy = e1;
736 preStepLambda = GetLambdaForScaledEnergy(e1);
737 }
738 return;
739 }
740 const G4double e3peak = xs->e3peak;
741 // above the deep, below 3d peak
742 if(e <= e3peak) {
743 if(e*invLambdaFactor < mfpKinEnergy) {
744 mfpKinEnergy = e;
745 preStepLambda = GetLambdaForScaledEnergy(e, LogScaledEkin(track));
746 }
747 return;
748 }
749 // above 3d peak
750 if(e <= mfpKinEnergy) {
751 const G4double e1 = std::max(e3peak, e*lambdaFactor);
752 mfpKinEnergy = e1;
753 preStepLambda = GetLambdaForScaledEnergy(e1);
754 }
755 // integral method is not used
756 } else {
757 preStepLambda = GetLambdaForScaledEnergy(e, LogScaledEkin(track));
758 }
759}
760
761//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
762
764 const G4Step& step)
765{
766 fParticleChange.InitializeForAlongStep(track);
767 // The process has range table - calculate energy loss
768 if(!isIonisation || !currentModel->IsActive(preStepScaledEnergy)) {
769 return &fParticleChange;
770 }
771
772 G4double length = step.GetStepLength();
773 G4double eloss = 0.0;
774
775 /*
776 if(-1 < verboseLevel) {
777 const G4ParticleDefinition* d = track.GetParticleDefinition();
778 G4cout << "AlongStepDoIt for "
779 << GetProcessName() << " and particle " << d->GetParticleName()
780 << " eScaled(MeV)=" << preStepScaledEnergy/MeV
781 << " range(mm)=" << fRange/mm << " s(mm)=" << length/mm
782 << " rf=" << reduceFactor << " q^2=" << chargeSqRatio
783 << " md=" << d->GetPDGMass() << " status=" << track.GetTrackStatus()
784 << " " << track.GetMaterial()->GetName() << G4endl;
785 }
786 */
787 const G4DynamicParticle* dynParticle = track.GetDynamicParticle();
788
789 // define new weight for primary and secondaries
790 G4double weight = fParticleChange.GetParentWeight();
791 if(weightFlag) {
792 weight /= biasFactor;
793 fParticleChange.ProposeWeight(weight);
794 }
795
796 // stopping, check actual range and kinetic energy
797 if (length >= fRange || preStepKinEnergy <= lowestKinEnergy) {
798 eloss = preStepKinEnergy;
799 if (useDeexcitation) {
800 atomDeexcitation->AlongStepDeexcitation(scTracks, step,
801 eloss, (G4int)currentCoupleIndex);
802 if (!scTracks.empty()) { FillSecondariesAlongStep(weight); }
803 eloss = std::max(eloss, 0.0);
804 }
805 fParticleChange.SetProposedKineticEnergy(0.0);
806 fParticleChange.ProposeLocalEnergyDeposit(eloss);
807 return &fParticleChange;
808 }
809 // zero step length with non-zero range
810 if(length <= 0.0) { return &fParticleChange; }
811
812 // Short step
813 eloss = length*GetDEDXForScaledEnergy(preStepScaledEnergy,
814 LogScaledEkin(track));
815 /*
816 G4cout << "##### Short STEP: eloss= " << eloss
817 << " Escaled=" << preStepScaledEnergy
818 << " R=" << fRange
819 << " L=" << length
820 << " fFactor=" << fFactor << " minE=" << minKinEnergy
821 << " idxBase=" << basedCoupleIndex << G4endl;
822 */
823 // Long step
824 if(eloss > preStepKinEnergy*linLossLimit) {
825
826 const G4double x = (fRange - length)/reduceFactor;
827 const G4double de = preStepKinEnergy - ScaledKinEnergyForLoss(x)/massRatio;
828 if(de > 0.0) { eloss = de; }
829 /*
830 if(-1 < verboseLevel)
831 G4cout << " Long STEP: rPre(mm)="
832 << GetScaledRangeForScaledEnergy(preStepScaledEnergy)/mm
833 << " x(mm)=" << x/mm
834 << " eloss(MeV)=" << eloss/MeV
835 << " rFactor=" << reduceFactor
836 << " massRatio=" << massRatio
837 << G4endl;
838 */
839 }
840
841 /*
842 if(-1 < verboseLevel ) {
843 G4cout << "Before fluct: eloss(MeV)= " << eloss/MeV
844 << " e-eloss= " << preStepKinEnergy-eloss
845 << " step(mm)= " << length/mm << " range(mm)= " << fRange/mm
846 << " fluct= " << lossFluctuationFlag << G4endl;
847 }
848 */
849
850 const G4double cut = (*theCuts)[currentCoupleIndex];
851 G4double esec = 0.0;
852
853 // Corrections, which cannot be tabulated
854 if (isIon) {
855 currentModel->SetCurrentCouple(currentCouple);
856 currentModel->CorrectionsAlongStep(currentMaterial,
857 track.GetParticleDefinition(),
858 preStepKinEnergy, cut,
859 length, eloss);
860 eloss = std::max(eloss, 0.0);
861 }
862
863 // Sample fluctuations if not full energy loss
864 if(eloss >= preStepKinEnergy) {
865 eloss = preStepKinEnergy;
866
867 } else if ((*theFluctuationFlags)[currentCoupleIndex]) {
868 const G4double tmax = currentModel->MaxSecondaryKinEnergy(dynParticle);
869 const G4double tcut = std::min(cut, tmax);
870 G4VEmFluctuationModel* fluc = currentModel->GetModelOfFluctuations();
871 eloss = fluc->SampleFluctuations(currentCouple,dynParticle,
872 tcut, tmax, length, eloss);
873 /*
874 if(-1 < verboseLevel)
875 G4cout << "After fluct: eloss(MeV)= " << eloss/MeV
876 << " fluc= " << (eloss-eloss0)/MeV
877 << " ChargeSqRatio= " << chargeSqRatio
878 << " massRatio= " << massRatio << " tmax= " << tmax << G4endl;
879 */
880 }
881
882 // deexcitation
883 if (useDeexcitation) {
884 G4double esecfluo = preStepKinEnergy;
885 G4double de = esecfluo;
886 atomDeexcitation->AlongStepDeexcitation(scTracks, step,
888
889 // sum of de-excitation energies
890 esecfluo -= de;
891
892 // subtracted from energy loss
893 if(eloss >= esecfluo) {
894 esec += esecfluo;
895 eloss -= esecfluo;
896 } else {
897 esec += esecfluo;
898 eloss = 0.0;
899 }
900 }
901 if(nullptr != subcutProducer && IsRegionForCubcutProcessor(track)) {
902 subcutProducer->SampleSecondaries(step, scTracks, eloss, cut);
903 }
904 // secondaries from atomic de-excitation and subcut
905 if(!scTracks.empty()) { FillSecondariesAlongStep(weight); }
906
907 // Energy balance
908 G4double finalT = preStepKinEnergy - eloss - esec;
909 if (finalT <= lowestKinEnergy) {
910 eloss += finalT;
911 finalT = 0.0;
912 } else if(isIon) {
913 fParticleChange.SetProposedCharge(
914 currentModel->GetParticleCharge(track.GetParticleDefinition(),
915 currentMaterial,finalT));
916 }
917 eloss = std::max(eloss, 0.0);
918
919 fParticleChange.SetProposedKineticEnergy(finalT);
920 fParticleChange.ProposeLocalEnergyDeposit(eloss);
921 /*
922 if(-1 < verboseLevel) {
923 G4double del = finalT + eloss + esec - preStepKinEnergy;
924 G4cout << "Final value eloss(MeV)= " << eloss/MeV
925 << " preStepKinEnergy= " << preStepKinEnergy
926 << " postStepKinEnergy= " << finalT
927 << " de(keV)= " << del/keV
928 << " lossFlag= " << lossFluctuationFlag
929 << " status= " << track.GetTrackStatus()
930 << G4endl;
931 }
932 */
933 return &fParticleChange;
934}
935
936//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
937
938void G4VEnergyLossProcess::FillSecondariesAlongStep(G4double wt)
939{
940 const std::size_t n0 = scTracks.size();
941 G4double weight = wt;
942 // weight may be changed by biasing manager
943 if(biasManager) {
945 weight *=
946 biasManager->ApplySecondaryBiasing(scTracks, (G4int)currentCoupleIndex);
947 }
948 }
949
950 // fill secondaries
951 const std::size_t n = scTracks.size();
952 fParticleChange.SetNumberOfSecondaries((G4int)n);
953
954 for(std::size_t i=0; i<n; ++i) {
955 G4Track* t = scTracks[i];
956 if(nullptr != t) {
957 t->SetWeight(weight);
958 pParticleChange->AddSecondary(t);
960 if (i < n0) {
961 if (pdg == 22) {
962 t->SetCreatorModelID(gpixeID);
963 } else if (pdg == 11) {
964 t->SetCreatorModelID(epixeID);
965 } else {
966 t->SetCreatorModelID(biasID);
967 }
968 } else {
969 t->SetCreatorModelID(biasID);
970 }
971 }
972 }
973 scTracks.clear();
974}
975
976//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
977
979 const G4Step& step)
980{
981 // clear number of interaction lengths in any case
984
985 fParticleChange.InitializeForPostStep(track);
986 const G4double finalT = track.GetKineticEnergy();
987
988 const G4double postStepScaledEnergy = finalT*massRatio;
989 SelectModel(postStepScaledEnergy);
990
991 if(!currentModel->IsActive(postStepScaledEnergy)) {
992 return &fParticleChange;
993 }
994 /*
995 if(1 < verboseLevel) {
996 G4cout<<GetProcessName()<<" PostStepDoIt: E(MeV)= "<< finalT/MeV<< G4endl;
997 }
998 */
999 // forced process - should happen only once per track
1000 if(biasFlag) {
1001 if(biasManager->ForcedInteractionRegion((G4int)currentCoupleIndex)) {
1002 biasFlag = false;
1003 }
1004 }
1005 const G4DynamicParticle* dp = track.GetDynamicParticle();
1006
1007 // Integral approach
1008 if (fXSType != fEmNoIntegral) {
1009 const G4double logFinalT = dp->GetLogKineticEnergy();
1010 G4double lx = GetLambdaForScaledEnergy(postStepScaledEnergy,
1011 logFinalT + logMassRatio);
1012 lx = std::max(lx, 0.0);
1013
1014 // if both lg and lx are zero then no interaction
1015 if(preStepLambda*G4UniformRand() >= lx) {
1016 return &fParticleChange;
1017 }
1018 }
1019
1020 // define new weight for primary and secondaries
1021 G4double weight = fParticleChange.GetParentWeight();
1022 if(weightFlag) {
1023 weight /= biasFactor;
1024 fParticleChange.ProposeWeight(weight);
1025 }
1026
1027 const G4double tcut = (*theCuts)[currentCoupleIndex];
1028
1029 // sample secondaries
1030 secParticles.clear();
1031 currentModel->SampleSecondaries(&secParticles, currentCouple, dp, tcut);
1032
1033 const G4int num0 = (G4int)secParticles.size();
1034
1035 // bremsstrahlung splitting or Russian roulette
1036 if(biasManager) {
1037 if(biasManager->SecondaryBiasingRegion((G4int)currentCoupleIndex)) {
1038 G4double eloss = 0.0;
1039 weight *= biasManager->ApplySecondaryBiasing(
1040 secParticles,
1041 track, currentModel,
1042 &fParticleChange, eloss,
1043 (G4int)currentCoupleIndex, tcut,
1044 step.GetPostStepPoint()->GetSafety());
1045 if(eloss > 0.0) {
1046 eloss += fParticleChange.GetLocalEnergyDeposit();
1047 fParticleChange.ProposeLocalEnergyDeposit(eloss);
1048 }
1049 }
1050 }
1051
1052 // save secondaries
1053 const G4int num = (G4int)secParticles.size();
1054 if(num > 0) {
1055
1056 fParticleChange.SetNumberOfSecondaries(num);
1057 G4double time = track.GetGlobalTime();
1058
1059 G4int n1(0), n2(0);
1060 if(num0 > mainSecondaries) {
1061 currentModel->FillNumberOfSecondaries(n1, n2);
1062 }
1063
1064 for (G4int i=0; i<num; ++i) {
1065 if(nullptr != secParticles[i]) {
1066 G4Track* t = new G4Track(secParticles[i], time, track.GetPosition());
1068 if (biasManager) {
1069 t->SetWeight(weight * biasManager->GetWeight(i));
1070 } else {
1071 t->SetWeight(weight);
1072 }
1073 if(i < num0) {
1074 t->SetCreatorModelID(secID);
1075 } else if(i < num0 + n1) {
1076 t->SetCreatorModelID(tripletID);
1077 } else {
1078 t->SetCreatorModelID(biasID);
1079 }
1080
1081 //G4cout << "Secondary(post step) has weight " << t->GetWeight()
1082 // << ", kenergy " << t->GetKineticEnergy()/MeV << " MeV"
1083 // << " time= " << time/ns << " ns " << G4endl;
1084 pParticleChange->AddSecondary(t);
1085 }
1086 }
1087 }
1088
1089 if(0.0 == fParticleChange.GetProposedKineticEnergy() &&
1090 fAlive == fParticleChange.GetTrackStatus()) {
1091 if(particle->GetProcessManager()->GetAtRestProcessVector()->size() > 0)
1092 { fParticleChange.ProposeTrackStatus(fStopButAlive); }
1093 else { fParticleChange.ProposeTrackStatus(fStopAndKill); }
1094 }
1095
1096 /*
1097 if(-1 < verboseLevel) {
1098 G4cout << "::PostStepDoIt: Sample secondary; Efin= "
1099 << fParticleChange.GetProposedKineticEnergy()/MeV
1100 << " MeV; model= (" << currentModel->LowEnergyLimit()
1101 << ", " << currentModel->HighEnergyLimit() << ")"
1102 << " preStepLambda= " << preStepLambda
1103 << " dir= " << track.GetMomentumDirection()
1104 << " status= " << track.GetTrackStatus()
1105 << G4endl;
1106 }
1107 */
1108 return &fParticleChange;
1109}
1110
1111//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1112
1114 const G4ParticleDefinition* part, const G4String& dir, G4bool ascii)
1115{
1116 if (!isMaster || nullptr != baseParticle || part != particle ) return true;
1117 for(std::size_t i=0; i<7; ++i) {
1118 // ionisation table only for ionisation process
1119 if (nullptr == theData->Table(i) || (!isIonisation && 1 == i)) {
1120 continue;
1121 }
1122 if (-1 < verboseLevel) {
1123 G4cout << "G4VEnergyLossProcess::StorePhysicsTable i=" << i
1124 << " " << particle->GetParticleName()
1125 << " " << GetProcessName()
1126 << " " << tnames[i] << " " << theData->Table(i) << G4endl;
1127 }
1128 if (!G4EmTableUtil::StoreTable(this, part, theData->Table(i),
1129 dir, tnames[i], verboseLevel, ascii)) {
1130 return false;
1131 }
1132 }
1133 return true;
1134}
1135
1136//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
1137
1138G4bool
1140 const G4String& dir, G4bool ascii)
1141{
1142 if (!isMaster || nullptr != baseParticle || part != particle ) return true;
1143 for(std::size_t i=0; i<7; ++i) {
1144 // ionisation table only for ionisation process
1145 if (!isIonisation && 1 == i) { continue; }
1146 if(!G4EmTableUtil::RetrieveTable(this, part, theData->Table(i), dir, tnames[i],
1147 verboseLevel, ascii, spline)) {
1148 return false;
1149 }
1150 }
1151 return true;
1152}
1153
1154//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1155
1157 const G4MaterialCutsCouple *couple,
1158 const G4DynamicParticle* dp,
1159 G4double length)
1160{
1161 DefineMaterial(couple);
1162 G4double ekin = dp->GetKineticEnergy();
1163 SelectModel(ekin*massRatio);
1164 G4double tmax = currentModel->MaxSecondaryKinEnergy(dp);
1165 G4double tcut = std::min(tmax,(*theCuts)[currentCoupleIndex]);
1166 G4double d = 0.0;
1167 G4VEmFluctuationModel* fm = currentModel->GetModelOfFluctuations();
1168 if(nullptr != fm) { d = fm->Dispersion(currentMaterial,dp,tcut,tmax,length); }
1169 return d;
1170}
1171
1172//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1173
1176 const G4MaterialCutsCouple* couple,
1177 G4double logKineticEnergy)
1178{
1179 // Cross section per volume is calculated
1180 DefineMaterial(couple);
1181 G4double cross = 0.0;
1182 if (nullptr != theLambdaTable) {
1183 cross = GetLambdaForScaledEnergy(kineticEnergy * massRatio,
1184 logKineticEnergy + logMassRatio);
1185 } else {
1186 SelectModel(kineticEnergy*massRatio);
1187 cross = (!baseMat) ? biasFactor : biasFactor*(*theDensityFactor)[currentCoupleIndex];
1188 cross *= (currentModel->CrossSectionPerVolume(currentMaterial, particle, kineticEnergy,
1189 (*theCuts)[currentCoupleIndex]));
1190 }
1191 return std::max(cross, 0.0);
1192}
1193
1194//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1195
1197{
1198 DefineMaterial(track.GetMaterialCutsCouple());
1199 const G4double kinEnergy = track.GetKineticEnergy();
1200 const G4double logKinEnergy = track.GetDynamicParticle()->GetLogKineticEnergy();
1201 const G4double cs = GetLambdaForScaledEnergy(kinEnergy * massRatio,
1202 logKinEnergy + logMassRatio);
1203 return (0.0 < cs) ? 1.0/cs : DBL_MAX;
1204}
1205
1206//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1207
1209 G4double x, G4double y,
1210 G4double& z)
1211{
1212 return AlongStepGetPhysicalInteractionLength(track, x, y, z, &aGPILSelection);
1213}
1214
1215//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1216
1218 const G4Track& track,
1219 G4double,
1221
1222{
1224 return MeanFreePath(track);
1225}
1226
1227//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1228
1235
1236//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1237
1240 G4double)
1241{
1242 DefineMaterial(couple);
1243 G4PhysicsVector* v = (*theLambdaTable)[basedCoupleIndex];
1244 return new G4PhysicsVector(*v);
1245}
1246
1247//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1248
1249void
1251{
1252 if(1 < verboseLevel) {
1253 G4cout << "### Set DEDX table " << p << " " << theDEDXTable
1254 << " " << theDEDXunRestrictedTable << " " << theIonisationTable
1255 << " for " << particle->GetParticleName()
1256 << " and process " << GetProcessName()
1257 << " type=" << tType << " isIonisation:" << isIonisation << G4endl;
1258 }
1259 if(fTotal == tType) {
1260 theDEDXunRestrictedTable = p;
1261 } else if(fRestricted == tType) {
1262 theDEDXTable = p;
1263 if(isMaster && nullptr == baseParticle) {
1264 theData->UpdateTable(theDEDXTable, 0);
1265 }
1266 } else if(fIsIonisation == tType) {
1267 theIonisationTable = p;
1268 if(isMaster && nullptr == baseParticle) {
1269 theData->UpdateTable(theIonisationTable, 1);
1270 }
1271 }
1272}
1273
1274//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1275
1277{
1278 theCSDARangeTable = p;
1279}
1280
1281//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1282
1284{
1285 theRangeTableForLoss = p;
1286}
1287
1288//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1289
1291{
1292 theInverseRangeTable = p;
1293}
1294
1295//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1296
1298{
1299 if(1 < verboseLevel) {
1300 G4cout << "### Set Lambda table " << p << " " << theLambdaTable
1301 << " for " << particle->GetParticleName()
1302 << " and process " << GetProcessName() << G4endl;
1303 }
1304 theLambdaTable = p;
1305 tablesAreBuilt = true;
1306
1307 if(isMaster && nullptr != p) {
1308 delete theEnergyOfCrossSectionMax;
1309 theEnergyOfCrossSectionMax = nullptr;
1310 if(fEmTwoPeaks == fXSType) {
1311 if(nullptr != fXSpeaks) {
1312 for(auto & ptr : *fXSpeaks) { delete ptr; }
1313 delete fXSpeaks;
1314 }
1315 G4LossTableBuilder* bld = lManager->GetTableBuilder();
1316 fXSpeaks = G4EmUtility::FillPeaksStructure(p, bld);
1317 if(nullptr == fXSpeaks) { fXSType = fEmOnePeak; }
1318 }
1319 if(fXSType == fEmOnePeak) {
1320 theEnergyOfCrossSectionMax = G4EmUtility::FindCrossSectionMax(p);
1321 if(nullptr == theEnergyOfCrossSectionMax) { fXSType = fEmIncreasing; }
1322 }
1323 }
1324}
1325
1326//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1327
1329{
1330 theEnergyOfCrossSectionMax = p;
1331}
1332
1333//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1334
1335void G4VEnergyLossProcess::SetTwoPeaksXS(std::vector<G4TwoPeaksXS*>* ptr)
1336{
1337 fXSpeaks = ptr;
1338}
1339
1340//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1341
1343{
1344 return (nullptr != currentModel)
1345 ? currentModel->GetCurrentElement(currentMaterial) : nullptr;
1346}
1347
1348//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1349
1351 G4bool flag)
1352{
1353 if(f > 0.0) {
1354 biasFactor = f;
1355 weightFlag = flag;
1356 if(1 < verboseLevel) {
1357 G4cout << "### SetCrossSectionBiasingFactor: for "
1358 << " process " << GetProcessName()
1359 << " biasFactor= " << f << " weightFlag= " << flag
1360 << G4endl;
1361 }
1362 }
1363}
1364
1365//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1366
1368 const G4String& region,
1369 G4bool flag)
1370{
1371 if(nullptr == biasManager) { biasManager = new G4EmBiasingManager(); }
1372 if(1 < verboseLevel) {
1373 G4cout << "### ActivateForcedInteraction: for "
1374 << " process " << GetProcessName()
1375 << " length(mm)= " << length/mm
1376 << " in G4Region <" << region
1377 << "> weightFlag= " << flag
1378 << G4endl;
1379 }
1380 weightFlag = flag;
1381 biasManager->ActivateForcedInteraction(length, region);
1382}
1383
1384//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1385
1386void
1388 G4double factor,
1389 G4double energyLimit)
1390{
1391 if (0.0 <= factor) {
1392 // Range cut can be applied only for e-
1393 if(0.0 == factor && secondaryParticle != G4Electron::Electron())
1394 { return; }
1395
1396 if(nullptr == biasManager) { biasManager = new G4EmBiasingManager(); }
1397 biasManager->ActivateSecondaryBiasing(region, factor, energyLimit);
1398 if(1 < verboseLevel) {
1399 G4cout << "### ActivateSecondaryBiasing: for "
1400 << " process " << GetProcessName()
1401 << " factor= " << factor
1402 << " in G4Region <" << region
1403 << "> energyLimit(MeV)= " << energyLimit/MeV
1404 << G4endl;
1405 }
1406 }
1407}
1408
1409//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1410
1412{
1413 isIonisation = val;
1414 aGPILSelection = (val) ? CandidateForSelection : NotCandidateForSelection;
1415}
1416
1417//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1418
1420{
1421 G4cout << "### G4VEnergyLossProcess::SetLossFluctuations has no effect and "
1422 << "will be removed for the next major release" << G4endl;
1423}
1424
1425//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1426
1428{
1429 if(0.0 < val && val < 1.0) {
1430 linLossLimit = val;
1431 actLinLossLimit = true;
1432 } else { PrintWarning("SetLinearLossLimit", val); }
1433}
1434
1435//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1436
1438{
1439 if(0.0 < v1 && 1.0 >= v1 && 0.0 < v2) {
1440 dRoverRange = std::min(1.0, v1);
1441 finalRange = std::min(v2, 1.e+50);
1442 } else {
1443 PrintWarning("SetStepFunctionV1", v1);
1444 PrintWarning("SetStepFunctionV2", v2);
1445 }
1446}
1447
1448//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1449
1451{
1452 if(1.e-18 < val && val < 1.e+50) { lowestKinEnergy = val; }
1453 else { PrintWarning("SetLowestEnergyLimit", val); }
1454}
1455
1456//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1457
1459{
1460 if(2 < n && n < 1000000000) {
1461 nBins = n;
1462 actBinning = true;
1463 } else {
1464 G4double e = (G4double)n;
1465 PrintWarning("SetDEDXBinning", e);
1466 }
1467}
1468
1469//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1470
1472{
1473 if(1.e-18 < e && e < maxKinEnergy) {
1474 minKinEnergy = e;
1475 actMinKinEnergy = true;
1476 } else { PrintWarning("SetMinKinEnergy", e); }
1477}
1478
1479//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1480
1482{
1483 if(minKinEnergy < e && e < 1.e+50) {
1484 maxKinEnergy = e;
1485 actMaxKinEnergy = true;
1486 if(e < maxKinEnergyCSDA) { maxKinEnergyCSDA = e; }
1487 } else { PrintWarning("SetMaxKinEnergy", e); }
1488}
1489
1490//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1491
1492void G4VEnergyLossProcess::PrintWarning(const G4String& tit, G4double val) const
1493{
1494 G4String ss = "G4VEnergyLossProcess::" + tit;
1496 ed << "Parameter is out of range: " << val
1497 << " it will have no effect!\n" << " Process "
1498 << GetProcessName() << " nbins= " << nBins
1499 << " Emin(keV)= " << minKinEnergy/keV
1500 << " Emax(GeV)= " << maxKinEnergy/GeV;
1501 G4Exception(ss, "em0044", JustWarning, ed);
1502}
1503
1504//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1505
1506void G4VEnergyLossProcess::ProcessDescription(std::ostream& out) const
1507{
1508 if(nullptr != particle) { StreamInfo(out, *particle, true); }
1509}
1510
1511//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
@ fIonisation
G4EmTableType
@ fTotal
@ fRestricted
@ fIsIonisation
@ fEmOnePeak
@ fEmNoIntegral
@ fEmTwoPeaks
@ fEmIncreasing
G4double condition(const G4ErrorSymMatrix &m)
@ JustWarning
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
G4ForceCondition
@ NotForced
G4GPILSelection
@ CandidateForSelection
@ NotCandidateForSelection
G4double G4Log(G4double x)
Definition G4Log.hh:169
G4ProcessType
#define G4BestUnit(a, b)
@ fAlive
@ fStopAndKill
@ fStopButAlive
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition Randomize.hh:52
G4double GetLogKineticEnergy() const
G4double GetKineticEnergy() const
static G4Electron * Electron()
Definition G4Electron.cc:91
G4double ApplySecondaryBiasing(std::vector< G4DynamicParticle * > &, const G4Track &track, G4VEmModel *currentModel, G4ParticleChangeForGamma *pParticleChange, G4double &eloss, G4int coupleIdx, G4double tcut, G4double safety=0.0)
G4bool SecondaryBiasingRegion(G4int coupleIdx)
static G4EmParameters * Instance()
G4int NumberOfBinsPerDecade() const
static G4bool RetrieveTable(G4VProcess *ptr, const G4ParticleDefinition *part, G4PhysicsTable *aTable, const G4String &dir, const G4String &tname, const G4int verb, const G4bool ascii, const G4bool spline)
static void UpdateModels(G4VEnergyLossProcess *proc, G4EmModelManager *modelManager, const G4double maxKinEnergy, const G4int nModels, G4int &secID, G4int &biasID, G4int &mainSecondaries, const G4bool baseMat, const G4bool isMaster, const G4bool useAGen)
static void BuildLocalElossProcess(G4VEnergyLossProcess *proc, const G4VEnergyLossProcess *masterProc, const G4ParticleDefinition *part, const G4int nModels)
static G4bool StoreTable(G4VProcess *, const G4ParticleDefinition *, G4PhysicsTable *, const G4String &dir, const G4String &tname, G4int verb, G4bool ascii)
static void BuildDEDXTable(G4VEnergyLossProcess *proc, const G4ParticleDefinition *part, G4EmModelManager *modelManager, G4LossTableBuilder *bld, G4PhysicsTable *table, const G4double minKinEnergy, const G4double maxKinEnergy, const G4int nbins, const G4int verbose, const G4EmTableType tType, const G4bool splineFlag)
static const G4ParticleDefinition * CheckIon(G4VEnergyLossProcess *proc, const G4ParticleDefinition *part, const G4ParticleDefinition *particle, const G4int verboseLevel, G4bool &isIon)
static void BuildLambdaTable(G4VEmProcess *proc, const G4ParticleDefinition *part, G4EmModelManager *modelManager, G4LossTableBuilder *bld, G4PhysicsTable *theLambdaTable, G4PhysicsTable *theLambdaTablePrim, const G4double minKinEnergy, const G4double minKinEnergyPrim, const G4double maxKinEnergy, const G4double scale, const G4int verbose, const G4bool startFromNull, const G4bool splineFlag)
static std::vector< G4TwoPeaksXS * > * FillPeaksStructure(G4PhysicsTable *, G4LossTableBuilder *)
static std::vector< G4double > * FindCrossSectionMax(G4PhysicsTable *)
G4Region * GetRegion() const
static G4bool GetBaseMaterialFlag()
static const std::vector< G4double > * GetDensityFactors()
static const std::vector< G4bool > * GetFluctuationFlags()
void InitialiseBaseMaterials(const G4PhysicsTable *table=nullptr)
static const std::vector< G4int > * GetCoupleIndexes()
static G4LossTableManager * Instance()
const G4String & GetName() const
const G4String & GetParticleName() const
G4Region defines a region or a group of regions in the detector geometry setup, sharing properties as...
Definition G4Region.hh:90
const G4String & GetName() const
G4double GetSafety() const
G4double GetStepLength() const
G4StepPoint * GetPostStepPoint() const
const G4ParticleDefinition * GetParticleDefinition() const
G4VPhysicalVolume * GetVolume() const
void SetWeight(G4double aValue)
const G4ThreeVector & GetPosition() const
void SetTouchableHandle(const G4TouchableHandle &apValue)
G4double GetGlobalTime() const
G4Material * GetMaterial() const
const G4DynamicParticle * GetDynamicParticle() const
const G4TouchableHandle & GetTouchableHandle() const
G4double GetKineticEnergy() const
void SetCreatorModelID(const G4int id)
G4int GetParentID() const
const G4MaterialCutsCouple * GetMaterialCutsCouple() const
static G4TransportationManager * GetTransportationManager()
G4SafetyHelper * GetSafetyHelper() const
G4VContinuousDiscreteProcess(const G4String &, G4ProcessType aType=fNotDefined)
virtual G4double Dispersion(const G4Material *, const G4DynamicParticle *, const G4double tcut, const G4double tmax, const G4double length)=0
virtual G4double SampleFluctuations(const G4MaterialCutsCouple *, const G4DynamicParticle *, const G4double tcut, const G4double tmax, const G4double length, const G4double meanLoss)=0
void SetParticleChange(G4VParticleChange *, G4VEmFluctuationModel *f=nullptr)
void AddEmModel(G4int, G4VEmModel *, G4VEmFluctuationModel *fluc=nullptr, const G4Region *region=nullptr)
G4double GetContinuousStepLimit(const G4Track &track, G4double previousStepSize, G4double currentMinimumStep, G4double &currentSafety) override
G4ParticleChangeForLoss fParticleChange
void PreparePhysicsTable(const G4ParticleDefinition &) override
G4double MeanFreePath(const G4Track &track)
virtual void InitialiseEnergyLossProcess(const G4ParticleDefinition *, const G4ParticleDefinition *)=0
void SelectModel(G4double kinEnergy)
void SetRangeTableForLoss(G4PhysicsTable *p)
G4PhysicsVector * LambdaPhysicsVector(const G4MaterialCutsCouple *, G4double cut)
void ProcessDescription(std::ostream &outFile) const override
G4PhysicsTable * BuildDEDXTable(G4EmTableType tType=fRestricted)
void SetTwoPeaksXS(std::vector< G4TwoPeaksXS * > *)
const G4MaterialCutsCouple * currentCouple
virtual G4double MinPrimaryEnergy(const G4ParticleDefinition *, const G4Material *, G4double cut)
void ActivateSecondaryBiasing(const G4String &region, G4double factor, G4double energyLimit)
G4double PostStepGetPhysicalInteractionLength(const G4Track &track, G4double previousStepSize, G4ForceCondition *condition) override
const G4Element * GetCurrentElement() const
void SetDEDXBinning(G4int nbins)
void SetStepFunction(G4double v1, G4double v2)
void SetEmModel(G4VEmModel *, G4int index=0)
void SetCrossSectionBiasingFactor(G4double f, G4bool flag=true)
const G4Material * currentMaterial
G4double GetMeanFreePath(const G4Track &track, G4double previousStepSize, G4ForceCondition *condition) override
G4double ContinuousStepLimit(const G4Track &track, G4double previousStepSize, G4double currentMinimumStep, G4double &currentSafety)
void SetInverseRangeTable(G4PhysicsTable *p)
G4bool RetrievePhysicsTable(const G4ParticleDefinition *, const G4String &directory, G4bool ascii) override
void ActivateForcedInteraction(G4double length, const G4String &region, G4bool flag=true)
void SetDynamicMassCharge(G4double massratio, G4double charge2ratio)
void SetEnergyOfCrossSectionMax(std::vector< G4double > *)
G4double CrossSectionPerVolume(G4double kineticEnergy, const G4MaterialCutsCouple *couple)
void SetDEDXTable(G4PhysicsTable *p, G4EmTableType tType)
G4PhysicsTable * BuildLambdaTable(G4EmTableType tType=fRestricted)
G4bool StorePhysicsTable(const G4ParticleDefinition *, const G4String &directory, G4bool ascii=false) override
G4double AlongStepGetPhysicalInteractionLength(const G4Track &, G4double previousStepSize, G4double currentMinimumStep, G4double &currentSafety, G4GPILSelection *selection) override
void SetLinearLossLimit(G4double val)
void SetLambdaTable(G4PhysicsTable *p)
void BuildPhysicsTable(const G4ParticleDefinition &) override
G4VEnergyLossProcess(const G4String &name="EnergyLoss", G4ProcessType type=fElectromagnetic)
G4VParticleChange * AlongStepDoIt(const G4Track &, const G4Step &) override
G4double GetDEDXDispersion(const G4MaterialCutsCouple *couple, const G4DynamicParticle *dp, G4double length)
void ActivateSubCutoff(const G4Region *region)
void SetCSDARangeTable(G4PhysicsTable *pRange)
virtual void StreamProcessInfo(std::ostream &) const
G4VParticleChange * PostStepDoIt(const G4Track &, const G4Step &) override
void StartTracking(G4Track *) override
G4LogicalVolume * GetLogicalVolume() const
G4double currentInteractionLength
G4double theInitialNumberOfInteractionLength
void SetVerboseLevel(G4int value)
const G4VProcess * GetMasterProcess() const
G4int verboseLevel
G4double theNumberOfInteractionLengthLeft
G4VParticleChange * pParticleChange
G4int GetProcessSubType() const
const G4String & GetProcessName() const
G4double e1peak
G4double e3peak
G4double e2deep
G4double e1deep
G4double e2peak
int G4lrint(double ad)
Definition templates.hh:134
#define DBL_MAX
Definition templates.hh:62