source: trunk/source/processes/electromagnetic/lowenergy/src/G4hLowEnergyIonisation.cc @ 1315

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

update geant4-09-04-beta-cand-01 interfaces-V09-03-09 vis-V09-03-08

File size: 66.6 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//
27// -------------------------------------------------------------
28//      GEANT 4 class implementation file
29//
30//      History: based on object model of
31//      2nd December 1995, G.Cosmo
32//      ---------- G4hLowEnergyIonisation physics process -------
33//                by Vladimir Ivanchenko, 14 July 1999
34//                was made on the base of G4hIonisation class
35//                developed by Laszlo Urban
36// ************************************************************
37// It is the extention of the ionisation process for the slow
38// charged hadrons.
39// ************************************************************
40// 28 July   1999 V.Ivanchenko cleen up
41// 17 August 1999 G.Mancinelli added ICRU parametrisations for protons
42// 20 August 1999 G.Mancinelli added ICRU tables for alpha
43// 31 August 1999 V.Ivanchenko update and cleen up
44// 30 Sept.  1999 V.Ivanchenko minor upgrade
45// 12 Dec.   1999 S. Chauvie added Barkas correction
46// 19 Jan.   2000 V.Ivanchenko minor changing in Barkas corrections
47// 02 April  2000 S. Chauvie linearization of Barkas effect
48// 03 April  2000 V.Ivanchenko Nuclear Stopping power for antiprotons
49// 23 May    2000 MG Pia  Clean up for QAO model
50// 24 May    2000 MG Pia  Code properly indented to improve legibility
51// 17 July   2000 V.Ivanchenko Bug in scaling AlongStepDoIt method
52// 25 July   2000 V.Ivanchenko New design iteration
53// 17 August 2000 V.Ivanchenko Add ion fluctuation models
54// 18 August 2000 V.Ivanchenko Bug fixed in GetConstrain
55// 22 August 2000 V.Ivanchenko Insert paramStepLimit and
56//                reorganise access to Barkas and Bloch terms 
57// 04 Sept.  2000 V.Ivanchenko rename fluctuations
58// 05 Sept.  2000 V.Ivanchenko clean up
59// 03 Oct.   2000 V.Ivanchenko CodeWizard clean up
60// 03 Nov.   2000 V.Ivanchenko MinKineticEnergy=LowestKineticEnergy=10eV
61// 05 Nov.   2000 MG Pia - Removed const cast previously introduced to get
62//                the code compiled (const G4Material* now introduced in
63//                electromagnetic/utils utils-V02-00-03 tag)
64//                (this is going back and forth, to cope with Michel's
65//                utils tag not being accepted yet by system testing)
66// 21 Nov.  2000 V.Ivanchenko Fix a problem in fluctuations
67// 23 Nov.  2000 V.Ivanchenko Ion type fluctuations only for charge>0
68// 10 May   2001 V.Ivanchenko Clean up againist Linux compilation with -Wall
69// 23 May   2001 V.Ivanchenko Minor fix in PostStepDoIt
70// 07 June  2001 V.Ivanchenko Clean up AntiProtonDEDX + add print out
71// 18 June  2001 V.Ivanchenko Cleanup print out
72// 18 Oct.  2001 V.Ivanchenko Add fluorescence
73// 30 Oct.  2001 V.Ivanchenko Add minGammaEnergy and minElectronEnergy
74// 07 Dec   2001 V.Ivanchenko Add SetFluorescence method
75// 15 Feb   2002 V.Ivanchenko Fix problem of Generic Ions
76// 25 Mar   2002 V.Ivanchenko Fix problem of fluorescence below threshold
77// 28 Mar   2002 V.Ivanchenko Set fluorescence off by default
78// 09 Apr   2002 V.Ivanchenko Fix table problem of GenericIons
79// 28 May   2002 V.Ivanchenko Remove flag fStopAndKill
80// 31 May   2002 V.Ivanchenko Add path of Fluo + Auger cuts to
81//                            AtomicDeexcitation
82// 03 Jun   2002 MGP          Restore fStopAndKill
83// 10 Jun   2002 V.Ivanchenko Restore fStopButAlive
84// 12 Jun   2002 V.Ivanchenko Fix in fluctuations - if tmax<2*Ipot Gaussian
85//                            fluctuations enables
86// 20 Sept  2002 V.Ivanchenko Clean up energy ranges for models
87// 07 Oct   2002 V.Ivanchenko Clean up initialisation of fluorescence
88// 28 Oct   2002 V.Ivanchenko Optimal binning for dE/dx
89// 10 Dec   2002 V.Ivanchenko antiProtonLowEnergy -> 25 keV, QEG model below
90// 21 Jan   2003 V.Ivanchenko Cut per region
91// 10 Mar   2003 V.Ivanchenko Use SubTypes for ions
92// 12 Apr   2003 V.Ivanchenko Cut per region for fluo AlongStep
93// 18 Apr   2003 V.Ivanchenko finalRange redefinition
94// 26 Apr   2003 V.Ivanchenko fix for stepLimit
95// 30 Mar   2004 S.Saliceti add shellCS data member and expFlag variable,
96//                          atom total cross section for the Empiric Model
97// 28 May   2004 V.Ivanchenko fix for ionisation of antiprotons in complex materials
98// 30 Aug   2004 V.Ivanchenko use energy limit for parameterisation from model
99// 03 Oct   2005 V.Ivanchenko change logic of definition of high energy limit for
100//               parametrised proton model: min(user value, model limit)
101// 26 Jan   2005 S. Chauvie added PrintInfoDefinition() for antiproton
102// 30 Sep   2009 A.Mantero Removed dependencies to old shell Ionisation XS models
103// 07 Jun    2010 Code Celaning for June beta Release
104// -----------------------------------------------------------------------
105
106//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
107//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
108
109#include "G4hLowEnergyIonisation.hh"
110#include "globals.hh"
111#include "G4ios.hh"
112#include "Randomize.hh"
113#include "G4Poisson.hh"
114#include "G4UnitsTable.hh"
115#include "G4EnergyLossTables.hh"
116#include "G4Material.hh"
117#include "G4DynamicParticle.hh"
118#include "G4ParticleDefinition.hh"
119#include "G4AtomicDeexcitation.hh"
120#include "G4AtomicTransitionManager.hh"
121#include "G4ShellVacancy.hh"
122#include "G4VhShellCrossSection.hh"
123#include "G4VEMDataSet.hh"
124#include "G4EMDataSet.hh"
125#include "G4CompositeEMDataSet.hh"
126#include "G4Gamma.hh"
127#include "G4LogLogInterpolation.hh"
128#include "G4SemiLogInterpolation.hh"
129#include "G4ProcessManager.hh"
130#include "G4ProductionCutsTable.hh"
131#include "G4teoCrossSection.hh"
132#include "G4empCrossSection.hh"
133//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
134
135G4hLowEnergyIonisation::G4hLowEnergyIonisation(const G4String& processName)
136  : G4hLowEnergyLoss(processName),
137    theBetheBlochModel(0),
138    theProtonModel(0),
139    theAntiProtonModel(0),
140    theIonEffChargeModel(0),
141    theNuclearStoppingModel(0),
142    theIonChuFluctuationModel(0),
143    theIonYangFluctuationModel(0),
144    theProtonTable("ICRU_R49p"),
145    theAntiProtonTable("ICRU_R49p"),
146    theNuclearTable("ICRU_R49"),
147    nStopping(true),
148    theBarkas(true),
149    theMeanFreePathTable(0),
150    paramStepLimit (0.005),
151    shellVacancy(0),
152    shellCS(0),
153    theFluo(false)
154{ 
155  InitializeMe();
156}
157
158//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
159
160void G4hLowEnergyIonisation::InitializeMe()
161{
162  LowestKineticEnergy  = 10.0*eV ;
163  HighestKineticEnergy = 100.0*GeV ;
164  MinKineticEnergy     = 10.0*eV ; 
165  TotBin               = 360 ;
166  protonLowEnergy      = 1.*keV ;
167  protonHighEnergy     = 100.*MeV ;
168  antiProtonLowEnergy  = 25.*keV ;
169  antiProtonHighEnergy = 2.*MeV ;
170  minGammaEnergy       = 25.*keV;
171  minElectronEnergy    = 25.*keV;
172  verboseLevel         = 0;
173
174  shellCS = new G4teoCrossSection("analytical");
175
176}
177
178//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
179
180G4hLowEnergyIonisation::~G4hLowEnergyIonisation()
181{
182  if (theMeanFreePathTable) {
183    theMeanFreePathTable->clearAndDestroy();
184    delete theMeanFreePathTable;
185  }
186  if(theBetheBlochModel)delete theBetheBlochModel;
187  if(theProtonModel)delete theProtonModel;
188  if(theAntiProtonModel)delete theAntiProtonModel;
189  if(theNuclearStoppingModel)delete theNuclearStoppingModel;
190  if(theIonEffChargeModel)delete theIonEffChargeModel;
191  if(theIonChuFluctuationModel)delete theIonChuFluctuationModel;
192  if(theIonYangFluctuationModel)delete theIonYangFluctuationModel;
193  if(shellVacancy) delete shellVacancy;
194  if(shellCS) delete shellCS;
195  cutForDelta.clear();
196  G4int length = zFluoDataVector.size();
197  if(length) {
198    for(G4int i=0; i<length; i++) {
199      delete zFluoDataVector[i];
200    }
201    zFluoDataVector.clear();
202  }
203}
204
205//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
206
207void G4hLowEnergyIonisation::SetElectronicStoppingPowerModel(
208                             const G4ParticleDefinition* aParticle,
209                             const G4String& dedxTable)
210  // This method defines the ionisation parametrisation method via its name
211{
212  if(0 < aParticle->GetPDGCharge()) {
213    SetProtonElectronicStoppingPowerModel(dedxTable) ;
214  } else {
215    SetAntiProtonElectronicStoppingPowerModel(dedxTable) ;
216  }
217}
218
219//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
220
221void G4hLowEnergyIonisation::InitializeParametrisation() 
222
223{
224  // Define models for parametrisation of electronic energy losses
225  theBetheBlochModel = new G4hBetheBlochModel("Bethe-Bloch") ;
226  theProtonModel = new G4hParametrisedLossModel(theProtonTable) ;
227  protonHighEnergy = std::min(protonHighEnergy,theProtonModel->HighEnergyLimit(0, 0));
228  theAntiProtonModel = new G4QAOLowEnergyLoss(theAntiProtonTable) ;
229  theNuclearStoppingModel = new G4hNuclearStoppingModel(theNuclearTable) ;
230  theIonEffChargeModel = new G4hIonEffChargeSquare("Ziegler1988") ;
231  theIonChuFluctuationModel = new G4IonChuFluctuationModel("Chu") ;
232  theIonYangFluctuationModel = new G4IonYangFluctuationModel("Yang") ;
233}
234
235//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
236
237void G4hLowEnergyIonisation::BuildPhysicsTable(
238                       const G4ParticleDefinition& aParticleType)
239
240  //  just call BuildLossTable+BuildLambdaTable
241{
242  if(verboseLevel > 0) {
243    G4cout << "G4hLowEnergyIonisation::BuildPhysicsTable for "
244           << aParticleType.GetParticleName()
245           << " mass(MeV)= " << aParticleType.GetPDGMass()/MeV
246           << " charge= " << aParticleType.GetPDGCharge()/eplus
247           << " type= " << aParticleType.GetParticleType()
248           << G4endl;
249
250    if(verboseLevel > 1) {
251      G4ProcessVector* pv = aParticleType.GetProcessManager()->GetProcessList();
252
253      G4cout << " 0: " << (*pv)[0]->GetProcessName() << " " << (*pv)[0]
254             << " 1: " << (*pv)[1]->GetProcessName() << " " << (*pv)[1]
255        //        << " 2: " << (*pv)[2]->GetProcessName() << " " << (*pv)[2]
256             << G4endl;
257      G4cout << "ionModel= " << theIonEffChargeModel
258             << " MFPtable= " << theMeanFreePathTable
259             << " iniMass= " << initialMass
260             << G4endl;
261    }
262  }
263
264  if(aParticleType.GetParticleType() == "nucleus" &&
265     aParticleType.GetParticleName() != "GenericIon" &&
266     aParticleType.GetParticleSubType() == "generic")
267  {
268
269     G4EnergyLossTables::Register(&aParticleType,
270              theDEDXpTable,
271              theRangepTable,
272              theInverseRangepTable,
273              theLabTimepTable,
274              theProperTimepTable,
275              LowestKineticEnergy, HighestKineticEnergy,
276              proton_mass_c2/aParticleType.GetPDGMass(),
277              TotBin);
278
279     return;
280  }
281
282  if( !CutsWhereModified() && theLossTable) return;
283
284  InitializeParametrisation() ;
285  G4Proton* theProton = G4Proton::Proton();
286  G4AntiProton* theAntiProton = G4AntiProton::AntiProton();
287
288  charge = aParticleType.GetPDGCharge()/eplus;
289  chargeSquare = charge*charge ;
290
291  const G4ProductionCutsTable* theCoupleTable=
292        G4ProductionCutsTable::GetProductionCutsTable();
293  size_t numOfCouples = theCoupleTable->GetTableSize();
294
295  cutForDelta.clear();
296  cutForGamma.clear();
297
298  for (size_t j=0; j<numOfCouples; j++) {
299
300    // get material parameters needed for the energy loss calculation
301    const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(j);
302    const G4Material* material= couple->GetMaterial();
303
304    // the cut cannot be below lowest limit
305    G4double tCut = (*(theCoupleTable->GetEnergyCutsVector(1)))[j];
306    if(tCut > HighestKineticEnergy) tCut = HighestKineticEnergy;
307
308    G4double excEnergy = material->GetIonisation()->GetMeanExcitationEnergy();
309
310    tCut = std::max(tCut,excEnergy);
311    cutForDelta.push_back(tCut);
312
313    // the cut cannot be below lowest limit
314    tCut = (*(theCoupleTable->GetEnergyCutsVector(0)))[j];
315    if(tCut > HighestKineticEnergy) tCut = HighestKineticEnergy;
316    tCut = std::max(tCut,minGammaEnergy);
317    cutForGamma.push_back(tCut);
318  }
319
320  if(verboseLevel > 0) {
321    G4cout << "Cuts are defined " << G4endl;
322  }
323
324  if(0.0 < charge)
325    {
326      {
327        BuildLossTable(*theProton) ;
328
329//      The following vector has a fixed dimension (see src/G4hLowEnergyLoss.cc for more details)       
330//      It happended in the past that caused memory corruption errors. The problem is still pending, even if temporary solved
331//        G4cout << "[NOTE]: __LINE__=" << __LINE__ << ", aParticleType=" << aParticleType.GetParticleName() << ", theProton=" << theProton << ", theLossTable=" << theLossTable << ", CounterOfpProcess=" << CounterOfpProcess << G4endl;
332       
333        RecorderOfpProcess[CounterOfpProcess] = theLossTable ;
334        CounterOfpProcess++;
335      }
336  } else {
337      {
338        BuildLossTable(*theAntiProton) ;
339       
340//      The following vector has a fixed dimension (see src/G4hLowEnergyLoss.cc for more details)       
341//      It happended in the past that caused memory corruption errors. The problem is still pending, even if temporary solved
342//        G4cout << "[NOTE]: __LINE__=" << __LINE__ << ", aParticleType=" << aParticleType.GetParticleName() << ", theAntiProton=" << theAntiProton << ", theLossTable=" << theLossTable << ", CounterOfpbarProcess=" << CounterOfpbarProcess << G4endl;
343       
344        RecorderOfpbarProcess[CounterOfpbarProcess] = theLossTable ;
345        CounterOfpbarProcess++;
346      }
347  }
348
349  if(verboseLevel > 0) {
350    G4cout << "G4hLowEnergyIonisation::BuildPhysicsTable: "
351           << "Loss table is built "
352//         << theLossTable
353           << G4endl;
354  }
355
356  BuildLambdaTable(aParticleType) ;
357  BuildDataForFluorescence(aParticleType);
358
359  if(verboseLevel > 1) {
360    G4cout << (*theMeanFreePathTable) << G4endl;
361  }
362
363  if(verboseLevel > 0) {
364    G4cout << "G4hLowEnergyIonisation::BuildPhysicsTable: "
365           << "DEDX table will be built "
366//         << theDEDXpTable << " " << theDEDXpbarTable
367//         << " " << theRangepTable << " " << theRangepbarTable
368           << G4endl;
369  }
370
371  BuildDEDXTable(aParticleType) ;
372
373  if(verboseLevel > 1) {
374    G4cout << (*theDEDXpTable) << G4endl;
375  }
376
377  if((&aParticleType == theProton) ||  (&aParticleType == theAntiProton)) PrintInfoDefinition() ;
378
379  if(verboseLevel > 0) {
380    G4cout << "G4hLowEnergyIonisation::BuildPhysicsTable: end for "
381           << aParticleType.GetParticleName() << G4endl;
382  }
383}
384
385//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
386
387void G4hLowEnergyIonisation::BuildLossTable(
388                             const G4ParticleDefinition& aParticleType)
389{
390
391  // Initialisation
392  G4double lowEdgeEnergy , ionloss, ionlossBB, paramB ;
393  G4double lowEnergy, highEnergy;
394  G4Proton* theProton = G4Proton::Proton();
395
396  if(aParticleType == *theProton) {
397    lowEnergy = protonLowEnergy ;
398    highEnergy = protonHighEnergy ;
399    charge = 1.0 ;
400  } else {
401    lowEnergy = antiProtonLowEnergy ;
402    highEnergy = antiProtonHighEnergy ;
403    charge = -1.0 ;
404  }
405  chargeSquare = 1.0 ;
406
407  const G4ProductionCutsTable* theCoupleTable=
408        G4ProductionCutsTable::GetProductionCutsTable();
409  size_t numOfCouples = theCoupleTable->GetTableSize();
410
411  if ( theLossTable) {
412    theLossTable->clearAndDestroy();
413    delete theLossTable;
414  }
415
416  theLossTable = new G4PhysicsTable(numOfCouples);
417
418  //  loop for materials
419  for (size_t j=0; j<numOfCouples; j++) {
420
421    // create physics vector and fill it
422    G4PhysicsLogVector* aVector = new G4PhysicsLogVector(LowestKineticEnergy,
423                                                         HighestKineticEnergy,
424                                                         TotBin);
425
426    // get material parameters needed for the energy loss calculation
427    const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(j);
428    const G4Material* material= couple->GetMaterial();
429
430    if ( charge > 0.0 ) {
431      ionloss = ProtonParametrisedDEDX(couple,highEnergy) ;
432    } else {
433      ionloss = AntiProtonParametrisedDEDX(couple,highEnergy) ;
434    }
435
436    ionlossBB = theBetheBlochModel->TheValue(&aParticleType,material,highEnergy) ;
437    ionlossBB -= DeltaRaysEnergy(couple,highEnergy,proton_mass_c2) ;
438
439
440    paramB =  ionloss/ionlossBB - 1.0 ;
441
442    // now comes the loop for the kinetic energy values
443    for (G4int i = 0 ; i < TotBin ; i++) {
444      lowEdgeEnergy = aVector->GetLowEdgeEnergy(i) ;
445
446      // low energy part for this material, parametrised energy loss formulae
447      if ( lowEdgeEnergy < highEnergy ) {
448
449        if ( charge > 0.0 ) {
450          ionloss = ProtonParametrisedDEDX(couple,lowEdgeEnergy) ;
451        } else {
452          ionloss = AntiProtonParametrisedDEDX(couple,lowEdgeEnergy) ;
453        }
454
455      } else {
456
457        // high energy part for this material, Bethe-Bloch formula
458        ionloss = theBetheBlochModel->TheValue(theProton,material,
459                                               lowEdgeEnergy) ;
460
461        ionloss -= DeltaRaysEnergy(couple,lowEdgeEnergy,proton_mass_c2) ;
462
463        ionloss *= (1.0 + paramB*highEnergy/lowEdgeEnergy) ;
464      }
465
466      // now put the loss into the vector
467      if(verboseLevel > 1) {
468        G4cout << "E(MeV)= " << lowEdgeEnergy/MeV
469               << "  dE/dx(MeV/mm)= " << ionloss*mm/MeV
470               << " in " << material->GetName() << G4endl;
471      }
472      aVector->PutValue(i,ionloss) ;
473    }
474    // Insert vector for this material into the table
475    theLossTable->insert(aVector) ;
476  }
477}
478
479//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
480
481void G4hLowEnergyIonisation::BuildDataForFluorescence(
482                         const G4ParticleDefinition& aParticleType)
483{
484
485  if(verboseLevel > 1) {
486    G4cout << "G4hLowEnergyIonisation::BuildDataForFluorescence for "
487           << aParticleType.GetParticleName() << " is started" << G4endl;
488  }
489
490  // fill data for fluorescence
491
492  deexcitationManager.SetCutForSecondaryPhotons(minGammaEnergy);
493  deexcitationManager.SetCutForAugerElectrons(minElectronEnergy);
494
495  G4double mass = aParticleType.GetPDGMass();
496  const G4ProductionCutsTable* theCoupleTable=
497        G4ProductionCutsTable::GetProductionCutsTable();
498  size_t numOfCouples = theCoupleTable->GetTableSize();
499
500  if (shellVacancy != 0) delete shellVacancy;
501  shellVacancy = new G4ShellVacancy();
502  G4DataVector* ksi = 0;
503  G4DataVector* ksi1 = 0;
504  G4DataVector* energy = 0;
505  G4DataVector* energy1 = 0;
506  size_t binForFluo = TotBin/10;
507  G4int length = zFluoDataVector.size();
508  if(length > 0) {
509    for(G4int i=0; i<length; i++) {
510      G4VEMDataSet* x = zFluoDataVector[i];
511      delete x;
512    }
513    zFluoDataVector.clear();
514  }
515
516  G4PhysicsLogVector* bVector = new G4PhysicsLogVector(LowestKineticEnergy,
517                                                       HighestKineticEnergy,
518                                                       binForFluo);
519  const G4AtomicTransitionManager* transitionManager =
520                             G4AtomicTransitionManager::Instance();
521
522  G4double bindingEnergy;
523  //  G4double x;
524  //  G4double y;
525
526  //  loop for materials
527  for (size_t j=0; j<numOfCouples; j++) {
528
529    // get material parameters needed for the energy loss calculation
530    const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(j);
531    const G4Material* material= couple->GetMaterial();
532
533    const G4ElementVector* theElementVector = material->GetElementVector();
534    size_t NumberOfElements = material->GetNumberOfElements() ;
535    const G4double* theAtomicNumDensityVector =
536                    material->GetAtomicNumDensityVector();
537    G4VDataSetAlgorithm* interp = new G4SemiLogInterpolation();
538    G4VEMDataSet* xsis = new G4CompositeEMDataSet(interp, 1., 1.);
539    G4VDataSetAlgorithm* interp1 = new G4SemiLogInterpolation();
540    G4VEMDataSet* xsis1 = new G4CompositeEMDataSet(interp1, 1., 1.);
541
542    G4double tCut = cutForDelta[j];
543    G4double elDensity = 1.;
544
545    for (size_t iel=0; iel<NumberOfElements; iel++ ) {
546
547      G4int Z = (G4int)((*theElementVector)[iel]->GetZ());
548      G4int nShells = transitionManager->NumberOfShells(Z);
549      energy = new G4DataVector();
550      ksi    = new G4DataVector();
551      energy1= new G4DataVector();
552      ksi1   = new G4DataVector();
553      //if(NumberOfElements > 1)
554      elDensity = theAtomicNumDensityVector[iel]/((G4double)nShells);
555
556      for (size_t j = 0; j<binForFluo; j++) {
557
558        G4double tkin  = bVector->GetLowEdgeEnergy(j);
559        G4double gamma = tkin/mass + 1.;
560        G4double beta2 = 1.0 - 1.0/(gamma*gamma);
561        G4double r     = electron_mass_c2/mass;
562        G4double tmax  = 2.*electron_mass_c2*(gamma*gamma - 1.)/(1. + 2.*gamma*r + r*r);
563        G4double cross   = 0.;
564        G4double cross1  = 0.;
565        G4double eAverage= 0.;
566        G4double tmin = std::min(tCut,tmax);
567        G4double rel;
568
569        for (G4int n=0; n<nShells; n++) {
570
571          bindingEnergy = transitionManager->Shell(Z, n)->BindingEnergy();
572          if (tmin > bindingEnergy) {
573            rel = std::log(tmin/bindingEnergy);
574            eAverage   += rel - beta2*(tmin - bindingEnergy)/tmax;
575            cross      += 1.0/bindingEnergy - 1.0/tmin - beta2*rel/tmax;
576          }
577          if (tmax > tmin) {
578            cross1     += 1.0/tmin - 1.0/tmax - beta2*std::log(tmax/tmin)/tmax;
579          }
580        }
581
582        cross1 *= elDensity;
583        energy1->push_back(tkin);
584        ksi1->push_back(cross1);
585
586        if(eAverage > 0.) cross /= eAverage;
587        else              cross  = 0.;
588
589        energy->push_back(tkin);
590        ksi->push_back(cross);
591      }
592      G4VDataSetAlgorithm* algo = interp->Clone();
593      G4VEMDataSet* set = new G4EMDataSet(Z,energy,ksi,algo,1.,1.);
594      xsis->AddComponent(set);
595      G4VDataSetAlgorithm* algo1 = interp1->Clone();
596      G4VEMDataSet* set1 = new G4EMDataSet(Z,energy1,ksi1,algo1,1.,1.);
597      xsis1->AddComponent(set1);
598    }
599    if(verboseLevel > 1) {
600      G4cout << "### Shell inverse cross sections for "
601             << material->GetName() << G4endl;
602      xsis->PrintData();
603      G4cout << "### Atom cross sections for "
604             << material->GetName() << G4endl;
605      xsis1->PrintData();
606    }
607    shellVacancy->AddXsiTable(xsis);
608    zFluoDataVector.push_back(xsis1);
609  }
610  delete bVector;
611}
612
613//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
614
615void G4hLowEnergyIonisation::BuildLambdaTable(
616                       const G4ParticleDefinition& aParticleType)
617
618{
619  // Build mean free path tables for the delta ray production process
620  //     tables are built for MATERIALS
621
622  if(verboseLevel > 1) {
623    G4cout << "G4hLowEnergyIonisation::BuildLambdaTable for "
624           << aParticleType.GetParticleName() << " is started" << G4endl;
625  }
626
627
628  G4double lowEdgeEnergy, value;
629  charge = aParticleType.GetPDGCharge()/eplus ;
630  chargeSquare = charge*charge ;
631  initialMass = aParticleType.GetPDGMass();
632
633  const G4ProductionCutsTable* theCoupleTable=
634        G4ProductionCutsTable::GetProductionCutsTable();
635  size_t numOfCouples = theCoupleTable->GetTableSize();
636
637
638  if (theMeanFreePathTable) {
639    theMeanFreePathTable->clearAndDestroy();
640    delete theMeanFreePathTable;
641  }
642
643  theMeanFreePathTable = new G4PhysicsTable(numOfCouples);
644
645  // loop for materials
646
647  for (size_t J=0 ; J < numOfCouples; J++) {
648
649    //create physics vector then fill it ....
650    G4PhysicsLogVector* aVector = new G4PhysicsLogVector(LowestKineticEnergy,
651                                                         HighestKineticEnergy,
652                                                         TotBin);
653
654    // compute the (macroscopic) cross section first
655    const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(J);
656    const G4Material* material= couple->GetMaterial();
657
658    const G4ElementVector* theElementVector =
659                           material->GetElementVector() ;
660    const G4double* theAtomicNumDensityVector =
661                           material->GetAtomicNumDensityVector();
662    const G4int NumberOfElements = material->GetNumberOfElements() ;
663
664      // get the electron kinetic energy cut for the actual material,
665      //  it will be used in ComputeMicroscopicCrossSection
666      // ( it is the SAME for ALL the ELEMENTS in THIS MATERIAL )
667      //   ------------------------------------------------------
668
669    G4double deltaCut = cutForDelta[J];
670
671    for ( G4int i = 0 ; i < TotBin ; i++ ) {
672      lowEdgeEnergy = aVector->GetLowEdgeEnergy(i) ;
673      G4double sigma = 0.0 ;
674      G4int Z;
675     
676      for (G4int iel=0; iel<NumberOfElements; iel++ ) {
677        Z = (G4int) (*theElementVector)[iel]->GetZ();
678        totalCrossSectionMap [Z] = ComputeMicroscopicCrossSection(
679                                                                  aParticleType,
680                                                                  lowEdgeEnergy,
681                                                                  Z,
682                                                                  deltaCut ) ; 
683        sigma += theAtomicNumDensityVector[iel]*ComputeMicroscopicCrossSection(
684                                                                               aParticleType,
685                                                                               lowEdgeEnergy,
686                                                                               Z,
687                                                                               deltaCut ) ; 
688       
689      }
690
691      // mean free path = 1./macroscopic cross section
692
693      value = sigma<=0 ? DBL_MAX : 1./sigma ;
694
695      aVector->PutValue(i, value) ;
696    }
697
698    theMeanFreePathTable->insert(aVector);
699  }
700
701}
702
703
704//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
705
706G4double G4hLowEnergyIonisation::ComputeMicroscopicCrossSection(
707                           const G4ParticleDefinition& aParticleType,
708                                 G4double kineticEnergy,
709                                 G4double atomicNumber,
710                                 G4double deltaCutInEnergy) const
711{
712  //******************************************************************
713  // cross section formula is OK for spin=0, 1/2, 1 only !
714  // *****************************************************************
715
716  // calculates the microscopic cross section in GEANT4 internal units
717  //    ( it is called for elements , AtomicNumber = z )
718
719  G4double energy, gamma, beta2, tmax, var;
720  G4double totalCrossSection = 0.0 ;
721
722  G4double particleMass = initialMass;
723
724  // get particle data ...................................
725
726  energy = kineticEnergy + particleMass;
727
728  // some kinematics......................
729
730  gamma  = energy/particleMass;
731  beta2  = 1.0 - 1.0/(gamma*gamma);
732  var    = electron_mass_c2/particleMass;
733  tmax   = 2.*electron_mass_c2*(gamma*gamma - 1.)/(1. + 2.*gamma*var + var*var);
734
735  // now you can calculate the total cross section
736
737  if( tmax > deltaCutInEnergy ) {
738
739    var=deltaCutInEnergy/tmax;
740    totalCrossSection = (1.0 - var*(1.0 - beta2*std::log(var))) / deltaCutInEnergy ;
741    G4double spin = aParticleType.GetPDGSpin() ;
742
743    // +term for spin=1/2 particle
744    if( 0.5 == spin )
745      totalCrossSection +=  0.5 * (tmax - deltaCutInEnergy) / (energy*energy);
746
747    // +term for spin=1 particle
748    else if( 0.9 < spin )
749      totalCrossSection += -std::log(var)/(3.0*deltaCutInEnergy) +
750        (tmax - deltaCutInEnergy) * ( (5.0+ 1.0/var)*0.25 / (energy*energy) -
751         beta2 / (tmax * deltaCutInEnergy) ) / 3.0 ;
752
753    totalCrossSection *= twopi_mc2_rcl2 * atomicNumber / beta2 ;
754  }
755
756  return totalCrossSection ;
757}
758
759//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
760
761G4double G4hLowEnergyIonisation::GetMeanFreePath(const G4Track& trackData,
762                                                 G4double, // previousStepSize
763                                                 enum G4ForceCondition* condition)
764{
765   const G4DynamicParticle* aParticle = trackData.GetDynamicParticle();
766   const G4MaterialCutsCouple* couple = trackData.GetMaterialCutsCouple();
767   const G4Material* material = couple->GetMaterial();
768   G4double meanFreePath;
769   G4bool isOutRange ;
770
771   *condition = NotForced ;
772
773   G4double kineticEnergy = (aParticle->GetKineticEnergy())*initialMass/(aParticle->GetMass());
774   charge = aParticle->GetCharge()/eplus;
775   chargeSquare = theIonEffChargeModel->TheValue(aParticle, material);
776
777   if(kineticEnergy < LowestKineticEnergy) meanFreePath = DBL_MAX;
778
779   else {
780     if(kineticEnergy > HighestKineticEnergy)
781                    kineticEnergy = HighestKineticEnergy;
782     meanFreePath = (((*theMeanFreePathTable)(couple->GetIndex()))->
783                    GetValue(kineticEnergy,isOutRange))/chargeSquare;
784     }
785
786   return meanFreePath ;
787}
788
789//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
790
791G4double G4hLowEnergyIonisation::GetConstraints(
792                                 const G4DynamicParticle* particle,
793                                 const G4MaterialCutsCouple* couple)
794{
795  // returns the Step limit
796  // dEdx is calculated as well as the range
797  // based on Effective Charge Approach
798
799  const G4Material* material = couple->GetMaterial();
800  G4Proton* theProton = G4Proton::Proton();
801  G4AntiProton* theAntiProton = G4AntiProton::AntiProton();
802
803  G4double stepLimit = 0.0 ;
804  G4double dx, highEnergy;
805
806  G4double massRatio = proton_mass_c2/(particle->GetMass()) ;
807  G4double kineticEnergy = particle->GetKineticEnergy() ;
808
809  // Scale the kinetic energy
810
811  G4double tscaled = kineticEnergy*massRatio ;
812  fBarkas = 0.0;
813
814  if(charge > 0.0) {
815
816    highEnergy = protonHighEnergy ;
817
818    fRangeNow = G4EnergyLossTables::GetRange(theProton, tscaled, couple);
819    dx = G4EnergyLossTables::GetRange(theProton, highEnergy, couple);
820    fdEdx = G4EnergyLossTables::GetDEDX(theProton, tscaled, couple)
821          * chargeSquare ;
822
823        // Correction for positive ions
824    if(theBarkas && tscaled > highEnergy) { 
825        fBarkas = BarkasTerm(material,tscaled)*std::sqrt(chargeSquare)*chargeSquare
826                + BlochTerm(material,tscaled,chargeSquare);
827    }
828    // Antiprotons and negative hadrons
829  } else {
830
831    highEnergy = antiProtonHighEnergy ;
832    fRangeNow = G4EnergyLossTables::GetRange(theAntiProton, tscaled, couple);
833    dx = G4EnergyLossTables::GetRange(theAntiProton, highEnergy, couple);
834    fdEdx = G4EnergyLossTables::GetDEDX(theAntiProton, tscaled, couple)
835          * chargeSquare ;
836
837    if(theBarkas && tscaled > highEnergy) { 
838        fBarkas = -BarkasTerm(material,tscaled)*std::sqrt(chargeSquare)*chargeSquare
839                + BlochTerm(material,tscaled,chargeSquare);
840    }
841  }
842  /*
843  const G4Material* mat = couple->GetMaterial();
844  G4double fac = gram/(MeV*cm2*mat->GetDensity());
845  G4cout << particle->GetDefinition()->GetParticleName()
846         << " in " << mat->GetName()
847         << " E(MeV)= " << kineticEnergy/MeV
848         << " dedx(MeV*cm^2/g)= " << fdEdx*fac
849         << " barcas(MeV*cm^2/gram)= " << fBarkas*fac
850         << " Q^2= " << chargeSquare
851         << G4endl;
852  */
853  // scaling back
854  fRangeNow /= (chargeSquare*massRatio) ;
855  dx        /= (chargeSquare*massRatio) ;
856
857  stepLimit  = fRangeNow ;
858  G4double r = std::min(finalRange, couple->GetProductionCuts()
859                 ->GetProductionCut(idxG4ElectronCut));
860
861  if (fRangeNow > r) {
862    stepLimit = dRoverRange*fRangeNow + r*(1.0 - dRoverRange)*(2.0 - r/fRangeNow);
863    if (stepLimit > fRangeNow) stepLimit = fRangeNow;
864  }
865  // compute the (random) Step limit in standard energy range
866  if(tscaled > highEnergy ) {
867
868    // add Barkas correction directly to dedx
869    fdEdx  += fBarkas;
870 
871    if(stepLimit > fRangeNow - dx*0.9) stepLimit = fRangeNow - dx*0.9 ;
872
873  // Step limit in low energy range
874  } else {
875    G4double x = dx*paramStepLimit;
876    if (stepLimit > x) stepLimit = x;
877  }
878  return stepLimit ;
879}
880
881//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
882
883G4VParticleChange* G4hLowEnergyIonisation::AlongStepDoIt(
884                                           const G4Track& trackData,
885                                           const G4Step& stepData)
886{
887  // compute the energy loss after a step
888  G4Proton* theProton = G4Proton::Proton();
889  G4AntiProton* theAntiProton = G4AntiProton::AntiProton();
890  G4double finalT = 0.0 ;
891
892  aParticleChange.Initialize(trackData) ;
893
894  const G4MaterialCutsCouple* couple = trackData.GetMaterialCutsCouple();
895  const G4Material* material = couple->GetMaterial();
896
897  // get the actual (true) Step length from stepData
898  const G4double step = stepData.GetStepLength() ;
899
900  const G4DynamicParticle* particle = trackData.GetDynamicParticle() ;
901
902  G4double kineticEnergy = particle->GetKineticEnergy() ;
903  G4double massRatio = proton_mass_c2/(particle->GetMass()) ;
904  G4double tscaled= kineticEnergy*massRatio ;
905  G4double eloss = 0.0 ;
906  G4double nloss = 0.0 ;
907
908
909    // very small particle energy
910  if(kineticEnergy < MinKineticEnergy) {
911
912    eloss = kineticEnergy ;
913
914    // particle energy outside tabulated energy range
915  } else if( kineticEnergy > HighestKineticEnergy) {
916    eloss = step*fdEdx ;
917
918    // big step
919  } else if(step >= fRangeNow ) {
920    eloss = kineticEnergy ;
921
922    // tabulated range
923  } else {
924
925    // step longer than linear step limit
926    if(step > linLossLimit*fRangeNow) {
927
928      G4double rscaled= fRangeNow*massRatio*chargeSquare ;
929      G4double sscaled=   step   *massRatio*chargeSquare ;
930
931      if(charge > 0.0) {
932        eloss = G4EnergyLossTables::GetPreciseEnergyFromRange(
933                                    theProton,rscaled, couple) -
934                G4EnergyLossTables::GetPreciseEnergyFromRange(
935                                    theProton,rscaled-sscaled,couple) ;
936
937      } else {
938        eloss = G4EnergyLossTables::GetPreciseEnergyFromRange(
939                                    theAntiProton,rscaled,couple) -
940                G4EnergyLossTables::GetPreciseEnergyFromRange(
941                                    theAntiProton,rscaled-sscaled,couple) ;
942      }
943      eloss /= massRatio ;
944
945      // Barkas correction at big step     
946      eloss += fBarkas*step;
947
948    // step shorter than linear step limit
949    } else {
950      eloss = step*fdEdx ;
951    }
952    if(nStopping && tscaled < protonHighEnergy) {
953      nloss = (theNuclearStoppingModel->TheValue(particle, material))*step;
954    }
955  }
956
957  if(eloss < 0.0) eloss = 0.0;
958
959  finalT = kineticEnergy - eloss - nloss;
960
961  if( EnlossFlucFlag && 0.0 < eloss && finalT > MinKineticEnergy) {
962
963    //  now the electron loss with fluctuation
964    eloss = ElectronicLossFluctuation(particle, couple, eloss, step) ;
965    if(eloss < 0.0) eloss = 0.0;
966    finalT = kineticEnergy - eloss - nloss;
967  }
968
969  //  stop particle if the kinetic energy <= MinKineticEnergy
970  if (finalT*massRatio <= MinKineticEnergy ) {
971
972     finalT = 0.0;
973      if(!particle->GetDefinition()->GetProcessManager()->
974                     GetAtRestProcessVector()->size())
975        aParticleChange.ProposeTrackStatus(fStopAndKill);
976      else
977        aParticleChange.ProposeTrackStatus(fStopButAlive);
978  }
979
980  aParticleChange.ProposeEnergy( finalT );
981  eloss = kineticEnergy-finalT;
982
983  // Deexcitation only of ionised atoms
984  G4double hMass = particle->GetMass();
985  std::vector<G4DynamicParticle*>* newpart = 0;
986  G4DynamicParticle* part = 0;
987
988  if(theFluo) newpart = DeexciteAtom(couple, kineticEnergy, hMass, eloss);
989
990  if(newpart != 0) {
991
992    size_t nSecondaries = newpart->size();
993    aParticleChange.SetNumberOfSecondaries(nSecondaries);
994    G4Track* newtrack = 0;
995    const G4StepPoint* preStep = stepData.GetPreStepPoint();
996    const G4StepPoint* postStep = stepData.GetPostStepPoint();
997    G4ThreeVector r = preStep->GetPosition();
998    G4ThreeVector deltaR = postStep->GetPosition();
999    deltaR -= r;
1000    G4double t = preStep->GetGlobalTime();
1001    G4double deltaT = postStep->GetGlobalTime();
1002    deltaT -= t;
1003    G4double time, q, e;
1004    G4ThreeVector position;
1005
1006    for(size_t i=0; i<nSecondaries; i++) {
1007
1008      part = (*newpart)[i];
1009      if(part) {
1010
1011        e = part->GetKineticEnergy();
1012        if(e <= eloss) {
1013
1014          eloss -= e;
1015          q = G4UniformRand();
1016          time = deltaT*q + t;
1017          position  = deltaR*q;
1018          position += r;
1019          newtrack = new G4Track(part, time, position);
1020          aParticleChange.AddSecondary(newtrack);
1021
1022        } else {
1023
1024          delete part;
1025
1026        }
1027      }
1028    }
1029    delete newpart;
1030  }
1031
1032  aParticleChange.ProposeLocalEnergyDeposit(eloss);
1033  return &aParticleChange ;
1034}
1035
1036//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1037
1038G4double G4hLowEnergyIonisation::ProtonParametrisedDEDX(
1039                                 const G4MaterialCutsCouple* couple,
1040                                       G4double kineticEnergy) const
1041{
1042  const G4Material* material = couple->GetMaterial();
1043  G4Proton* theProton = G4Proton::Proton();
1044  G4double eloss = 0.0;
1045
1046    // Free Electron Gas Model
1047  if(kineticEnergy < protonLowEnergy) {
1048    eloss = (theProtonModel->TheValue(theProton, material, protonLowEnergy))
1049          * std::sqrt(kineticEnergy/protonLowEnergy) ;
1050
1051    // Parametrisation
1052  } else {
1053    eloss = theProtonModel->TheValue(theProton, material, kineticEnergy) ;
1054  }
1055
1056  // Delta rays energy
1057  eloss -= DeltaRaysEnergy(couple,kineticEnergy,proton_mass_c2) ;
1058
1059  if(verboseLevel > 2) {
1060    G4cout << "p E(MeV)= " << kineticEnergy/MeV
1061           << " dE/dx(MeV/mm)= " << eloss*mm/MeV
1062           << " for " << material->GetName()
1063           << " model: " << theProtonModel << G4endl;
1064  }
1065
1066  if(eloss < 0.0) eloss = 0.0 ;
1067
1068  return eloss ;
1069}
1070
1071//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1072
1073G4double G4hLowEnergyIonisation::AntiProtonParametrisedDEDX(
1074                                 const G4MaterialCutsCouple* couple,
1075                                       G4double kineticEnergy) const
1076{
1077  const G4Material* material = couple->GetMaterial();
1078  G4AntiProton* theAntiProton = G4AntiProton::AntiProton();
1079  G4double eloss = 0.0 ;
1080
1081  // Antiproton model is used
1082  if(theAntiProtonModel->IsInCharge(theAntiProton,material)) {
1083    if(kineticEnergy < antiProtonLowEnergy) {
1084      eloss = theAntiProtonModel->TheValue(theAntiProton,material,antiProtonLowEnergy)
1085            * std::sqrt(kineticEnergy/antiProtonLowEnergy) ;
1086
1087    // Parametrisation
1088    } else {
1089      eloss = theAntiProtonModel->TheValue(theAntiProton,material,
1090                                           kineticEnergy);
1091    }
1092
1093  // The proton model is used + Barkas correction
1094  } else {
1095    if(kineticEnergy < protonLowEnergy) {
1096      eloss = theProtonModel->TheValue(G4Proton::Proton(),material,protonLowEnergy)
1097          * std::sqrt(kineticEnergy/protonLowEnergy) ;
1098
1099    // Parametrisation
1100    } else {
1101      eloss = theProtonModel->TheValue(G4Proton::Proton(),material,
1102                                       kineticEnergy);
1103    }
1104    //if(theBarkas) eloss -= 2.0*BarkasTerm(material, kineticEnergy);
1105  }
1106
1107  // Delta rays energy
1108  eloss -= DeltaRaysEnergy(couple,kineticEnergy,proton_mass_c2) ;
1109
1110  if(verboseLevel > 2) {
1111    G4cout << "pbar E(MeV)= " << kineticEnergy/MeV
1112           << " dE/dx(MeV/mm)= " << eloss*mm/MeV
1113           << " for " << material->GetName()
1114           << " model: " << theProtonModel << G4endl;
1115  }
1116
1117  if(eloss < 0.0) eloss = 0.0 ;
1118
1119  return eloss ;
1120}
1121
1122//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1123
1124G4double G4hLowEnergyIonisation::DeltaRaysEnergy(
1125                                 const G4MaterialCutsCouple* couple,
1126                                       G4double kineticEnergy,
1127                                       G4double particleMass) const
1128{
1129  G4double dloss = 0.0 ;
1130
1131  G4double deltaCutNow = cutForDelta[(couple->GetIndex())] ;
1132  const G4Material* material = couple->GetMaterial();
1133  G4double electronDensity = material->GetElectronDensity();
1134  G4double eexc = material->GetIonisation()->GetMeanExcitationEnergy();
1135
1136  G4double tau = kineticEnergy/particleMass ;
1137  G4double rateMass = electron_mass_c2/particleMass ;
1138
1139  // some local variables
1140
1141  G4double gamma,bg2,beta2,tmax,x ;
1142
1143  gamma = tau + 1.0 ;
1144  bg2 = tau*(tau+2.0) ;
1145  beta2 = bg2/(gamma*gamma) ;
1146  tmax = 2.*electron_mass_c2*bg2/(1.0+2.0*gamma*rateMass+rateMass*rateMass) ;
1147
1148  // Validity range for delta electron cross section
1149  G4double deltaCut = std::max(deltaCutNow, eexc);
1150
1151  if ( deltaCut < tmax) {
1152    x = deltaCut / tmax ;
1153    dloss = ( beta2 * (x - 1.0) - std::log(x) ) * twopi_mc2_rcl2
1154          * electronDensity / beta2 ;
1155  }
1156  return dloss ;
1157}
1158
1159//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1160
1161G4VParticleChange* G4hLowEnergyIonisation::PostStepDoIt(
1162                                           const G4Track& trackData,
1163                                           const G4Step& stepData)
1164{
1165  // Units are expressed in GEANT4 internal units.
1166
1167  G4double KineticEnergy,TotalEnergy,TotalMomentum,betasquare,
1168           DeltaKineticEnergy,DeltaTotalMomentum,costheta,sintheta,phi,
1169           dirx,diry,dirz,finalKineticEnergy,finalPx,finalPy,finalPz,
1170           x,xc,grej,Psquare,Esquare,rate,finalMomentum ;
1171
1172  aParticleChange.Initialize(trackData) ;
1173  const G4MaterialCutsCouple* couple = trackData.GetMaterialCutsCouple();
1174
1175  const G4DynamicParticle* aParticle = trackData.GetDynamicParticle() ;
1176
1177  // some kinematics
1178
1179  ParticleMass=aParticle->GetDefinition()->GetPDGMass();
1180  KineticEnergy=aParticle->GetKineticEnergy();
1181  TotalEnergy=KineticEnergy + ParticleMass ;
1182  Psquare=KineticEnergy*(TotalEnergy+ParticleMass) ;
1183  Esquare=TotalEnergy*TotalEnergy;
1184  betasquare=Psquare/Esquare;
1185  G4ThreeVector ParticleDirection = aParticle->GetMomentumDirection() ;
1186
1187  G4double gamma= KineticEnergy/ParticleMass + 1.;
1188  G4double r    = electron_mass_c2/ParticleMass;
1189  G4double tmax = 2.*electron_mass_c2*(gamma*gamma - 1.)/(1. + 2.*gamma*r + r*r);
1190
1191  // Validity range for delta electron cross section
1192  G4double DeltaCut = cutForDelta[couple->GetIndex()];
1193
1194  // This should not be a case
1195  if(DeltaCut >= tmax)
1196       return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
1197
1198  xc   = DeltaCut / tmax;
1199  rate = tmax / TotalEnergy;
1200  rate = rate*rate ;
1201  G4double spin = aParticle->GetDefinition()->GetPDGSpin() ;
1202
1203  // sampling follows ...
1204      do {
1205        x=xc/(1.-(1.-xc)*G4UniformRand());
1206
1207        if(0.0 == spin) {
1208          grej = 1.0 - betasquare * x ;
1209
1210        } else if (0.5 == spin) {
1211          grej = (1.0 - betasquare * x + 0.5*x*x*rate) / (1.0 + 0.5 * rate) ;
1212
1213        } else {
1214          grej = (1.0 - betasquare * x ) * (1.0 + x/ (3.0*xc)) +
1215            x * x * rate * (1.0 + 0.5 * x / xc) / 3.0 /
1216            (1.0 + 1.0/(3.0*xc) + rate *(1.0+ 0.5/xc) /3.0) ;
1217        }
1218
1219      } while( G4UniformRand() > grej );
1220
1221
1222  DeltaKineticEnergy = x * tmax;
1223
1224  DeltaTotalMomentum = std::sqrt(DeltaKineticEnergy * (DeltaKineticEnergy +
1225                                                  2. * electron_mass_c2 )) ;
1226  TotalMomentum = std::sqrt(Psquare) ;
1227  costheta = DeltaKineticEnergy * (TotalEnergy + electron_mass_c2)
1228    /(DeltaTotalMomentum * TotalMomentum) ;
1229
1230  //  protection against costheta > 1 or < -1   ---------------
1231  if ( costheta < -1. )
1232    costheta = -1. ;
1233  if ( costheta > +1. )
1234    costheta = +1. ;
1235
1236  //  direction of the delta electron  ........
1237  phi = twopi * G4UniformRand() ;
1238  sintheta = std::sqrt(1. - costheta*costheta);
1239  dirx = sintheta * std::cos(phi) ;
1240  diry = sintheta * std::sin(phi) ;
1241  dirz = costheta ;
1242
1243  G4ThreeVector DeltaDirection(dirx,diry,dirz) ;
1244  DeltaDirection.rotateUz(ParticleDirection) ;
1245
1246  // create G4DynamicParticle object for delta ray
1247  G4DynamicParticle *theDeltaRay = new G4DynamicParticle;
1248  theDeltaRay->SetKineticEnergy( DeltaKineticEnergy );
1249  theDeltaRay->SetMomentumDirection(DeltaDirection.x(),
1250                                    DeltaDirection.y(),
1251                                    DeltaDirection.z());
1252  theDeltaRay->SetDefinition(G4Electron::Electron());
1253
1254  // fill aParticleChange
1255  finalKineticEnergy = KineticEnergy - DeltaKineticEnergy ;
1256
1257  // Generation of Fluorescence and Auger
1258  size_t nSecondaries = 0;
1259  size_t totalNumber  = 1;
1260  std::vector<G4DynamicParticle*>* secondaryVector = 0;
1261  G4DynamicParticle* aSecondary = 0;
1262  G4ParticleDefinition* type = 0;
1263
1264  // Select atom and shell
1265  G4int Z = SelectRandomAtom(couple, KineticEnergy);
1266
1267  //   G4cout << "Fluorescence is switched :" << theFluo << G4endl;
1268
1269  // Fluorescence data start from element 6
1270  if(theFluo && Z > 5) {
1271
1272
1273
1274    // Atom total cross section     
1275    shellCS->SetTotalCS(totalCrossSectionMap[Z]);   
1276
1277    G4int shell = shellCS->SelectRandomShell(Z, KineticEnergy,ParticleMass,DeltaKineticEnergy);
1278
1279    if (shell!=-1) {       
1280     
1281      const G4AtomicShell* atomicShell =
1282        (G4AtomicTransitionManager::Instance())->Shell(Z, shell);
1283      G4double bindingEnergy = atomicShell->BindingEnergy();
1284     
1285      if(verboseLevel > 1) {
1286        G4cout << "PostStep Z= " << Z << " shell= " << shell
1287               << " bindingE(keV)= " << bindingEnergy/keV
1288               << " finalE(keV)= " << finalKineticEnergy/keV
1289               << G4endl;
1290      }
1291     
1292     
1293     
1294      if (finalKineticEnergy >= bindingEnergy
1295          && (bindingEnergy >= minGammaEnergy
1296              ||  bindingEnergy >= minElectronEnergy) ) {
1297       
1298        G4int shellId = atomicShell->ShellId();
1299        secondaryVector = deexcitationManager.GenerateParticles(Z, shellId);
1300       
1301        if (secondaryVector != 0) {
1302         
1303          nSecondaries = secondaryVector->size();
1304          for (size_t i = 0; i<nSecondaries; i++) {
1305           
1306            aSecondary = (*secondaryVector)[i];
1307            if (aSecondary) {
1308             
1309              G4double e = aSecondary->GetKineticEnergy();
1310              type = aSecondary->GetDefinition();
1311              if (e < finalKineticEnergy &&
1312                  ((type == G4Gamma::Gamma() && e > minGammaEnergy ) ||
1313                   (type == G4Electron::Electron() && e > minElectronEnergy ))) {
1314               
1315                finalKineticEnergy -= e;
1316                totalNumber++;
1317               
1318              } else {
1319               
1320                delete aSecondary;
1321                (*secondaryVector)[i] = 0;
1322              }
1323            }
1324          }
1325        }
1326      }
1327    }
1328  }
1329 
1330  // Save delta-electrons
1331
1332  G4double edep = 0.0;
1333
1334  if (finalKineticEnergy > MinKineticEnergy)
1335    {
1336      finalPx = TotalMomentum*ParticleDirection.x()
1337        - DeltaTotalMomentum*DeltaDirection.x();
1338      finalPy = TotalMomentum*ParticleDirection.y()
1339        - DeltaTotalMomentum*DeltaDirection.y();
1340      finalPz = TotalMomentum*ParticleDirection.z()
1341        - DeltaTotalMomentum*DeltaDirection.z();
1342      finalMomentum =
1343        std::sqrt(finalPx*finalPx+finalPy*finalPy+finalPz*finalPz) ;
1344      finalPx /= finalMomentum ;
1345      finalPy /= finalMomentum ;
1346      finalPz /= finalMomentum ;
1347
1348      aParticleChange.ProposeMomentumDirection( finalPx,finalPy,finalPz );
1349    }
1350  else
1351    {
1352      edep = finalKineticEnergy;
1353      finalKineticEnergy = 0.;
1354      aParticleChange.ProposeMomentumDirection(ParticleDirection.x(),
1355                      ParticleDirection.y(),ParticleDirection.z());
1356      if(!aParticle->GetDefinition()->GetProcessManager()->
1357                     GetAtRestProcessVector()->size())
1358        aParticleChange.ProposeTrackStatus(fStopAndKill);
1359      else
1360        aParticleChange.ProposeTrackStatus(fStopButAlive);
1361    }
1362
1363  aParticleChange.ProposeEnergy( finalKineticEnergy );
1364  aParticleChange.ProposeLocalEnergyDeposit (edep);
1365  aParticleChange.SetNumberOfSecondaries(totalNumber);
1366  aParticleChange.AddSecondary(theDeltaRay);
1367
1368  // Save Fluorescence and Auger
1369
1370  if (secondaryVector) {
1371
1372    for (size_t l = 0; l < nSecondaries; l++) {
1373
1374      aSecondary = (*secondaryVector)[l];
1375      if(aSecondary) {
1376        aParticleChange.AddSecondary(aSecondary);
1377      }
1378    }
1379    delete secondaryVector;
1380  }
1381
1382  return G4VContinuousDiscreteProcess::PostStepDoIt(trackData,stepData);
1383}
1384
1385//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1386
1387
1388
1389void G4hLowEnergyIonisation::SelectShellIonisationCS(G4String val) {
1390
1391  if (val == "analytical" )  { 
1392    if (shellCS) delete shellCS;
1393    shellCS = new G4teoCrossSection(val);
1394  }
1395  else if (val == "empirical") {
1396    if (shellCS) delete shellCS;
1397    shellCS = new G4empCrossSection();
1398  }
1399}
1400
1401
1402
1403//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1404
1405
1406std::vector<G4DynamicParticle*>* G4hLowEnergyIonisation::DeexciteAtom(const G4MaterialCutsCouple* couple,
1407                                           G4double incidentEnergy,
1408                                           G4double hMass,
1409                                           G4double eLoss)
1410{
1411
1412  if (verboseLevel > 1) {
1413        G4cout << "DeexciteAtom: cutForPhotons(keV)= " << minGammaEnergy/keV
1414               << "  cutForElectrons(keV)= " << minElectronEnergy/keV
1415               << "  eLoss(MeV)= " << eLoss
1416               << G4endl;
1417  }
1418
1419
1420
1421  if(eLoss < minGammaEnergy && eLoss < minElectronEnergy) return 0;
1422
1423  const G4Material* material = couple->GetMaterial();
1424  G4int index    = couple->GetIndex();
1425  //  G4double eexc  = material->GetIonisation()->GetMeanExcitationEnergy();
1426  G4double gamma = incidentEnergy/hMass + 1;
1427  G4double beta2 = 1.0 - 1.0/(gamma*gamma);
1428  G4double r     = electron_mass_c2/hMass;
1429  G4double tmax  = 2.*electron_mass_c2*(gamma*gamma - 1.)/(1. + 2.*gamma*r + r*r);
1430  G4double tcut  = std::min(tmax,cutForDelta[index]);
1431  const G4AtomicTransitionManager* transitionManager =
1432                             G4AtomicTransitionManager::Instance();
1433
1434  size_t nElements = material->GetNumberOfElements();
1435  const G4ElementVector* theElementVector = material->GetElementVector();
1436  G4bool stop = true;
1437
1438  for (size_t j=0; j<nElements; j++) {
1439
1440    G4int Z = (G4int)((*theElementVector)[j]->GetZ());
1441    G4double maxE = transitionManager->Shell(Z, 0)->BindingEnergy();
1442
1443    if (Z > 5 && maxE < tcut && (maxE > minGammaEnergy || maxE > minElectronEnergy) ) {
1444      stop = false;
1445      break;
1446    }
1447  }
1448
1449  if(stop) return 0;
1450
1451  // create vector of tracks of secondary particles
1452
1453  std::vector<G4DynamicParticle*>* partVector =
1454         new std::vector<G4DynamicParticle*>;
1455  std::vector<G4DynamicParticle*>* secVector = 0;
1456  G4DynamicParticle* aSecondary = 0;
1457  G4ParticleDefinition* type = 0;
1458  G4double e, tkin, grej;
1459  G4ThreeVector position;
1460  G4int shell, shellId;
1461
1462  // sample secondaries
1463
1464  G4double etot = 0.0;
1465  std::vector<G4int> n = shellVacancy->GenerateNumberOfIonisations(couple,
1466                                         incidentEnergy, eLoss);
1467
1468  for (size_t i=0; i<nElements; i++) {
1469
1470    size_t nVacancies = n[i];
1471    G4int Z = (G4int)((*theElementVector)[i]->GetZ());
1472    G4double maxE = transitionManager->Shell(Z, 0)->BindingEnergy();
1473
1474    if (nVacancies && Z  > 5 && maxE < tcut && (maxE > minGammaEnergy || maxE > minElectronEnergy)) {
1475      for(size_t j=0; j<nVacancies; j++) {
1476
1477        // sampling follows
1478        do {
1479          tkin = tcut/(1.0 + (tcut/maxE - 1.0)*G4UniformRand());
1480          grej = 1.0 - beta2 * tkin/tmax;
1481
1482        } while( G4UniformRand() > grej );
1483
1484        shell = shellCS->SelectRandomShell(Z,incidentEnergy,hMass,tkin);
1485
1486        shellId = transitionManager->Shell(Z, shell)->ShellId();
1487        G4double maxE = transitionManager->Shell(Z, shell)->BindingEnergy();
1488
1489        if (maxE>minGammaEnergy || maxE>minElectronEnergy ) {
1490          secVector = deexcitationManager.GenerateParticles(Z, shellId);
1491        } else {
1492          secVector = 0;
1493        }
1494
1495        if (secVector) {
1496
1497          for (size_t l = 0; l<secVector->size(); l++) {
1498
1499            aSecondary = (*secVector)[l];
1500            if(aSecondary) {
1501
1502              e = aSecondary->GetKineticEnergy();
1503              type = aSecondary->GetDefinition();
1504              if ( etot + e <= eLoss &&
1505                   ( (type == G4Gamma::Gamma() && e > minGammaEnergy ) ||
1506                   (type == G4Electron::Electron() && e > minElectronEnergy) ) ) {
1507
1508                     etot += e;
1509                     partVector->push_back(aSecondary);
1510
1511              } else {
1512                     delete aSecondary;
1513              }
1514            }
1515          }
1516          delete secVector;
1517        }
1518      }
1519    }
1520  }
1521
1522  if(partVector->empty()) {
1523    delete partVector;
1524    return 0;
1525  }
1526
1527  return partVector;
1528}
1529
1530//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1531
1532G4int G4hLowEnergyIonisation::SelectRandomAtom(const G4MaterialCutsCouple* couple,
1533                                                     G4double kineticEnergy) const
1534{
1535  const G4Material* material = couple->GetMaterial();
1536  G4int nElements = material->GetNumberOfElements();
1537  G4int Z = 0;
1538
1539  if(nElements == 1) {
1540    Z = (G4int)(material->GetZ());
1541    return Z;
1542  }
1543
1544  const G4ElementVector* theElementVector = material->GetElementVector();
1545  std::vector<G4double> p;
1546  G4int index = couple->GetIndex();
1547
1548  G4double norm = 0.0;
1549  for (G4int j=0; j<nElements; j++) {
1550
1551    const G4VEMDataSet* set = (zFluoDataVector[index])->GetComponent(j);
1552    G4double cross    = set->FindValue(kineticEnergy);
1553
1554    p.push_back(cross);
1555    norm += cross;
1556  }
1557
1558  if(norm == 0.0) return 0;
1559
1560  G4double q = norm*G4UniformRand();
1561
1562  for (G4int i=0; i<nElements; i++) {
1563
1564    if(p[i] > q) {
1565       Z = (G4int)((*theElementVector)[i]->GetZ());
1566       break;
1567    }
1568    q -= p[i];
1569  }
1570
1571  return Z;
1572}
1573
1574//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1575
1576G4double G4hLowEnergyIonisation::ComputeDEDX(
1577                                 const G4ParticleDefinition* aParticle,
1578                                 const G4MaterialCutsCouple* couple,
1579                                 G4double kineticEnergy)
1580{
1581  const G4Material* material = couple->GetMaterial();
1582  G4Proton* theProton = G4Proton::Proton();
1583  G4AntiProton* theAntiProton = G4AntiProton::AntiProton();
1584  G4double dedx = 0.0 ;
1585
1586  G4double tscaled = kineticEnergy*proton_mass_c2/(aParticle->GetPDGMass()) ;
1587  charge  = aParticle->GetPDGCharge() ;
1588
1589  if(charge>0.0) {
1590    if(tscaled > protonHighEnergy) {
1591      dedx=G4EnergyLossTables::GetDEDX(theProton,tscaled,couple) ;
1592
1593    } else {
1594      dedx=ProtonParametrisedDEDX(couple,tscaled) ;
1595    }
1596
1597  } else {
1598    if(tscaled > antiProtonHighEnergy) {
1599      dedx=G4EnergyLossTables::GetDEDX(theAntiProton,tscaled,couple);
1600
1601    } else {
1602      dedx=AntiProtonParametrisedDEDX(couple,tscaled) ;
1603    }
1604  }
1605  dedx *= theIonEffChargeModel->TheValue(aParticle, material, kineticEnergy) ;
1606
1607  return dedx ;
1608}
1609
1610//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1611
1612G4double G4hLowEnergyIonisation::BarkasTerm(const G4Material* material,
1613                                                  G4double kineticEnergy) const
1614//Function to compute the Barkas term for protons:
1615//
1616//Ref. Z_1^3 effect in the stopping power of matter for charged particles
1617//     J.C Ashley and R.H.Ritchie
1618//     Physical review B Vol.5 No.7 1 April 1972 pagg. 2393-2397
1619//
1620{
1621  static double FTable[47][2] = {
1622   { 0.02, 21.5},
1623   { 0.03, 20.0},
1624   { 0.04, 18.0},
1625   { 0.05, 15.6},
1626   { 0.06, 15.0},
1627   { 0.07, 14.0},
1628   { 0.08, 13.5},
1629   { 0.09, 13.},
1630   { 0.1,  12.2},
1631   { 0.2,  9.25},
1632   { 0.3,  7.0},
1633   { 0.4,  6.0},
1634   { 0.5,  4.5},
1635   { 0.6,  3.5},
1636   { 0.7,  3.0},
1637   { 0.8,  2.5},
1638   { 0.9,  2.0},
1639   { 1.0,  1.7},
1640   { 1.2,  1.2},
1641   { 1.3,  1.0},
1642   { 1.4,  0.86},
1643   { 1.5,  0.7},
1644   { 1.6,  0.61},
1645   { 1.7,  0.52},
1646   { 1.8,  0.5},
1647   { 1.9,  0.43},
1648   { 2.0,  0.42},
1649   { 2.1,  0.3},
1650   { 2.4,  0.2},
1651   { 3.0,  0.13},
1652   { 3.08, 0.1},
1653   { 3.1,  0.09},
1654   { 3.3,  0.08},
1655   { 3.5,  0.07},
1656   { 3.8,  0.06},
1657   { 4.0,  0.051},
1658   { 4.1,  0.04},
1659   { 4.8,  0.03},
1660   { 5.0,  0.024},
1661   { 5.1,  0.02},
1662   { 6.0,  0.013},
1663   { 6.5,  0.01},
1664   { 7.0,  0.009},
1665   { 7.1,  0.008},
1666   { 8.0,  0.006},
1667   { 9.0,  0.0032},
1668   { 10.0, 0.0025} };
1669
1670  // Information on particle and material
1671  G4double kinE  = kineticEnergy ;
1672  if(0.5*MeV > kinE) kinE = 0.5*MeV ;
1673  G4double gamma = 1.0 + kinE / proton_mass_c2 ;
1674  G4double beta2 = 1.0 - 1.0/(gamma*gamma) ;
1675  if(0.0 >= beta2) return 0.0;
1676
1677  G4double BarkasTerm = 0.0;
1678  G4double AMaterial = 0.0;
1679  G4double ZMaterial = 0.0;
1680  const G4ElementVector* theElementVector = material->GetElementVector();
1681  G4int numberOfElements = material->GetNumberOfElements();
1682
1683  for (G4int i = 0; i<numberOfElements; i++) {
1684
1685    AMaterial = (*theElementVector)[i]->GetA()*mole/g;
1686    ZMaterial = (*theElementVector)[i]->GetZ();
1687
1688    G4double X = 137.0 * 137.0 * beta2 / ZMaterial;
1689
1690    // Variables to compute L_1
1691    G4double Eta0Chi = 0.8;
1692    G4double EtaChi = Eta0Chi * ( 1.0 + 6.02*std::pow( ZMaterial,-1.19 ) );
1693    G4double W = ( EtaChi * std::pow( ZMaterial,1.0/6.0 ) ) / std::sqrt(X);
1694    G4double FunctionOfW = FTable[46][1]*FTable[46][0]/W ;
1695
1696    for(G4int j=0; j<47; j++) {
1697
1698      if( W < FTable[j][0] ) {
1699
1700        if(0 == j) {
1701          FunctionOfW = FTable[0][1] ;
1702
1703        } else {
1704          FunctionOfW = (FTable[j][1] - FTable[j-1][1]) * (W - FTable[j-1][0])
1705                      / (FTable[j][0] - FTable[j-1][0])
1706                      +  FTable[j-1][1] ;
1707        }
1708
1709        break;
1710      }
1711
1712    }
1713
1714    BarkasTerm += FunctionOfW /( std::sqrt(ZMaterial * X) * X);
1715  }
1716
1717  BarkasTerm *= twopi_mc2_rcl2 * (material->GetElectronDensity()) / beta2 ;
1718
1719  return BarkasTerm;
1720}
1721
1722//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1723
1724G4double G4hLowEnergyIonisation::BlochTerm(const G4Material* material,
1725                                                 G4double kineticEnergy,
1726                                                 G4double cSquare) const
1727//Function to compute the Bloch term for protons:
1728//
1729//Ref. Z_1^3 effect in the stopping power of matter for charged particles
1730//     J.C Ashley and R.H.Ritchie
1731//     Physical review B Vol.5 No.7 1 April 1972 pagg. 2393-2397
1732//
1733{
1734  G4double eloss = 0.0 ;
1735  G4double gamma = 1.0 + kineticEnergy / proton_mass_c2 ;
1736  G4double beta2 = 1.0 - 1.0/(gamma*gamma) ;
1737  G4double y = cSquare / (137.0*137.0*beta2) ;
1738
1739  if(y < 0.05) {
1740    eloss = 1.202 ;
1741
1742  } else {
1743    eloss = 1.0 / (1.0 + y) ;
1744    G4double de = eloss ;
1745
1746    for(G4int i=2; de>eloss*0.01; i++) {
1747      de = 1.0/( i * (i*i + y)) ;
1748      eloss += de ;
1749    }
1750  }
1751  eloss *= -1.0 * y * cSquare * twopi_mc2_rcl2 *
1752            (material->GetElectronDensity()) / beta2 ;
1753
1754  return eloss;
1755}
1756
1757//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1758
1759G4double G4hLowEnergyIonisation::ElectronicLossFluctuation(
1760                                 const G4DynamicParticle* particle,
1761                                 const G4MaterialCutsCouple* couple,
1762                                       G4double meanLoss,
1763                                       G4double step) const
1764//  calculate actual loss from the mean loss
1765//  The model used to get the fluctuation is essentially the same
1766// as in Glandz in Geant3.
1767{
1768  // data members to speed up the fluctuation calculation
1769  //  G4int imat ;
1770  //  G4double f1Fluct,f2Fluct,e1Fluct,e2Fluct,rateFluct,ipotFluct;
1771  //  G4double e1LogFluct,e2LogFluct,ipotLogFluct;
1772
1773  static const G4double minLoss = 1.*eV ;
1774  static const G4double kappa = 10. ;
1775  static const G4double theBohrBeta2 = 50.0 * keV/proton_mass_c2 ;
1776
1777  const G4Material* material = couple->GetMaterial();
1778  G4int    imaterial   = couple->GetIndex() ;
1779  G4double ipotFluct   = material->GetIonisation()->GetMeanExcitationEnergy() ;
1780  G4double electronDensity = material->GetElectronDensity() ;
1781  G4double zeff = electronDensity/(material->GetTotNbOfAtomsPerVolume()) ;
1782
1783  // get particle data
1784  G4double tkin   = particle->GetKineticEnergy();
1785  G4double particleMass = particle->GetMass() ;
1786  G4double deltaCutInKineticEnergyNow = cutForDelta[imaterial];
1787
1788  // shortcut for very very small loss
1789  if(meanLoss < minLoss) return meanLoss ;
1790
1791  // Validity range for delta electron cross section
1792  G4double threshold = std::max(deltaCutInKineticEnergyNow,ipotFluct);
1793  G4double loss, siga;
1794
1795  G4double rmass = electron_mass_c2/particleMass;
1796  G4double tau   = tkin/particleMass;
1797  G4double tau1 = tau+1.0;
1798  G4double tau2 = tau*(tau+2.);
1799  G4double tmax    = 2.*electron_mass_c2*tau2/(1.+2.*tau1*rmass+rmass*rmass);
1800
1801
1802  if(tmax > threshold) tmax = threshold;
1803  G4double beta2 = tau2/(tau1*tau1);
1804
1805  // Gaussian fluctuation
1806  if(meanLoss > kappa*tmax || tmax < kappa*ipotFluct )
1807  {
1808    siga = tmax * (1.0-0.5*beta2) * step * twopi_mc2_rcl2
1809         * electronDensity / beta2 ;
1810
1811    // High velocity or negatively charged particle
1812    if( beta2 > 3.0*theBohrBeta2*zeff || charge < 0.0) {
1813      siga = std::sqrt( siga * chargeSquare ) ;
1814
1815    // Low velocity - additional ion charge fluctuations according to
1816    // Q.Yang et al., NIM B61(1991)149-155.
1817    } else {
1818      G4double chu = theIonChuFluctuationModel->TheValue(particle, material);
1819      G4double yang = theIonYangFluctuationModel->TheValue(particle, material);
1820      siga = std::sqrt( siga * (chargeSquare * chu + yang)) ;
1821    }
1822
1823    do {
1824        loss = G4RandGauss::shoot(meanLoss,siga);
1825    } while (loss < 0. || loss > 2.0*meanLoss);
1826    return loss;
1827  }
1828
1829  // Non Gaussian fluctuation
1830  static const G4double probLim = 0.01 ;
1831  static const G4double sumaLim = -std::log(probLim) ;
1832  static const G4double alim = 10.;
1833
1834  G4double suma,w1,w2,C,e0,lossc,w;
1835  G4double a1,a2,a3;
1836  G4int p1,p2,p3;
1837  G4int nb;
1838  G4double corrfac, na,alfa,rfac,namean,sa,alfa1,ea,sea;
1839  G4double dp3;
1840
1841  G4double f1Fluct     = material->GetIonisation()->GetF1fluct();
1842  G4double f2Fluct     = material->GetIonisation()->GetF2fluct();
1843  G4double e1Fluct     = material->GetIonisation()->GetEnergy1fluct();
1844  G4double e2Fluct     = material->GetIonisation()->GetEnergy2fluct();
1845  G4double e1LogFluct  = material->GetIonisation()->GetLogEnergy1fluct();
1846  G4double e2LogFluct  = material->GetIonisation()->GetLogEnergy2fluct();
1847  G4double rateFluct   = material->GetIonisation()->GetRateionexcfluct();
1848  G4double ipotLogFluct= material->GetIonisation()->GetLogMeanExcEnergy();
1849
1850  w1 = tmax/ipotFluct;
1851  w2 = std::log(2.*electron_mass_c2*tau2);
1852
1853  C = meanLoss*(1.-rateFluct)/(w2-ipotLogFluct-beta2);
1854
1855  a1 = C*f1Fluct*(w2-e1LogFluct-beta2)/e1Fluct;
1856  a2 = C*f2Fluct*(w2-e2LogFluct-beta2)/e2Fluct;
1857  a3 = rateFluct*meanLoss*(tmax-ipotFluct)/(ipotFluct*tmax*std::log(w1));
1858  if(a1 < 0.0) a1 = 0.0;
1859  if(a2 < 0.0) a2 = 0.0;
1860  if(a3 < 0.0) a3 = 0.0;
1861
1862  suma = a1+a2+a3;
1863
1864  loss = 0.;
1865
1866
1867  if(suma < sumaLim)             // very small Step
1868    {
1869      e0 = material->GetIonisation()->GetEnergy0fluct();
1870
1871      if(tmax == ipotFluct)
1872      {
1873        a3 = meanLoss/e0;
1874
1875        if(a3>alim)
1876        {
1877          siga=std::sqrt(a3) ;
1878          p3 = std::max(0,G4int(G4RandGauss::shoot(a3,siga)+0.5));
1879        }
1880        else
1881          p3 = G4Poisson(a3);
1882
1883        loss = p3*e0 ;
1884
1885        if(p3 > 0)
1886          loss += (1.-2.*G4UniformRand())*e0 ;
1887
1888      }
1889      else
1890      {
1891        tmax = tmax-ipotFluct+e0 ;
1892        a3 = meanLoss*(tmax-e0)/(tmax*e0*std::log(tmax/e0));
1893
1894        if(a3>alim)
1895        {
1896          siga=std::sqrt(a3) ;
1897          p3 = std::max(0,int(G4RandGauss::shoot(a3,siga)+0.5));
1898        }
1899        else
1900          p3 = G4Poisson(a3);
1901
1902        if(p3 > 0)
1903        {
1904          w = (tmax-e0)/tmax ;
1905          if(p3 > nmaxCont2)
1906          {
1907            dp3 = G4float(p3) ;
1908            corrfac = dp3/G4float(nmaxCont2) ;
1909            p3 = nmaxCont2 ;
1910          }
1911          else
1912            corrfac = 1. ;
1913
1914          for(G4int i=0; i<p3; i++) loss += 1./(1.-w*G4UniformRand()) ;
1915          loss *= e0*corrfac ;
1916        }
1917      }
1918    }
1919
1920  else                              // not so small Step
1921    {
1922      // excitation type 1
1923      if(a1>alim)
1924      {
1925        siga=std::sqrt(a1) ;
1926        p1 = std::max(0,G4int(G4RandGauss::shoot(a1,siga)+0.5));
1927      }
1928      else
1929       p1 = G4Poisson(a1);
1930
1931      // excitation type 2
1932      if(a2>alim)
1933      {
1934        siga=std::sqrt(a2) ;
1935        p2 = std::max(0,G4int(G4RandGauss::shoot(a2,siga)+0.5));
1936      }
1937      else
1938        p2 = G4Poisson(a2);
1939
1940      loss = p1*e1Fluct+p2*e2Fluct;
1941
1942      // smearing to avoid unphysical peaks
1943      if(p2 > 0)
1944        loss += (1.-2.*G4UniformRand())*e2Fluct;
1945      else if (loss>0.)
1946        loss += (1.-2.*G4UniformRand())*e1Fluct;
1947
1948      // ionisation .......................................
1949     if(a3 > 0.)
1950     {
1951      if(a3>alim)
1952      {
1953        siga=std::sqrt(a3) ;
1954        p3 = std::max(0,G4int(G4RandGauss::shoot(a3,siga)+0.5));
1955      }
1956      else
1957        p3 = G4Poisson(a3);
1958
1959      lossc = 0.;
1960      if(p3 > 0)
1961      {
1962        na = 0.;
1963        alfa = 1.;
1964        if (p3 > nmaxCont2)
1965        {
1966          dp3        = G4float(p3);
1967          rfac       = dp3/(G4float(nmaxCont2)+dp3);
1968          namean     = G4float(p3)*rfac;
1969          sa         = G4float(nmaxCont1)*rfac;
1970          na         = G4RandGauss::shoot(namean,sa);
1971          if (na > 0.)
1972          {
1973            alfa   = w1*G4float(nmaxCont2+p3)/
1974                    (w1*G4float(nmaxCont2)+G4float(p3));
1975            alfa1  = alfa*std::log(alfa)/(alfa-1.);
1976            ea     = na*ipotFluct*alfa1;
1977            sea    = ipotFluct*std::sqrt(na*(alfa-alfa1*alfa1));
1978            lossc += G4RandGauss::shoot(ea,sea);
1979          }
1980        }
1981
1982        nb = G4int(G4float(p3)-na);
1983        if (nb > 0)
1984        {
1985          w2 = alfa*ipotFluct;
1986          w  = (tmax-w2)/tmax;
1987          for (G4int k=0; k<nb; k++) lossc += w2/(1.-w*G4UniformRand());
1988        }
1989      }
1990      loss += lossc;
1991     }
1992    }
1993
1994  return loss ;
1995}
1996
1997//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1998
1999void G4hLowEnergyIonisation::SetCutForSecondaryPhotons(G4double cut)
2000{
2001  minGammaEnergy = cut;
2002}
2003
2004//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
2005
2006void G4hLowEnergyIonisation::SetCutForAugerElectrons(G4double cut)
2007{
2008  minElectronEnergy = cut;
2009}
2010
2011//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
2012
2013void G4hLowEnergyIonisation::ActivateAugerElectronProduction(G4bool val)
2014{
2015  deexcitationManager.ActivateAugerElectronProduction(val);
2016}
2017
2018//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
2019
2020void G4hLowEnergyIonisation::PrintInfoDefinition() const
2021{
2022  G4String comments = "  Knock-on electron cross sections . ";
2023  comments += "\n        Good description above the mean excitation energy.\n";
2024  comments += "        Delta ray energy sampled from  differential Xsection.";
2025
2026  G4cout << G4endl << GetProcessName() << ":  " << comments
2027         << "\n        PhysicsTables from " << LowestKineticEnergy / eV << " eV "
2028         << " to " << HighestKineticEnergy / TeV << " TeV "
2029         << " in " << TotBin << " bins."
2030 << "\n        Electronic stopping power model is  "
2031 << theProtonTable
2032         << "\n        from " << protonLowEnergy / keV << " keV "
2033         << " to " << protonHighEnergy / MeV << " MeV " << "." << G4endl ;
2034  G4cout << "\n        Parametrisation model for antiprotons is  "
2035         << theAntiProtonTable
2036         << "\n        from " << antiProtonLowEnergy / keV << " keV "
2037         << " to " << antiProtonHighEnergy / MeV << " MeV " << "." << G4endl ;
2038  if(theBarkas){
2039  G4cout << "        Parametrization of the Barkas effect is switched on."
2040         << G4endl ;
2041  }
2042  if(nStopping) {
2043  G4cout << "        Nuclear stopping power model is " << theNuclearTable
2044         << G4endl ;
2045  }
2046
2047  G4bool printHead = true;
2048
2049  const G4ProductionCutsTable* theCoupleTable=
2050        G4ProductionCutsTable::GetProductionCutsTable();
2051  size_t numOfCouples = theCoupleTable->GetTableSize();
2052
2053  // loop for materials
2054
2055  for (size_t j=0 ; j < numOfCouples; j++) {
2056
2057    const G4MaterialCutsCouple* couple = theCoupleTable->GetMaterialCutsCouple(j);
2058    const G4Material* material= couple->GetMaterial();
2059    G4double deltaCutNow = cutForDelta[(couple->GetIndex())] ;
2060    G4double eexc = material->GetIonisation()->GetMeanExcitationEnergy();
2061
2062    if(eexc > deltaCutNow) {
2063      if(printHead) {
2064        printHead = false ;
2065
2066        G4cout << "           material       min.delta energy(keV) " << G4endl;
2067        G4cout << G4endl;
2068      }
2069
2070      G4cout << std::setw(20) << material->GetName()
2071             << std::setw(15) << eexc/keV << G4endl;
2072    }
2073  }
2074}
Note: See TracBrowser for help on using the repository browser.