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

Last change on this file since 1340 was 1340, checked in by garnier, 14 years ago

update ti head

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