source: trunk/source/processes/electromagnetic/utils/src/G4VEnergyLossProcess.cc@ 1007

Last change on this file since 1007 was 1007, checked in by garnier, 17 years ago

update to geant4.9.2

File size: 52.5 KB
Line 
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// $Id: G4VEnergyLossProcess.cc,v 1.143 2008/10/17 14:46:16 vnivanch Exp $
27// GEANT4 tag $Name: geant4-09-02 $
28//
29// -------------------------------------------------------------------
30//
31// GEANT4 Class file
32//
33//
34// File name: G4VEnergyLossProcess
35//
36// Author: Vladimir Ivanchenko
37//
38// Creation date: 03.01.2002
39//
40// Modifications:
41//
42// 13-11-02 Minor fix - use normalised direction (V.Ivanchenko)
43// 04-12-02 Minor change in PostStepDoIt (V.Ivanchenko)
44// 23-12-02 Change interface in order to move to cut per region (V.Ivanchenko)
45// 26-12-02 Secondary production moved to derived classes (V.Ivanchenko)
46// 04-01-03 Fix problem of very small steps for ions (V.Ivanchenko)
47// 20-01-03 Migrade to cut per region (V.Ivanchenko)
48// 24-01-03 Temporarily close a control on usage of couples (V.Ivanchenko)
49// 24-01-03 Make models region aware (V.Ivanchenko)
50// 05-02-03 Fix compilation warnings (V.Ivanchenko)
51// 06-02-03 Add control on tmax in PostStepDoIt (V.Ivanchenko)
52// 13-02-03 SubCutoffProcessors defined for regions (V.Ivanchenko)
53// 15-02-03 Lambda table can be scaled (V.Ivanchenko)
54// 17-02-03 Fix problem of store/restore tables (V.Ivanchenko)
55// 18-02-03 Add control on CutCouple usage (V.Ivanchenko)
56// 26-02-03 Simplify control on GenericIons (V.Ivanchenko)
57// 06-03-03 Control on GenericIons using SubType + update verbose (V.Ivanchenko)
58// 10-03-03 Add Ion registration (V.Ivanchenko)
59// 22-03-03 Add Initialisation of cash (V.Ivanchenko)
60// 26-03-03 Remove finalRange modification (V.Ivanchenko)
61// 09-04-03 Fix problem of negative range limit for non integral (V.Ivanchenko)
62// 26-04-03 Fix retrieve tables (V.Ivanchenko)
63// 06-05-03 Set defalt finalRange = 1 mm (V.Ivanchenko)
64// 12-05-03 Update range calculations + lowKinEnergy (V.Ivanchenko)
65// 13-05-03 Add calculation of precise range (V.Ivanchenko)
66// 23-05-03 Remove tracking cuts (V.Ivanchenko)
67// 03-06-03 Fix initialisation problem for STD ionisation (V.Ivanchenko)
68// 21-07-03 Add UpdateEmModel method (V.Ivanchenko)
69// 03-11-03 Fix initialisation problem in RetrievePhysicsTable (V.Ivanchenko)
70// 04-11-03 Add checks in RetrievePhysicsTable (V.Ivanchenko)
71// 12-11-03 G4EnergyLossSTD -> G4EnergyLossProcess (V.Ivanchenko)
72// 21-01-04 Migrade to G4ParticleChangeForLoss (V.Ivanchenko)
73// 27-02-04 Fix problem of loss in low presure gases, cleanup precise range
74// calculation, use functions ForLoss in AlongStepDoIt (V.Ivanchenko)
75// 10-03-04 Fix a problem of Precise Range table (V.Ivanchenko)
76// 19-03-04 Fix a problem energy below lowestKinEnergy (V.Ivanchenko)
77// 31-03-04 Fix a problem of retrieve tables (V.Ivanchenko)
78// 21-07-04 Check weather AtRest are active or not (V.Ivanchenko)
79// 03-08-04 Add pointer of DEDX table to all processes (V.Ivanchenko)
80// 06-08-04 Clear up names of member functions (V.Ivanchenko)
81// 06-08-04 Clear up names of member functions (V.Ivanchenko)
82// 27-08-04 Add NeedBuildTables method (V.Ivanchneko)
83// 08-11-04 Migration to new interface of Store/Retrieve tables (V.Ivantchenko)
84// 11-03-05 Shift verbose level by 1 (V.Ivantchenko)
85// 08-04-05 Major optimisation of internal interfaces (V.Ivantchenko)
86// 11-04-05 Use MaxSecondaryEnergy from a model (V.Ivanchenko)
87// 25-07-05 Add extra protection PostStep for non-integral mode (V.Ivanchenko)
88// 12-08-05 Integral=false; SetStepFunction(0.2, 0.1*mm) (mma)
89// 18-08-05 Return back both AlongStep and PostStep from 7.0 (V.Ivanchenko)
90// 02-09-05 Default StepFunction 0.2 1 mm + integral (V.Ivanchenko)
91// 04-09-05 default lambdaFactor 0.8 (V.Ivanchenko)
92// 05-10-05 protection against 0 energy loss added (L.Urban)
93// 17-10-05 protection above has been removed (L.Urban)
94// 06-01-06 reset currentCouple when StepFunction is changed (V.Ivanchenko)
95// 10-01-06 PreciseRange -> CSDARange (V.Ivantchenko)
96// 18-01-06 Clean up subcutoff including recalculation of presafety (VI)
97// 20-01-06 Introduce G4EmTableType and reducing number of methods (VI)
98// 22-03-06 Add control on warning printout AlongStep (VI)
99// 23-03-06 Use isIonisation flag (V.Ivanchenko)
100// 07-06-06 Do not reflect AlongStep in subcutoff regime (V.Ivanchenko)
101// 14-01-07 add SetEmModel(index) and SetFluctModel() (mma)
102// 16-01-07 add IonisationTable and IonisationSubTable (V.Ivanchenko)
103// 16-02-07 set linLossLimit=1.e-6 (V.Ivanchenko)
104// 13-03-07 use SafetyHelper instead of navigator (V.Ivanchenko)
105// 10-04-07 use unique SafetyHelper (V.Ivanchenko)
106// 12-04-07 Add verbosity at destruction (V.Ivanchenko)
107// 25-04-07 move initialisation of safety helper to BuildPhysicsTable (VI)
108// 27-10-07 Virtual functions moved to source (V.Ivanchenko)
109//
110// Class Description:
111//
112// It is the unified energy loss process it calculates the continuous
113// energy loss for charged particles using a set of Energy Loss
114// models valid for different energy regions. There are a possibility
115// to create and access to dE/dx and range tables, or to calculate
116// that information on fly.
117// -------------------------------------------------------------------
118//
119//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
120//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
121
122#include "G4VEnergyLossProcess.hh"
123#include "G4LossTableManager.hh"
124#include "G4Step.hh"
125#include "G4ParticleDefinition.hh"
126#include "G4VEmModel.hh"
127#include "G4VEmFluctuationModel.hh"
128#include "G4DataVector.hh"
129#include "G4PhysicsLogVector.hh"
130#include "G4VParticleChange.hh"
131#include "G4Gamma.hh"
132#include "G4Electron.hh"
133#include "G4Positron.hh"
134#include "G4Proton.hh"
135#include "G4ProcessManager.hh"
136#include "G4UnitsTable.hh"
137#include "G4GenericIon.hh"
138#include "G4ProductionCutsTable.hh"
139#include "G4Region.hh"
140#include "G4RegionStore.hh"
141#include "G4PhysicsTableHelper.hh"
142#include "G4SafetyHelper.hh"
143#include "G4TransportationManager.hh"
144
145//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
146
147G4VEnergyLossProcess::G4VEnergyLossProcess(const G4String& name,
148 G4ProcessType type):
149 G4VContinuousDiscreteProcess(name, type),
150 secondaryParticle(0),
151 nSCoffRegions(0),
152 idxSCoffRegions(0),
153 nProcesses(0),
154 theDEDXTable(0),
155 theDEDXSubTable(0),
156 theDEDXunRestrictedTable(0),
157 theIonisationTable(0),
158 theIonisationSubTable(0),
159 theRangeTableForLoss(0),
160 theCSDARangeTable(0),
161 theSecondaryRangeTable(0),
162 theInverseRangeTable(0),
163 theLambdaTable(0),
164 theSubLambdaTable(0),
165 theDEDXAtMaxEnergy(0),
166 theRangeAtMaxEnergy(0),
167 theEnergyOfCrossSectionMax(0),
168 theCrossSectionMax(0),
169 baseParticle(0),
170 minSubRange(0.1),
171 lossFluctuationFlag(true),
172 rndmStepFlag(false),
173 tablesAreBuilt(false),
174 integral(true),
175 isIon(false),
176 isIonisation(true),
177 useSubCutoff(false),
178 particle(0),
179 currentCouple(0),
180 nWarnings(0),
181 mfpKinEnergy(0.0)
182{
183 SetVerboseLevel(1);
184
185 // low energy limit
186 lowestKinEnergy = 1.*eV;
187
188 // Size of tables assuming spline
189 minKinEnergy = 0.1*keV;
190 maxKinEnergy = 100.0*TeV;
191 nBins = 84;
192 maxKinEnergyCSDA = 1.0*GeV;
193 nBinsCSDA = 35;
194
195 // default linear loss limit for spline
196 linLossLimit = 0.01;
197
198 // default dRoverRange and finalRange
199 SetStepFunction(0.2, 1.0*mm);
200
201 // default lambda factor
202 lambdaFactor = 0.8;
203
204 // particle types
205 theElectron = G4Electron::Electron();
206 thePositron = G4Positron::Positron();
207 theGenericIon = 0;
208
209 // run time objects
210 pParticleChange = &fParticleChange;
211 modelManager = new G4EmModelManager();
212 safetyHelper = G4TransportationManager::GetTransportationManager()
213 ->GetSafetyHelper();
214 aGPILSelection = CandidateForSelection;
215
216 // initialise model
217 (G4LossTableManager::Instance())->Register(this);
218 fluctModel = 0;
219
220 scTracks.reserve(5);
221 secParticles.reserve(5);
222
223 // Data for stragling of ranges from ICRU'37 report
224 const G4int nrbins = 7;
225 vstrag = new G4PhysicsLogVector(keV, GeV, nrbins-1);
226 vstrag->SetSpline(true);
227 G4double s[nrbins] = {-0.2, -0.85, -1.3, -1.578, -1.76, -1.85, -1.9};
228 for(G4int i=0; i<nrbins; i++) {vstrag->PutValue(i, s[i]);}
229}
230
231//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
232
233G4VEnergyLossProcess::~G4VEnergyLossProcess()
234{
235 if(1 < verboseLevel)
236 G4cout << "G4VEnergyLossProcess destruct " << GetProcessName()
237 << G4endl;
238 delete vstrag;
239 Clear();
240
241 if ( !baseParticle ) {
242 if(theDEDXTable && theRangeTableForLoss) {
243 if(theIonisationTable == theDEDXTable) theIonisationTable = 0;
244 theDEDXTable->clearAndDestroy();
245 delete theDEDXTable;
246 if(theDEDXSubTable) {
247 if(theIonisationSubTable == theDEDXSubTable)
248 theIonisationSubTable = 0;
249 theDEDXSubTable->clearAndDestroy();
250 delete theDEDXSubTable;
251 }
252 }
253 if(theIonisationTable) {
254 theIonisationTable->clearAndDestroy();
255 delete theIonisationTable;
256 }
257 if(theIonisationSubTable) {
258 theIonisationSubTable->clearAndDestroy();
259 delete theIonisationSubTable;
260 }
261 if(theDEDXunRestrictedTable && theCSDARangeTable) {
262 theDEDXunRestrictedTable->clearAndDestroy();
263 delete theDEDXunRestrictedTable;
264 }
265 if(theCSDARangeTable) {
266 theCSDARangeTable->clearAndDestroy();
267 delete theCSDARangeTable;
268 }
269 if(theRangeTableForLoss) {
270 theRangeTableForLoss->clearAndDestroy();
271 delete theRangeTableForLoss;
272 }
273 if(theInverseRangeTable) {
274 theInverseRangeTable->clearAndDestroy();
275 delete theInverseRangeTable;
276 }
277 if(theLambdaTable) {
278 theLambdaTable->clearAndDestroy();
279 delete theLambdaTable;
280 }
281 if(theSubLambdaTable) {
282 theSubLambdaTable->clearAndDestroy();
283 delete theSubLambdaTable;
284 }
285 }
286
287 delete modelManager;
288 (G4LossTableManager::Instance())->DeRegister(this);
289}
290
291//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
292
293void G4VEnergyLossProcess::Clear()
294{
295 if(1 < verboseLevel) {
296 G4cout << "G4VEnergyLossProcess::Clear() for " << GetProcessName()
297 << G4endl;
298 }
299 delete [] theDEDXAtMaxEnergy;
300 delete [] theRangeAtMaxEnergy;
301 delete [] theEnergyOfCrossSectionMax;
302 delete [] theCrossSectionMax;
303 delete [] idxSCoffRegions;
304
305 theDEDXAtMaxEnergy = 0;
306 theRangeAtMaxEnergy = 0;
307 theEnergyOfCrossSectionMax = 0;
308 theCrossSectionMax = 0;
309 tablesAreBuilt = false;
310
311 //scTracks.clear();
312 scProcesses.clear();
313 nProcesses = 0;
314}
315
316//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
317
318void
319G4VEnergyLossProcess::PreparePhysicsTable(const G4ParticleDefinition& part)
320{
321 if(1 < verboseLevel) {
322 G4cout << "G4VEnergyLossProcess::PreparePhysicsTable for "
323 << GetProcessName()
324 << " for " << part.GetParticleName()
325 << G4endl;
326 }
327
328 currentCouple = 0;
329 preStepLambda = 0.0;
330 mfpKinEnergy = DBL_MAX;
331 fRange = DBL_MAX;
332 preStepKinEnergy = 0.0;
333 chargeSqRatio = 1.0;
334 massRatio = 1.0;
335 reduceFactor = 1.0;
336
337 G4LossTableManager* lManager = G4LossTableManager::Instance();
338
339 // Are particle defined?
340 if( !particle ) {
341 particle = &part;
342 if(part.GetParticleType() == "nucleus") {
343 if(!theGenericIon) theGenericIon = G4GenericIon::GenericIon();
344 if(particle == theGenericIon) { isIon = true; }
345 else if(part.GetPDGCharge() > eplus) {
346 isIon = true;
347
348 // generic ions created on-fly
349 if(part.GetPDGCharge() > 2.5*eplus) {
350 particle = theGenericIon;
351 }
352 }
353 }
354 }
355
356 if( particle != &part) {
357 if(part.GetParticleType() == "nucleus") {
358 isIon = true;
359 lManager->RegisterIon(&part, this);
360 } else {
361 lManager->RegisterExtraParticle(&part, this);
362 }
363 return;
364 }
365
366 Clear();
367
368 // Base particle and set of models can be defined here
369 InitialiseEnergyLossProcess(particle, baseParticle);
370
371 // Tables preparation
372 if (!baseParticle) {
373
374 theDEDXTable = G4PhysicsTableHelper::PreparePhysicsTable(theDEDXTable);
375 if (lManager->BuildCSDARange()) {
376 theDEDXunRestrictedTable =
377 G4PhysicsTableHelper::PreparePhysicsTable(theDEDXunRestrictedTable);
378 theCSDARangeTable =
379 G4PhysicsTableHelper::PreparePhysicsTable(theCSDARangeTable);
380 }
381
382 theRangeTableForLoss =
383 G4PhysicsTableHelper::PreparePhysicsTable(theRangeTableForLoss);
384 theInverseRangeTable =
385 G4PhysicsTableHelper::PreparePhysicsTable(theInverseRangeTable);
386
387 theLambdaTable = G4PhysicsTableHelper::PreparePhysicsTable(theLambdaTable);
388 if (nSCoffRegions) {
389 theDEDXSubTable =
390 G4PhysicsTableHelper::PreparePhysicsTable(theDEDXSubTable);
391 theSubLambdaTable =
392 G4PhysicsTableHelper::PreparePhysicsTable(theSubLambdaTable);
393 }
394 }
395
396 G4double initialCharge = particle->GetPDGCharge();
397 G4double initialMass = particle->GetPDGMass();
398
399 if (baseParticle) {
400 massRatio = (baseParticle->GetPDGMass())/initialMass;
401 G4double q = initialCharge/baseParticle->GetPDGCharge();
402 chargeSqRatio = q*q;
403 if(chargeSqRatio > 0.0) reduceFactor = 1.0/(chargeSqRatio*massRatio);
404 }
405
406 theCuts = modelManager->Initialise(particle, secondaryParticle,
407 minSubRange, verboseLevel);
408
409 // Sub Cutoff Regime
410 if (nSCoffRegions>0) {
411 theSubCuts = modelManager->SubCutoff();
412
413 const G4ProductionCutsTable* theCoupleTable=
414 G4ProductionCutsTable::GetProductionCutsTable();
415 size_t numOfCouples = theCoupleTable->GetTableSize();
416 idxSCoffRegions = new G4int[numOfCouples];
417
418 for (size_t j=0; j<numOfCouples; j++) {
419
420 const G4MaterialCutsCouple* couple =
421 theCoupleTable->GetMaterialCutsCouple(j);
422 const G4ProductionCuts* pcuts = couple->GetProductionCuts();
423 G4int reg = 0;
424 for(G4int i=0; i<nSCoffRegions; i++) {
425 if( pcuts == scoffRegions[i]->GetProductionCuts()) reg = 1;
426 }
427 idxSCoffRegions[j] = reg;
428 }
429 }
430
431 lManager->EnergyLossProcessIsInitialised(particle, this);
432
433 if (1 < verboseLevel) {
434 G4cout << "G4VEnergyLossProcess::Initialise() is done "
435 << " for local " << particle->GetParticleName()
436 << " isIon= " << isIon
437 << " chargeSqRatio= " << chargeSqRatio
438 << " massRatio= " << massRatio
439 << " reduceFactor= " << reduceFactor << G4endl;
440 if (nSCoffRegions) {
441 G4cout << " SubCutoff Regime is ON for regions: " << G4endl;
442 for (G4int i=0; i<nSCoffRegions; i++) {
443 const G4Region* r = scoffRegions[i];
444 G4cout << " " << r->GetName() << G4endl;
445 }
446 }
447 }
448}
449
450//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
451
452void G4VEnergyLossProcess::BuildPhysicsTable(const G4ParticleDefinition& part)
453{
454 if(1 < verboseLevel) {
455 G4cout << "### G4VEnergyLossProcess::BuildPhysicsTable() for "
456 << GetProcessName()
457 << " and particle " << part.GetParticleName()
458 << "; local: " << particle->GetParticleName();
459 if(baseParticle) G4cout << "; base: " << baseParticle->GetParticleName();
460 G4cout << G4endl;
461 }
462
463 if(&part == particle) {
464 if(!tablesAreBuilt) {
465 G4LossTableManager::Instance()->BuildPhysicsTable(particle, this);
466 }
467 if(!baseParticle) {
468 if(0 < verboseLevel) PrintInfoDefinition();
469
470 // needs to be done only once
471 safetyHelper->InitialiseHelper();
472 }
473 }
474
475 if(1 < verboseLevel) {
476 G4cout << "### G4VEnergyLossProcess::BuildPhysicsTable() done for "
477 << GetProcessName()
478 << " and particle " << part.GetParticleName();
479 if(isIonisation) G4cout << " isIonisation flag = 1";
480 G4cout << G4endl;
481 }
482}
483
484//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
485
486void G4VEnergyLossProcess::ActivateSubCutoff(G4bool val, const G4Region* r)
487{
488 G4RegionStore* regionStore = G4RegionStore::GetInstance();
489 if(val) {
490 useSubCutoff = true;
491 if (!r) {r = regionStore->GetRegion("DefaultRegionForTheWorld", false);}
492 if (nSCoffRegions) {
493 for (G4int i=0; i<nSCoffRegions; i++) {
494 if (r == scoffRegions[i]) return;
495 }
496 }
497 scoffRegions.push_back(r);
498 nSCoffRegions++;
499 } else {
500 useSubCutoff = false;
501 }
502}
503
504//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
505
506G4PhysicsTable* G4VEnergyLossProcess::BuildDEDXTable(G4EmTableType tType)
507{
508 if(1 < verboseLevel) {
509 G4cout << "G4VEnergyLossProcess::BuildDEDXTable() of type " << tType
510 << " for " << GetProcessName()
511 << " and particle " << particle->GetParticleName()
512 << G4endl;
513 }
514 G4PhysicsTable* table = 0;
515 G4double emin = minKinEnergy;
516 G4double emax = maxKinEnergy;
517 G4int bin = nBins;
518
519 if(fTotal == tType) {
520 emax = maxKinEnergyCSDA;
521 bin = nBinsCSDA;
522 table = theDEDXunRestrictedTable;
523 } else if(fRestricted == tType) {
524 table = theDEDXTable;
525 if(theIonisationTable)
526 table = G4PhysicsTableHelper::PreparePhysicsTable(theIonisationTable);
527 } else if(fSubRestricted == tType) {
528 table = theDEDXSubTable;
529 if(theIonisationSubTable)
530 table = G4PhysicsTableHelper::PreparePhysicsTable(theIonisationSubTable);
531 } else {
532 G4cout << "G4VEnergyLossProcess::BuildDEDXTable WARNING: wrong type "
533 << tType << G4endl;
534 }
535
536 // Access to materials
537 const G4ProductionCutsTable* theCoupleTable=
538 G4ProductionCutsTable::GetProductionCutsTable();
539 size_t numOfCouples = theCoupleTable->GetTableSize();
540
541 if(1 < verboseLevel) {
542 G4cout << numOfCouples << " materials"
543 << " minKinEnergy= " << minKinEnergy
544 << " maxKinEnergy= " << maxKinEnergy
545 << " EmTableType= " << tType
546 << " table= " << table
547 << G4endl;
548 }
549 if(!table) return table;
550
551 for(size_t i=0; i<numOfCouples; i++) {
552
553 if(1 < verboseLevel) {
554 G4cout << "G4VEnergyLossProcess::BuildDEDXVector flag= "
555 << table->GetFlag(i) << G4endl;
556 }
557 if (table->GetFlag(i)) {
558
559 // create physics vector and fill it
560 const G4MaterialCutsCouple* couple =
561 theCoupleTable->GetMaterialCutsCouple(i);
562 G4PhysicsVector* aVector = new G4PhysicsLogVector(emin, emax, bin);
563 aVector->SetSpline((G4LossTableManager::Instance())->SplineFlag());
564
565 modelManager->FillDEDXVector(aVector, couple, tType);
566
567 // Insert vector for this material into the table
568 G4PhysicsTableHelper::SetPhysicsVector(table, i, aVector);
569 }
570 }
571
572 if(1 < verboseLevel) {
573 G4cout << "G4VEnergyLossProcess::BuildDEDXTable(): table is built for "
574 << particle->GetParticleName()
575 << " and process " << GetProcessName()
576 << G4endl;
577 // if(2 < verboseLevel) G4cout << (*table) << G4endl;
578 }
579
580 return table;
581}
582
583//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
584
585G4PhysicsTable* G4VEnergyLossProcess::BuildLambdaTable(G4EmTableType tType)
586{
587 G4PhysicsTable* table = 0;
588
589 if(fRestricted == tType) {
590 table = theLambdaTable;
591 } else if(fSubRestricted == tType) {
592 table = theSubLambdaTable;
593 } else {
594 G4cout << "G4VEnergyLossProcess::BuildLambdaTable WARNING: wrong type "
595 << tType << G4endl;
596 }
597
598 if(1 < verboseLevel) {
599 G4cout << "G4VEnergyLossProcess::BuildLambdaTable() of type "
600 << tType << " for process "
601 << GetProcessName() << " and particle "
602 << particle->GetParticleName()
603 << " EmTableType= " << tType
604 << " table= " << table
605 << G4endl;
606 }
607 if(!table) {return table;}
608
609 // Access to materials
610 const G4ProductionCutsTable* theCoupleTable=
611 G4ProductionCutsTable::GetProductionCutsTable();
612 size_t numOfCouples = theCoupleTable->GetTableSize();
613
614 for(size_t i=0; i<numOfCouples; i++) {
615
616 if (table->GetFlag(i)) {
617
618 // create physics vector and fill it
619 const G4MaterialCutsCouple* couple =
620 theCoupleTable->GetMaterialCutsCouple(i);
621 G4double cut = (*theCuts)[i];
622 if(fSubRestricted == tType) cut = (*theSubCuts)[i];
623 G4PhysicsVector* aVector = LambdaPhysicsVector(couple, cut);
624 modelManager->FillLambdaVector(aVector, couple, true, tType);
625
626 // Insert vector for this material into the table
627 G4PhysicsTableHelper::SetPhysicsVector(table, i, aVector);
628 }
629 }
630
631 if(1 < verboseLevel) {
632 G4cout << "Lambda table is built for "
633 << particle->GetParticleName()
634 << G4endl;
635 }
636
637 return table;
638}
639
640//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
641
642G4double G4VEnergyLossProcess::GetContinuousStepLimit(
643 const G4Track&,
644 G4double, G4double, G4double&)
645{
646 return DBL_MAX;
647}
648
649//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
650
651G4double G4VEnergyLossProcess::AlongStepGetPhysicalInteractionLength(
652 const G4Track&,
653 G4double,
654 G4double currentMinStep,
655 G4double&,
656 G4GPILSelection* selection)
657{
658 G4double x = DBL_MAX;
659 *selection = aGPILSelection;
660 if(isIonisation) {
661 fRange = GetScaledRangeForScaledEnergy(preStepScaledEnergy)*reduceFactor;
662
663 x = fRange;
664 G4double y = x*dRoverRange;
665
666 if(x > finalRange && y < currentMinStep) {
667 x = y + finalRange*(1.0 - dRoverRange)*(2.0 - finalRange/fRange);
668 } else if (rndmStepFlag) {x = SampleRange();}
669 //G4cout<<GetProcessName()<<": e= "<<preStepKinEnergy
670 // <<" range= "<<fRange <<" cMinSt="<<currentMinStep
671 // << " limit= " << x <<G4endl;
672 }
673 //G4cout<<GetProcessName()<<": e= "<<preStepKinEnergy
674 // <<" stepLimit= "<<x<<G4endl;
675 return x;
676}
677
678//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
679
680G4double G4VEnergyLossProcess::GetMeanFreePath(
681 const G4Track& track,
682 G4double,
683 G4ForceCondition* condition)
684
685{
686 *condition = NotForced;
687 return MeanFreePath(track);
688}
689
690//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
691
692G4double G4VEnergyLossProcess::PostStepGetPhysicalInteractionLength(
693 const G4Track& track,
694 G4double previousStepSize,
695 G4ForceCondition* condition)
696{
697 // condition is set to "Not Forced"
698 *condition = NotForced;
699 G4double x = DBL_MAX;
700
701 // initialisation of material, mass, charge, model at the beginning of the step
702 DefineMaterial(track.GetMaterialCutsCouple());
703
704 const G4ParticleDefinition* currPart = track.GetDefinition();
705 if(theGenericIon == particle) {
706 massRatio = proton_mass_c2/currPart->GetPDGMass();
707 }
708 preStepKinEnergy = track.GetKineticEnergy();
709 preStepScaledEnergy = preStepKinEnergy*massRatio;
710 SelectModel(preStepScaledEnergy);
711
712 if(isIon) {
713 chargeSqRatio =
714 currentModel->GetChargeSquareRatio(currPart,currentMaterial,preStepKinEnergy);
715 reduceFactor = 1.0/(chargeSqRatio*massRatio);
716 }
717 //G4cout << "q2= " << chargeSqRatio << " massRatio= " << massRatio << G4endl;
718 // initialisation for sampling of the interaction length
719 if(previousStepSize <= DBL_MIN) theNumberOfInteractionLengthLeft = -1.0;
720 if(theNumberOfInteractionLengthLeft < 0.0) mfpKinEnergy = DBL_MAX;
721
722 // compute mean free path
723 if(preStepScaledEnergy < mfpKinEnergy) {
724 if (integral) ComputeLambdaForScaledEnergy(preStepScaledEnergy);
725 else preStepLambda = GetLambdaForScaledEnergy(preStepScaledEnergy);
726 if(preStepLambda <= DBL_MIN) mfpKinEnergy = 0.0;
727 }
728
729 // non-zero cross section
730 if(preStepLambda > DBL_MIN) {
731 if (theNumberOfInteractionLengthLeft < 0.0) {
732 // beggining of tracking (or just after DoIt of this process)
733 //G4cout<<"G4VEnergyLossProcess::PostStepGetPhysicalInteractionLength Reset"<<G4endl;
734 ResetNumberOfInteractionLengthLeft();
735 } else if(currentInteractionLength < DBL_MAX) {
736 // subtract NumberOfInteractionLengthLeft
737 SubtractNumberOfInteractionLengthLeft(previousStepSize);
738 if(theNumberOfInteractionLengthLeft < 0.)
739 theNumberOfInteractionLengthLeft = perMillion;
740 }
741
742 // get mean free path and step limit
743 currentInteractionLength = 1.0/preStepLambda;
744 x = theNumberOfInteractionLengthLeft * currentInteractionLength;
745
746#ifdef G4VERBOSE
747 if (verboseLevel>2){
748 G4cout << "G4VEnergyLossProcess::PostStepGetPhysicalInteractionLength ";
749 G4cout << "[ " << GetProcessName() << "]" << G4endl;
750 G4cout << " for " << currPart->GetParticleName()
751 << " in Material " << currentMaterial->GetName()
752 << " Ekin(MeV)= " << preStepKinEnergy/MeV
753 <<G4endl;
754 G4cout << "MeanFreePath = " << currentInteractionLength/cm << "[cm]"
755 << "InteractionLength= " << x/cm <<"[cm] " <<G4endl;
756 }
757#endif
758 // zero cross section case
759 } else {
760 if(theNumberOfInteractionLengthLeft > DBL_MIN &&
761 currentInteractionLength < DBL_MAX) {
762 // subtract NumberOfInteractionLengthLeft
763 SubtractNumberOfInteractionLengthLeft(previousStepSize);
764 if(theNumberOfInteractionLengthLeft < 0.)
765 theNumberOfInteractionLengthLeft = perMillion;
766 }
767 currentInteractionLength = DBL_MAX;
768 }
769 return x;
770}
771
772//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
773
774G4VParticleChange* G4VEnergyLossProcess::AlongStepDoIt(const G4Track& track,
775 const G4Step& step)
776{
777 fParticleChange.InitializeForAlongStep(track);
778 // The process has range table - calculate energy loss
779 if(!isIonisation) return &fParticleChange;
780
781 // Get the actual (true) Step length
782 G4double length = step.GetStepLength();
783 if(length <= DBL_MIN) return &fParticleChange;
784 G4double eloss = 0.0;
785 G4double esecdep = 0.0;
786
787 /*
788 if(-1 < verboseLevel) {
789 const G4ParticleDefinition* d = track.GetDefinition();
790 G4cout << "AlongStepDoIt for "
791 << GetProcessName() << " and particle "
792 << d->GetParticleName()
793 << " eScaled(MeV)= " << preStepScaledEnergy/MeV
794 << " range(mm)= " << fRange/mm
795 << " s(mm)= " << length/mm
796 << " q^2= " << chargeSqRatio
797 << " md= " << d->GetPDGMass()
798 << " status= " << track.GetTrackStatus()
799 << G4endl;
800 }
801 */
802
803 const G4DynamicParticle* dynParticle = track.GetDynamicParticle();
804
805 // stopping
806 if (length >= fRange) {
807 eloss = preStepKinEnergy;
808 currentModel->CorrectionsAlongStep(currentCouple, dynParticle,
809 eloss, esecdep, length);
810 fParticleChange.SetProposedKineticEnergy(0.0);
811 fParticleChange.ProposeLocalEnergyDeposit(preStepKinEnergy);
812 return &fParticleChange;
813 }
814
815 // Short step
816 eloss = GetDEDXForScaledEnergy(preStepScaledEnergy)*length;
817
818 // Long step
819 //} else {
820 if(eloss > preStepKinEnergy*linLossLimit) {
821
822 G4double x =
823 GetScaledRangeForScaledEnergy(preStepScaledEnergy) - length/reduceFactor;
824 eloss = preStepKinEnergy - ScaledKinEnergyForLoss(x)/massRatio;
825
826 /*
827 if(-1 < verboseLevel)
828 G4cout << "Long STEP: rPre(mm)= "
829 << GetScaledRangeForScaledEnergy(preStepScaledEnergy)/mm
830 << " rPost(mm)= " << x/mm
831 << " ePre(MeV)= " << preStepScaledEnergy/MeV
832 << " eloss(MeV)= " << eloss/MeV
833 << " eloss0(MeV)= "
834 << GetDEDXForScaledEnergy(preStepScaledEnergy)*length/MeV
835 << " lim(MeV)= " << preStepKinEnergy*linLossLimit/MeV
836 << G4endl;
837 */
838 }
839
840 /*
841 G4double eloss0 = eloss;
842 if(-1 < verboseLevel ) {
843 G4cout << "Before fluct: eloss(MeV)= " << eloss/MeV
844 << " e-eloss= " << preStepKinEnergy-eloss
845 << " step(mm)= " << length/mm
846 << " range(mm)= " << fRange/mm
847 << " fluct= " << lossFluctuationFlag
848 << G4endl;
849 }
850 */
851
852 G4double cut = (*theCuts)[currentMaterialIndex];
853 G4double esec = 0.0;
854
855 // SubCutOff
856 if(useSubCutoff) {
857 if(idxSCoffRegions[currentMaterialIndex]) {
858
859 G4bool yes = false;
860 G4StepPoint* prePoint = step.GetPreStepPoint();
861
862 // Check boundary
863 if(prePoint->GetStepStatus() == fGeomBoundary) yes = true;
864
865 // Check PrePoint
866 else {
867 G4double preSafety = prePoint->GetSafety();
868 G4double rcut = currentCouple->GetProductionCuts()->GetProductionCut(1);
869
870 // recompute presafety
871 if(preSafety < rcut) {
872 preSafety = safetyHelper->ComputeSafety(prePoint->GetPosition());
873 }
874
875 if(preSafety < rcut) yes = true;
876
877 // Check PostPoint
878 else {
879 G4double postSafety = preSafety - length;
880 if(postSafety < rcut) {
881 postSafety =
882 safetyHelper->ComputeSafety(step.GetPostStepPoint()->GetPosition());
883 if(postSafety < rcut) yes = true;
884 }
885 }
886 }
887
888 // Decide to start subcut sampling
889 if(yes) {
890
891 cut = (*theSubCuts)[currentMaterialIndex];
892 eloss -= GetSubDEDXForScaledEnergy(preStepScaledEnergy)*length;
893 scTracks.clear();
894 SampleSubCutSecondaries(scTracks, step,
895 currentModel,currentMaterialIndex,
896 esecdep);
897 // add bremsstrahlung sampling
898 /*
899 if(nProcesses > 0) {
900 for(G4int i=0; i<nProcesses; i++) {
901 (scProcesses[i])->SampleSubCutSecondaries(
902 scTracks, step, (scProcesses[i])->
903 SelectModelForMaterial(preStepKinEnergy, currentMaterialIndex),
904 currentMaterialIndex,esecdep);
905 }
906 }
907 */
908 G4int n = scTracks.size();
909 if(n>0) {
910 G4ThreeVector mom = dynParticle->GetMomentum();
911 fParticleChange.SetNumberOfSecondaries(n);
912 for(G4int i=0; i<n; i++) {
913 G4Track* t = scTracks[i];
914 G4double e = t->GetKineticEnergy();
915 if (t->GetDefinition() == thePositron) e += 2.0*electron_mass_c2;
916 esec += e;
917 pParticleChange->AddSecondary(t);
918 }
919 }
920 }
921 }
922 }
923
924 // Corrections, which cannot be tabulated
925 currentModel->CorrectionsAlongStep(currentCouple, dynParticle,
926 eloss, esecdep, length);
927
928 // Sample fluctuations
929 if (lossFluctuationFlag) {
930 G4VEmFluctuationModel* fluc = currentModel->GetModelOfFluctuations();
931 if(fluc &&
932 (eloss + esec + esecdep + lowestKinEnergy) < preStepKinEnergy) {
933
934 G4double tmax =
935 std::min(currentModel->MaxSecondaryKinEnergy(dynParticle),cut);
936 eloss = fluc->SampleFluctuations(currentMaterial,dynParticle,
937 tmax,length,eloss);
938 /*
939 if(-1 < verboseLevel)
940 G4cout << "After fluct: eloss(MeV)= " << eloss/MeV
941 << " fluc= " << (eloss-eloss0)/MeV
942 << " ChargeSqRatio= " << chargeSqRatio
943 << " massRatio= " << massRatio
944 << " tmax= " << tmax
945 << G4endl;
946 */
947 }
948 }
949 // add low-energy subcutoff particles
950 eloss += esecdep;
951 if(eloss < 0.0) eloss = 0.0;
952
953 // Energy balanse
954 G4double finalT = preStepKinEnergy - eloss - esec;
955 if (finalT <= lowestKinEnergy) {
956 eloss = preStepKinEnergy - esec;
957 finalT = 0.0;
958 } else if(isIon) {
959 fParticleChange.SetProposedCharge(
960 currentModel->GetParticleCharge(track.GetDefinition(),currentMaterial,finalT));
961 }
962
963 fParticleChange.SetProposedKineticEnergy(finalT);
964 fParticleChange.ProposeLocalEnergyDeposit(eloss);
965
966 /*
967 if(-1 < verboseLevel) {
968 G4cout << "Final value eloss(MeV)= " << eloss/MeV
969 << " preStepKinEnergy= " << preStepKinEnergy
970 << " postStepKinEnergy= " << finalT
971 << " lossFlag= " << lossFluctuationFlag
972 << " status= " << track.GetTrackStatus()
973 << G4endl;
974 }
975 */
976
977 return &fParticleChange;
978}
979
980//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
981
982void G4VEnergyLossProcess::SampleSubCutSecondaries(
983 std::vector<G4Track*>& tracks,
984 const G4Step& step,
985 G4VEmModel* model,
986 G4int idx,
987 G4double& /*extraEdep*/)
988{
989 // Fast check weather subcutoff can work
990 G4double subcut = (*theSubCuts)[idx];
991 G4double cut = (*theCuts)[idx];
992 if(cut <= subcut) return;
993
994 const G4Track* track = step.GetTrack();
995 const G4DynamicParticle* dp = track->GetDynamicParticle();
996 G4double e = dp->GetKineticEnergy()*massRatio;
997 G4bool b;
998 G4double cross = chargeSqRatio*(((*theSubLambdaTable)[idx])->GetValue(e,b));
999 G4double length = step.GetStepLength();
1000
1001 // negligible probability to get any interaction
1002 if(length*cross < perMillion) return;
1003 /*
1004 if(-1 < verboseLevel)
1005 G4cout << "<<< Subcutoff for " << GetProcessName()
1006 << " cross(1/mm)= " << cross*mm << ">>>"
1007 << " e(MeV)= " << preStepScaledEnergy
1008 << " matIdx= " << currentMaterialIndex
1009 << G4endl;
1010 */
1011
1012 // Sample subcutoff secondaries
1013 G4StepPoint* preStepPoint = step.GetPreStepPoint();
1014 G4StepPoint* postStepPoint = step.GetPostStepPoint();
1015 G4ThreeVector prepoint = preStepPoint->GetPosition();
1016 G4ThreeVector dr = postStepPoint->GetPosition() - prepoint;
1017 G4double pretime = preStepPoint->GetGlobalTime();
1018 G4double dt = postStepPoint->GetGlobalTime() - pretime;
1019 //G4double dt = length/preStepPoint->GetVelocity();
1020 G4double fragment = 0.0;
1021
1022 do {
1023 G4double del = -std::log(G4UniformRand())/cross;
1024 fragment += del/length;
1025 if (fragment > 1.0) break;
1026
1027 // sample secondaries
1028 secParticles.clear();
1029 model->SampleSecondaries(&secParticles,track->GetMaterialCutsCouple(),
1030 dp,subcut,cut);
1031
1032 // position of subcutoff particles
1033 G4ThreeVector r = prepoint + fragment*dr;
1034 std::vector<G4DynamicParticle*>::iterator it;
1035 for(it=secParticles.begin(); it!=secParticles.end(); it++) {
1036
1037 G4bool addSec = true;
1038 /*
1039 // do not track very low-energy delta-electrons
1040 if(theSecondaryRangeTable && (*it)->GetDefinition() == theElectron) {
1041 G4bool b;
1042 G4double ekin = (*it)->GetKineticEnergy();
1043 G4double rg = ((*theSecondaryRangeTable)[idx]->GetValue(ekin, b));
1044 // if(rg < currentMinSafety) {
1045 if(rg < safetyHelper->ComputeSafety(r)) {
1046 extraEdep += ekin;
1047 delete (*it);
1048 addSec = false;
1049 }
1050 }
1051 */
1052 if(addSec) {
1053 G4Track* t = new G4Track((*it), pretime + fragment*dt, r);
1054 //G4Track* t = new G4Track((*it), pretime, r);
1055 t->SetTouchableHandle(track->GetTouchableHandle());
1056 tracks.push_back(t);
1057
1058 /*
1059 if(-1 < verboseLevel)
1060 G4cout << "New track " << t->GetDefinition()->GetParticleName()
1061 << " e(keV)= " << t->GetKineticEnergy()/keV
1062 << " fragment= " << fragment
1063 << G4endl;
1064 */
1065 }
1066 }
1067 } while (fragment <= 1.0);
1068}
1069
1070//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1071
1072G4VParticleChange* G4VEnergyLossProcess::PostStepDoIt(const G4Track& track,
1073 const G4Step&)
1074{
1075 fParticleChange.InitializeForPostStep(track);
1076 G4double finalT = track.GetKineticEnergy();
1077 if(finalT <= lowestKinEnergy) return &fParticleChange;
1078
1079 G4double postStepScaledEnergy = finalT*massRatio;
1080 /*
1081 if(-1 < verboseLevel) {
1082 G4cout << GetProcessName()
1083 << "::PostStepDoIt: E(MeV)= " << finalT/MeV
1084 << G4endl;
1085 }
1086 */
1087 // Integral approach
1088 if (integral) {
1089 G4double lx = GetLambdaForScaledEnergy(postStepScaledEnergy);
1090 /*
1091 if(preStepLambda<lx && 1 < verboseLevel && nWarnings<200) {
1092 G4cout << "WARNING: for " << particle->GetParticleName()
1093 << " and " << GetProcessName()
1094 << " E(MeV)= " << finalT/MeV
1095 << " preLambda= " << preStepLambda
1096 << " < " << lx << " (postLambda) "
1097 << G4endl;
1098 nWarnings++;
1099 }
1100 */
1101 if(preStepLambda*G4UniformRand() > lx) {
1102 ClearNumberOfInteractionLengthLeft();
1103 return &fParticleChange;
1104 }
1105 }
1106
1107 SelectModel(postStepScaledEnergy);
1108 const G4DynamicParticle* dynParticle = track.GetDynamicParticle();
1109 G4double tcut = (*theCuts)[currentMaterialIndex];
1110
1111 // sample secondaries
1112 secParticles.clear();
1113 currentModel->SampleSecondaries(&secParticles, currentCouple, dynParticle, tcut);
1114
1115 // save secondaries
1116 G4int num = secParticles.size();
1117 if(num > 0) {
1118 fParticleChange.SetNumberOfSecondaries(num);
1119 for (G4int i=0; i<num; i++) {
1120 fParticleChange.AddSecondary(secParticles[i]);
1121 }
1122 }
1123
1124 /*
1125 if(-1 < verboseLevel) {
1126 G4cout << "::PostStepDoIt: Sample secondary; Efin= "
1127 << fParticleChange.GetProposedKineticEnergy()/MeV
1128 << " MeV; model= (" << currentModel->LowEnergyLimit()
1129 << ", " << currentModel->HighEnergyLimit() << ")"
1130 << " preStepLambda= " << preStepLambda
1131 << " dir= " << track.GetMomentumDirection()
1132 << " status= " << track.GetTrackStatus()
1133 << G4endl;
1134 }
1135 */
1136 ClearNumberOfInteractionLengthLeft();
1137 return &fParticleChange;
1138}
1139
1140//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1141
1142void G4VEnergyLossProcess::PrintInfoDefinition()
1143{
1144 if(0 < verboseLevel) {
1145 G4cout << G4endl << GetProcessName() << ": for "
1146 << particle->GetParticleName()
1147 << " SubType= " << GetProcessSubType()
1148 << G4endl
1149 << " dE/dx and range tables from "
1150 << G4BestUnit(minKinEnergy,"Energy")
1151 << " to " << G4BestUnit(maxKinEnergy,"Energy")
1152 << " in " << nBins << " bins" << G4endl
1153 << " Lambda tables from threshold to "
1154 << G4BestUnit(maxKinEnergy,"Energy")
1155 << " in " << nBins << " bins, spline: "
1156 << (G4LossTableManager::Instance())->SplineFlag()
1157 << G4endl;
1158 if(theRangeTableForLoss && isIonisation) {
1159 G4cout << " finalRange(mm)= " << finalRange/mm
1160 << ", dRoverRange= " << dRoverRange
1161 << ", integral: " << integral
1162 << ", fluct: " << lossFluctuationFlag
1163 << ", linLossLimit= " << linLossLimit
1164 << G4endl;
1165 }
1166 PrintInfo();
1167 modelManager->DumpModelList(verboseLevel);
1168 if(theCSDARangeTable && isIonisation) {
1169 G4cout << " CSDA range table up"
1170 << " to " << G4BestUnit(maxKinEnergyCSDA,"Energy")
1171 << " in " << nBinsCSDA << " bins" << G4endl;
1172 }
1173 if(nSCoffRegions>0 && isIonisation) {
1174 G4cout << " Subcutoff sampling in " << nSCoffRegions
1175 << " regions" << G4endl;
1176 }
1177 if(2 < verboseLevel) {
1178 G4cout << " DEDXTable address= " << theDEDXTable << G4endl;
1179 if(theDEDXTable && isIonisation) G4cout << (*theDEDXTable) << G4endl;
1180 G4cout << "non restricted DEDXTable address= "
1181 << theDEDXunRestrictedTable << G4endl;
1182 if(theDEDXunRestrictedTable && isIonisation) {
1183 G4cout << (*theDEDXunRestrictedTable) << G4endl;
1184 }
1185 if(theDEDXSubTable && isIonisation) {
1186 G4cout << (*theDEDXSubTable) << G4endl;
1187 }
1188 G4cout << " CSDARangeTable address= " << theCSDARangeTable
1189 << G4endl;
1190 if(theCSDARangeTable && isIonisation) {
1191 G4cout << (*theCSDARangeTable) << G4endl;
1192 }
1193 G4cout << " RangeTableForLoss address= " << theRangeTableForLoss
1194 << G4endl;
1195 if(theRangeTableForLoss && isIonisation) {
1196 G4cout << (*theRangeTableForLoss) << G4endl;
1197 }
1198 G4cout << " InverseRangeTable address= " << theInverseRangeTable
1199 << G4endl;
1200 if(theInverseRangeTable && isIonisation) {
1201 G4cout << (*theInverseRangeTable) << G4endl;
1202 }
1203 G4cout << " LambdaTable address= " << theLambdaTable << G4endl;
1204 if(theLambdaTable && isIonisation) {
1205 G4cout << (*theLambdaTable) << G4endl;
1206 }
1207 G4cout << " SubLambdaTable address= " << theSubLambdaTable << G4endl;
1208 if(theSubLambdaTable && isIonisation) {
1209 G4cout << (*theSubLambdaTable) << G4endl;
1210 }
1211 }
1212 }
1213}
1214
1215//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1216
1217void G4VEnergyLossProcess::SetDEDXTable(G4PhysicsTable* p, G4EmTableType tType)
1218{
1219 if(fTotal == tType && theDEDXunRestrictedTable != p) {
1220 if(theDEDXunRestrictedTable) theDEDXunRestrictedTable->clearAndDestroy();
1221 theDEDXunRestrictedTable = p;
1222 if(p) {
1223 size_t n = p->length();
1224 G4PhysicsVector* pv = (*p)[0];
1225 G4double emax = maxKinEnergyCSDA;
1226 G4bool b;
1227 theDEDXAtMaxEnergy = new G4double [n];
1228
1229 for (size_t i=0; i<n; i++) {
1230 pv = (*p)[i];
1231 G4double dedx = pv->GetValue(emax, b);
1232 theDEDXAtMaxEnergy[i] = dedx;
1233 //G4cout << "i= " << i << " emax(MeV)= " << emax/MeV<< " dedx= "
1234 //<< dedx << G4endl;
1235 }
1236 }
1237
1238 } else if(fRestricted == tType) {
1239 theDEDXTable = p;
1240 } else if(fSubRestricted == tType) {
1241 theDEDXSubTable = p;
1242 } else if(fIsIonisation == tType && theIonisationTable != p) {
1243 if(theIonisationTable) theIonisationTable->clearAndDestroy();
1244 theIonisationTable = p;
1245 } else if(fIsSubIonisation == tType && theIonisationSubTable != p) {
1246 if(theIonisationSubTable) theIonisationSubTable->clearAndDestroy();
1247 theIonisationSubTable = p;
1248 }
1249}
1250
1251//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1252
1253void G4VEnergyLossProcess::SetCSDARangeTable(G4PhysicsTable* p)
1254{
1255 if(theCSDARangeTable != p) theCSDARangeTable = p;
1256
1257 if(p) {
1258 size_t n = p->length();
1259 G4PhysicsVector* pv = (*p)[0];
1260 G4double emax = maxKinEnergyCSDA;
1261 G4bool b;
1262 theRangeAtMaxEnergy = new G4double [n];
1263
1264 for (size_t i=0; i<n; i++) {
1265 pv = (*p)[i];
1266 G4double r2 = pv->GetValue(emax, b);
1267 theRangeAtMaxEnergy[i] = r2;
1268 //G4cout << "i= " << i << " e2(MeV)= " << emax/MeV << " r2= "
1269 //<< r2<< G4endl;
1270 }
1271 }
1272}
1273
1274//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1275
1276void G4VEnergyLossProcess::SetRangeTableForLoss(G4PhysicsTable* p)
1277{
1278 if(theRangeTableForLoss != p) {
1279 theRangeTableForLoss = p;
1280 if(1 < verboseLevel) {
1281 G4cout << "### Set Range table " << p
1282 << " for " << particle->GetParticleName()
1283 << " and process " << GetProcessName() << G4endl;
1284 }
1285 }
1286}
1287
1288//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1289
1290void G4VEnergyLossProcess::SetSecondaryRangeTable(G4PhysicsTable* p)
1291{
1292 if(theSecondaryRangeTable != p) {
1293 theSecondaryRangeTable = p;
1294 if(1 < verboseLevel) {
1295 G4cout << "### Set SecondaryRange table " << p
1296 << " for " << particle->GetParticleName()
1297 << " and process " << GetProcessName() << G4endl;
1298 }
1299 }
1300}
1301
1302//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1303
1304void G4VEnergyLossProcess::SetInverseRangeTable(G4PhysicsTable* p)
1305{
1306 if(theInverseRangeTable != p) {
1307 theInverseRangeTable = p;
1308 if(1 < verboseLevel) {
1309 G4cout << "### Set InverseRange table " << p
1310 << " for " << particle->GetParticleName()
1311 << " and process " << GetProcessName() << G4endl;
1312 }
1313 }
1314}
1315
1316//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1317
1318void G4VEnergyLossProcess::SetLambdaTable(G4PhysicsTable* p)
1319{
1320 if(1 < verboseLevel) {
1321 G4cout << "### Set Lambda table " << p
1322 << " for " << particle->GetParticleName()
1323 << " and process " << GetProcessName() << G4endl;
1324 }
1325 if(theLambdaTable != p) theLambdaTable = p;
1326 tablesAreBuilt = true;
1327
1328 if(p) {
1329 size_t n = p->length();
1330 G4PhysicsVector* pv = (*p)[0];
1331 G4double e, s, smax, emax;
1332 theEnergyOfCrossSectionMax = new G4double [n];
1333 theCrossSectionMax = new G4double [n];
1334 G4bool b;
1335
1336 for (size_t i=0; i<n; i++) {
1337 pv = (*p)[i];
1338 emax = DBL_MAX;
1339 smax = 0.0;
1340 if(pv) {
1341 size_t nb = pv->GetVectorLength();
1342 emax = pv->GetLowEdgeEnergy(nb);
1343 for (size_t j=0; j<nb; j++) {
1344 e = pv->GetLowEdgeEnergy(j);
1345 s = pv->GetValue(e,b);
1346 if(s > smax) {
1347 smax = s;
1348 emax = e;
1349 }
1350 }
1351 }
1352 theEnergyOfCrossSectionMax[i] = emax;
1353 theCrossSectionMax[i] = smax;
1354 if(1 < verboseLevel) {
1355 G4cout << "For " << particle->GetParticleName()
1356 << " Max CS at i= " << i << " emax(MeV)= " << emax/MeV
1357 << " lambda= " << smax << G4endl;
1358 }
1359 }
1360 }
1361}
1362
1363//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1364
1365void G4VEnergyLossProcess::SetSubLambdaTable(G4PhysicsTable* p)
1366{
1367 if(theSubLambdaTable != p) {
1368 theSubLambdaTable = p;
1369 if(1 < verboseLevel) {
1370 G4cout << "### Set SebLambda table " << p
1371 << " for " << particle->GetParticleName()
1372 << " and process " << GetProcessName() << G4endl;
1373 }
1374 }
1375}
1376
1377//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1378
1379G4PhysicsVector* G4VEnergyLossProcess::LambdaPhysicsVector(
1380 const G4MaterialCutsCouple* couple, G4double cut)
1381{
1382 // G4double cut = (*theCuts)[couple->GetIndex()];
1383 // G4int nbins = nLambdaBins;
1384 G4double tmin =
1385 std::max(MinPrimaryEnergy(particle, couple->GetMaterial(), cut),
1386 minKinEnergy);
1387 if(tmin >= maxKinEnergy) tmin = 0.5*maxKinEnergy;
1388 G4PhysicsVector* v = new G4PhysicsLogVector(tmin, maxKinEnergy, nBins);
1389 v->SetSpline((G4LossTableManager::Instance())->SplineFlag());
1390
1391 return v;
1392}
1393
1394//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1395
1396G4double G4VEnergyLossProcess::CrossSectionPerVolume(
1397 G4double kineticEnergy, const G4MaterialCutsCouple* couple)
1398{
1399 // Cross section per volume is calculated
1400 DefineMaterial(couple);
1401 G4double cross = 0.0;
1402 G4bool b;
1403 if(theLambdaTable) {
1404 cross =
1405 ((*theLambdaTable)[currentMaterialIndex])->GetValue(kineticEnergy, b);
1406 } else {
1407 SelectModel(kineticEnergy);
1408 cross =
1409 currentModel->CrossSectionPerVolume(currentMaterial,
1410 particle, kineticEnergy,
1411 (*theCuts)[currentMaterialIndex]);
1412 }
1413
1414 return cross;
1415}
1416
1417//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1418
1419G4bool G4VEnergyLossProcess::StorePhysicsTable(
1420 const G4ParticleDefinition* part, const G4String& directory,
1421 G4bool ascii)
1422{
1423 G4bool res = true;
1424 if ( baseParticle || part != particle ) return res;
1425
1426 if(!StoreTable(part,theDEDXTable,ascii,directory,"DEDX"))
1427 {res = false;}
1428
1429 if(!StoreTable(part,theDEDXunRestrictedTable,ascii,directory,"DEDXnr"))
1430 {res = false;}
1431
1432 if(!StoreTable(part,theDEDXSubTable,ascii,directory,"SubDEDX"))
1433 {res = false;}
1434
1435 if(!StoreTable(part,theIonisationTable,ascii,directory,"Ionisation"))
1436 {res = false;}
1437
1438 if(!StoreTable(part,theIonisationSubTable,ascii,directory,"SubIonisation"))
1439 {res = false;}
1440
1441 if(isIonisation &&
1442 !StoreTable(part,theCSDARangeTable,ascii,directory,"CSDARange"))
1443 {res = false;}
1444
1445 if(isIonisation &&
1446 !StoreTable(part,theRangeTableForLoss,ascii,directory,"Range"))
1447 {res = false;}
1448
1449 if(isIonisation &&
1450 !StoreTable(part,theInverseRangeTable,ascii,directory,"InverseRange"))
1451 {res = false;}
1452
1453 if(!StoreTable(part,theLambdaTable,ascii,directory,"Lambda"))
1454 {res = false;}
1455
1456 if(!StoreTable(part,theSubLambdaTable,ascii,directory,"SubLambda"))
1457 {res = false;}
1458
1459 if ( res ) {
1460 if(0 < verboseLevel) {
1461 G4cout << "Physics tables are stored for " << particle->GetParticleName()
1462 << " and process " << GetProcessName()
1463 << " in the directory <" << directory
1464 << "> " << G4endl;
1465 }
1466 } else {
1467 G4cout << "Fail to store Physics Tables for "
1468 << particle->GetParticleName()
1469 << " and process " << GetProcessName()
1470 << " in the directory <" << directory
1471 << "> " << G4endl;
1472 }
1473 return res;
1474}
1475
1476//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
1477
1478G4bool G4VEnergyLossProcess::StoreTable(const G4ParticleDefinition* part,
1479 G4PhysicsTable* aTable, G4bool ascii,
1480 const G4String& directory,
1481 const G4String& tname)
1482{
1483 G4bool res = true;
1484 if ( aTable ) {
1485 const G4String name = GetPhysicsTableFileName(part,directory,tname,ascii);
1486 if( !aTable->StorePhysicsTable(name,ascii)) res = false;
1487 }
1488 return res;
1489}
1490
1491//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
1492
1493G4bool G4VEnergyLossProcess::RetrievePhysicsTable(
1494 const G4ParticleDefinition* part, const G4String& directory,
1495 G4bool ascii)
1496{
1497 G4bool res = true;
1498 const G4String particleName = part->GetParticleName();
1499
1500 if(1 < verboseLevel) {
1501 G4cout << "G4VEnergyLossProcess::RetrievePhysicsTable() for "
1502 << particleName << " and process " << GetProcessName()
1503 << "; tables_are_built= " << tablesAreBuilt
1504 << G4endl;
1505 }
1506 if(particle == part) {
1507
1508 // G4bool yes = true;
1509 if ( !baseParticle ) {
1510
1511 G4bool fpi = true;
1512 if(!RetrieveTable(part,theDEDXTable,ascii,directory,"DEDX",fpi))
1513 {fpi = false;}
1514
1515 if(!RetrieveTable(part,theIonisationTable,ascii,directory,"Ionisation",false))
1516 {fpi = false;}
1517
1518 if(!RetrieveTable(part,theRangeTableForLoss,ascii,directory,"Range",fpi))
1519 {res = false;}
1520
1521 if(!RetrieveTable(part,theDEDXunRestrictedTable,ascii,directory,"DEDXnr",false))
1522 {res = false;}
1523
1524 if(!RetrieveTable(part,theCSDARangeTable,ascii,directory,"CSDARange",false))
1525 {res = false;}
1526
1527 if(!RetrieveTable(part,theInverseRangeTable,ascii,directory,"InverseRange",fpi))
1528 {res = false;}
1529
1530 if(!RetrieveTable(part,theLambdaTable,ascii,directory,"Lambda",true))
1531 {res = false;}
1532
1533 G4bool yes = false;
1534 if(nSCoffRegions > 0) {yes = true;}
1535
1536 if(!RetrieveTable(part,theDEDXSubTable,ascii,directory,"SubDEDX",yes))
1537 {res = false;}
1538
1539 if(!RetrieveTable(part,theSubLambdaTable,ascii,directory,"SubLambda",yes))
1540 {res = false;}
1541
1542 if(!fpi) yes = false;
1543 if(!RetrieveTable(part,theIonisationSubTable,ascii,directory,"SubIonisation",yes))
1544 {res = false;}
1545 }
1546 }
1547
1548 return res;
1549}
1550
1551//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
1552
1553G4bool G4VEnergyLossProcess::RetrieveTable(const G4ParticleDefinition* part,
1554 G4PhysicsTable* aTable, G4bool ascii,
1555 const G4String& directory,
1556 const G4String& tname,
1557 G4bool mandatory)
1558{
1559 G4bool res = true;
1560 G4String filename = GetPhysicsTableFileName(part,directory,tname,ascii);
1561 G4bool yes = aTable->ExistPhysicsTable(filename);
1562 if(yes) {
1563 yes = G4PhysicsTableHelper::RetrievePhysicsTable(aTable,filename,ascii);
1564 if((G4LossTableManager::Instance())->SplineFlag()) {
1565 size_t n = aTable->length();
1566 for(size_t i=0; i<n; i++) {(*aTable)[i]->SetSpline(true);}
1567 }
1568 }
1569 if(yes) {
1570 if (0 < verboseLevel) {
1571 G4cout << tname << " table for " << part->GetParticleName()
1572 << " is Retrieved from <" << filename << ">"
1573 << G4endl;
1574 }
1575 } else {
1576 if(mandatory) res = false;
1577 if(mandatory || 1 < verboseLevel) {
1578 G4cout << tname << " table for " << part->GetParticleName()
1579 << " from file <"
1580 << filename << "> is not Retrieved"
1581 << G4endl;
1582 }
1583 }
1584 return res;
1585}
1586
1587//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1588
1589void G4VEnergyLossProcess::AddCollaborativeProcess(
1590 G4VEnergyLossProcess* p)
1591{
1592 G4bool add = true;
1593 if(p->GetProcessName() != "eBrem") add = false;
1594 if(add && nProcesses > 0) {
1595 for(G4int i=0; i<nProcesses; i++) {
1596 if(p == scProcesses[i]) {
1597 add = false;
1598 break;
1599 }
1600 }
1601 }
1602 if(add) {
1603 scProcesses.push_back(p);
1604 nProcesses++;
1605 if (1 < verboseLevel) {
1606 G4cout << "### The process " << p->GetProcessName()
1607 << " is added to the list of collaborative processes of "
1608 << GetProcessName() << G4endl;
1609 }
1610 }
1611}
1612
1613//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1614
1615G4double G4VEnergyLossProcess::GetDEDXDispersion(
1616 const G4MaterialCutsCouple *couple,
1617 const G4DynamicParticle* dp,
1618 G4double length)
1619{
1620 DefineMaterial(couple);
1621 G4double ekin = dp->GetKineticEnergy();
1622 SelectModel(ekin*massRatio);
1623 G4double tmax = currentModel->MaxSecondaryKinEnergy(dp);
1624 tmax = std::min(tmax,(*theCuts)[currentMaterialIndex]);
1625 G4double d = 0.0;
1626 G4VEmFluctuationModel* fm = currentModel->GetModelOfFluctuations();
1627 if(fm) d = fm->Dispersion(currentMaterial,dp,tmax,length);
1628 return d;
1629}
1630
1631//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1632
1633void G4VEnergyLossProcess::ActivateDeexcitation(G4bool, const G4Region*)
1634{}
1635
1636//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1637
Note: See TracBrowser for help on using the repository browser.