source: trunk/source/processes/electromagnetic/standard/src/G4PAIModel.cc@ 1344

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

update ti head

File size: 32.3 KB
RevLine 
[819]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//
[1340]26// $Id: G4PAIModel.cc,v 1.54 2010/11/04 17:30:32 vnivanch Exp $
27// GEANT4 tag $Name: emstand-V09-03-25 $
[1055]28//
29// -------------------------------------------------------------------
30//
31// GEANT4 Class
[819]32// File name: G4PAIModel.cc
33//
[1315]34// Author: Vladimir.Grichine@cern.ch on base of Vladimir Ivanchenko model interface
[819]35//
36// Creation date: 05.10.2003
37//
38// Modifications:
39//
40// 17.08.04 V.Grichine, bug fixed for Tkin<=0 in SampleSecondary
41// 16.08.04 V.Grichine, bug fixed in massRatio for DEDX, CrossSection, SampleSecondary
42// 08.04.05 Major optimisation of internal interfaces (V.Ivantchenko)
[1196]43// 26.07.09 Fixed logic to work with several materials (V.Ivantchenko)
[819]44//
45
46#include "G4Region.hh"
47#include "G4PhysicsLogVector.hh"
48#include "G4PhysicsFreeVector.hh"
49#include "G4PhysicsTable.hh"
50#include "G4ProductionCutsTable.hh"
51#include "G4MaterialCutsCouple.hh"
52#include "G4MaterialTable.hh"
53#include "G4SandiaTable.hh"
54#include "G4OrderedTable.hh"
55
56#include "G4PAIModel.hh"
57#include "Randomize.hh"
58#include "G4Electron.hh"
59#include "G4Positron.hh"
60#include "G4Poisson.hh"
61#include "G4Step.hh"
62#include "G4Material.hh"
63#include "G4DynamicParticle.hh"
64#include "G4ParticleDefinition.hh"
65#include "G4ParticleChangeForLoss.hh"
66
67////////////////////////////////////////////////////////////////////////
68
69using namespace std;
70
71G4PAIModel::G4PAIModel(const G4ParticleDefinition* p, const G4String& nam)
72 : G4VEmModel(nam),G4VEmFluctuationModel(nam),
73 fVerbose(0),
74 fLowestGamma(1.005),
75 fHighestGamma(10000.),
76 fTotBin(200),
77 fMeanNumber(20),
78 fParticle(0),
79 fHighKinEnergy(100.*TeV),
80 fTwoln10(2.0*log(10.0)),
81 fBg2lim(0.0169),
82 fTaulim(8.4146e-3)
[1340]83{
[819]84 fElectron = G4Electron::Electron();
85 fPositron = G4Positron::Positron();
86
87 fPAItransferTable = 0;
88 fPAIdEdxTable = 0;
89 fSandiaPhotoAbsCof = 0;
90 fdEdxVector = 0;
91 fLambdaVector = 0;
92 fdNdxCutVector = 0;
[1340]93 fParticleEnergyVector = 0;
94 fSandiaIntervalNumber = 0;
95 fMatIndex = 0;
96 fDeltaCutInKinEnergy = 0.0;
[819]97
[1340]98 if(p) { SetParticle(p); }
99 else { SetParticle(fElectron); }
100
[819]101 isInitialised = false;
102}
103
104////////////////////////////////////////////////////////////////////////////
105
106G4PAIModel::~G4PAIModel()
107{
108 // G4cout << "PAI: start destruction" << G4endl;
109 if(fParticleEnergyVector) delete fParticleEnergyVector;
110 if(fdEdxVector) delete fdEdxVector ;
111 if(fLambdaVector) delete fLambdaVector;
112 if(fdNdxCutVector) delete fdNdxCutVector;
113
114 if( fPAItransferTable )
115 {
116 fPAItransferTable->clearAndDestroy();
117 delete fPAItransferTable ;
118 }
119 if( fPAIdEdxTable )
120 {
121 fPAIdEdxTable->clearAndDestroy();
122 delete fPAIdEdxTable ;
123 }
124 if(fSandiaPhotoAbsCof)
125 {
126 for(G4int i=0;i<fSandiaIntervalNumber;i++)
127 {
128 delete[] fSandiaPhotoAbsCof[i];
129 }
130 delete[] fSandiaPhotoAbsCof;
131 }
132 //G4cout << "PAI: end destruction" << G4endl;
133}
134
135///////////////////////////////////////////////////////////////////////////////
136
137void G4PAIModel::SetParticle(const G4ParticleDefinition* p)
138{
[1340]139 if(fParticle == p) { return; }
[819]140 fParticle = p;
141 fMass = fParticle->GetPDGMass();
142 fSpin = fParticle->GetPDGSpin();
143 G4double q = fParticle->GetPDGCharge()/eplus;
144 fChargeSquare = q*q;
145 fLowKinEnergy = 0.2*MeV*fMass/proton_mass_c2;
146 fRatio = electron_mass_c2/fMass;
147 fQc = fMass/fRatio;
[1340]148 fLowestKineticEnergy = fMass*(fLowestGamma - 1.0);
149 fHighestKineticEnergy = fMass*(fHighestGamma - 1.0);
[819]150}
151
152////////////////////////////////////////////////////////////////////////////
153
154void G4PAIModel::Initialise(const G4ParticleDefinition* p,
155 const G4DataVector&)
156{
[1340]157 //G4cout<<"G4PAIModel::Initialise for "<<p->GetParticleName()<<G4endl;
158 if(isInitialised) { return; }
[819]159 isInitialised = true;
160
161 SetParticle(p);
162
163 fParticleEnergyVector = new G4PhysicsLogVector(fLowestKineticEnergy,
164 fHighestKineticEnergy,
165 fTotBin);
166
[1055]167 fParticleChange = GetParticleChangeForLoss();
[819]168
169 // Prepare initialization
170 const G4ProductionCutsTable* theCoupleTable =
171 G4ProductionCutsTable::GetProductionCutsTable();
172 const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
173 size_t numOfMat = G4Material::GetNumberOfMaterials();
174 size_t numRegions = fPAIRegionVector.size();
175
176 for(size_t iReg = 0; iReg < numRegions; ++iReg) // region loop
177 {
178 const G4Region* curReg = fPAIRegionVector[iReg];
179 for(size_t jMat = 0; jMat < numOfMat; ++jMat) // region material loop
180 {
181 fMaterial = (*theMaterialTable)[jMat];
182 fCutCouple = theCoupleTable->GetMaterialCutsCouple( fMaterial,
183 curReg->GetProductionCuts() );
[1055]184 //G4cout << "Reg <" <<curReg->GetName() << "> mat <"
185 // << fMaterial->GetName() << "> fCouple= "
[1196]186 // << fCutCouple<<" " << p->GetParticleName() <<G4endl;
[819]187 if( fCutCouple ) {
188 fMaterialCutsCoupleVector.push_back(fCutCouple);
189
[1196]190 fPAItransferTable = new G4PhysicsTable(fTotBin+1);
191 fPAIdEdxTable = new G4PhysicsTable(fTotBin+1);
192
[819]193 fDeltaCutInKinEnergy =
194 (*theCoupleTable->GetEnergyCutsVector(1))[fCutCouple->GetIndex()];
195
196 //ComputeSandiaPhotoAbsCof();
197 BuildPAIonisationTable();
198
199 fPAIxscBank.push_back(fPAItransferTable);
200 fPAIdEdxBank.push_back(fPAIdEdxTable);
201 fdEdxTable.push_back(fdEdxVector);
202
203 BuildLambdaVector();
204 fdNdxCutTable.push_back(fdNdxCutVector);
205 fLambdaTable.push_back(fLambdaVector);
206 }
207 }
208 }
209}
210
211//////////////////////////////////////////////////////////////////
212
[1055]213void G4PAIModel::InitialiseMe(const G4ParticleDefinition*)
214{}
215
216//////////////////////////////////////////////////////////////////
217
[819]218void G4PAIModel::ComputeSandiaPhotoAbsCof()
219{
[1340]220 G4int i, j;
221 const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
[819]222
223 G4SandiaTable thisMaterialSandiaTable(fMatIndex) ;
[1340]224 G4int numberOfElements =
225 (*theMaterialTable)[fMatIndex]->GetNumberOfElements();
226
[819]227 G4int* thisMaterialZ = new G4int[numberOfElements] ;
228
229 for(i=0;i<numberOfElements;i++)
230 {
231 thisMaterialZ[i] =
232 (G4int)(*theMaterialTable)[fMatIndex]->GetElement(i)->GetZ() ;
233 }
234 fSandiaIntervalNumber = thisMaterialSandiaTable.SandiaIntervals
235 (thisMaterialZ,numberOfElements) ;
236
237 fSandiaIntervalNumber = thisMaterialSandiaTable.SandiaMixing
238 ( thisMaterialZ ,
239 (*theMaterialTable)[fMatIndex]->GetFractionVector() ,
240 numberOfElements,fSandiaIntervalNumber) ;
241
242 fSandiaPhotoAbsCof = new G4double*[fSandiaIntervalNumber] ;
243
[1340]244 for(i=0; i<fSandiaIntervalNumber; i++)
245 {
246 fSandiaPhotoAbsCof[i] = new G4double[5];
247 }
[819]248
249 for( i = 0 ; i < fSandiaIntervalNumber ; i++ )
250 {
[1340]251 fSandiaPhotoAbsCof[i][0] = thisMaterialSandiaTable.GetPhotoAbsorpCof(i+1,0);
[819]252
253 for( j = 1; j < 5 ; j++ )
254 {
[1340]255 fSandiaPhotoAbsCof[i][j] = thisMaterialSandiaTable.GetPhotoAbsorpCof(i+1,j)*
[819]256 (*theMaterialTable)[fMatIndex]->GetDensity() ;
257 }
258 }
[1340]259 delete[] thisMaterialZ;
[819]260}
261
262////////////////////////////////////////////////////////////////////////////
263//
264// Build tables for the ionization energy loss
265// the tables are built for MATERIALS
266// *********
267
268void G4PAIModel::BuildPAIonisationTable()
269{
270 G4double LowEdgeEnergy , ionloss ;
271 G4double tau, Tmax, Tmin, Tkin, deltaLow, gamma, bg2 ;
272
273 fdEdxVector = new G4PhysicsLogVector( fLowestKineticEnergy,
274 fHighestKineticEnergy,
275 fTotBin);
276 G4SandiaTable* sandia = fMaterial->GetSandiaTable();
277
278 Tmin = sandia->GetSandiaCofForMaterialPAI(0,0)*keV;
279 deltaLow = 100.*eV; // 0.5*eV ;
280
[1196]281 for (G4int i = 0 ; i <= fTotBin ; i++) //The loop for the kinetic energy
[819]282 {
283 LowEdgeEnergy = fParticleEnergyVector->GetLowEdgeEnergy(i) ;
284 tau = LowEdgeEnergy/fMass ;
285 gamma = tau +1. ;
286 // G4cout<<"gamma = "<<gamma<<endl ;
287 bg2 = tau*( tau + 2. );
288 Tmax = MaxSecondaryEnergy(fParticle, LowEdgeEnergy);
289 // Tmax = std::min(fDeltaCutInKinEnergy, Tmax);
290 Tkin = Tmax ;
291
292 if ( Tmax < Tmin + deltaLow ) // low energy safety
293 Tkin = Tmin + deltaLow ;
294
295 fPAIySection.Initialize(fMaterial, Tkin, bg2);
296
297 // G4cout<<"ionloss = "<<ionloss*cm/keV<<" keV/cm"<<endl ;
298 // G4cout<<"n1 = "<<protonPAI.GetIntegralPAIxSection(1)*cm<<" 1/cm"<<endl ;
299 // G4cout<<"protonPAI.GetSplineSize() = "<<
300 // protonPAI.GetSplineSize()<<G4endl<<G4endl ;
301
302 G4int n = fPAIySection.GetSplineSize();
303 G4PhysicsFreeVector* transferVector = new G4PhysicsFreeVector(n) ;
304 G4PhysicsFreeVector* dEdxVector = new G4PhysicsFreeVector(n);
305
306 for( G4int k = 0 ; k < n; k++ )
307 {
308 transferVector->PutValue( k ,
309 fPAIySection.GetSplineEnergy(k+1),
310 fPAIySection.GetIntegralPAIySection(k+1) ) ;
311 dEdxVector->PutValue( k ,
312 fPAIySection.GetSplineEnergy(k+1),
313 fPAIySection.GetIntegralPAIdEdx(k+1) ) ;
314 }
315 ionloss = fPAIySection.GetMeanEnergyLoss() ; // total <dE/dx>
316
[1340]317 if ( ionloss < DBL_MIN) { ionloss = 0.0; }
[819]318 fdEdxVector->PutValue(i,ionloss) ;
319
320 fPAItransferTable->insertAt(i,transferVector) ;
321 fPAIdEdxTable->insertAt(i,dEdxVector) ;
322
323 } // end of Tkin loop
324}
325
326///////////////////////////////////////////////////////////////////////
327//
328// Build mean free path tables for the delta ray production process
329// tables are built for MATERIALS
330//
331
332void G4PAIModel::BuildLambdaVector()
333{
334 fLambdaVector = new G4PhysicsLogVector( fLowestKineticEnergy,
335 fHighestKineticEnergy,
336 fTotBin ) ;
337 fdNdxCutVector = new G4PhysicsLogVector( fLowestKineticEnergy,
338 fHighestKineticEnergy,
339 fTotBin ) ;
340 if(fVerbose > 1)
341 {
342 G4cout<<"PAIModel DeltaCutInKineticEnergyNow = "
343 <<fDeltaCutInKinEnergy/keV<<" keV"<<G4endl;
344 }
[1196]345 for (G4int i = 0 ; i <= fTotBin ; i++ )
[819]346 {
347 G4double dNdxCut = GetdNdxCut(i,fDeltaCutInKinEnergy) ;
[1196]348 //G4cout << "i= " << i << " x= " << dNdxCut << G4endl;
349 if(dNdxCut < 0.0) dNdxCut = 0.0;
350 // G4double lambda = dNdxCut <= DBL_MIN ? DBL_MAX: 1.0/dNdxCut ;
351 G4double lambda = DBL_MAX;
352 if(dNdxCut > 0.0) lambda = 1.0/dNdxCut;
[819]353
354 fLambdaVector->PutValue(i, lambda) ;
355 fdNdxCutVector->PutValue(i, dNdxCut) ;
356 }
357}
358
359///////////////////////////////////////////////////////////////////////
360//
361// Returns integral PAI cross section for energy transfers >= transferCut
362
363G4double
364G4PAIModel::GetdNdxCut( G4int iPlace, G4double transferCut)
365{
366 G4int iTransfer;
367 G4double x1, x2, y1, y2, dNdxCut;
368 // G4cout<<"iPlace = "<<iPlace<<"; "<<"transferCut = "<<transferCut<<G4endl;
369 // G4cout<<"size = "<<G4int((*fPAItransferTable)(iPlace)->GetVectorLength())
370 // <<G4endl;
371 for( iTransfer = 0 ;
372 iTransfer < G4int((*fPAItransferTable)(iPlace)->GetVectorLength()) ;
373 iTransfer++)
374 {
375 if(transferCut <= (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer))
376 {
377 break ;
378 }
379 }
380 if ( iTransfer >= G4int((*fPAItransferTable)(iPlace)->GetVectorLength()) )
381 {
382 iTransfer = (*fPAItransferTable)(iPlace)->GetVectorLength() - 1 ;
383 }
384 y1 = (*(*fPAItransferTable)(iPlace))(iTransfer-1) ;
385 y2 = (*(*fPAItransferTable)(iPlace))(iTransfer) ;
[1196]386 if(y1 < 0.0) y1 = 0.0;
387 if(y2 < 0.0) y2 = 0.0;
[819]388 // G4cout<<"y1 = "<<y1<<"; "<<"y2 = "<<y2<<G4endl;
389 x1 = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1) ;
390 x2 = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ;
391 // G4cout<<"x1 = "<<x1<<"; "<<"x2 = "<<x2<<G4endl;
392
393 if ( y1 == y2 ) dNdxCut = y2 ;
394 else
395 {
396 // if ( x1 == x2 ) dNdxCut = y1 + (y2 - y1)*G4UniformRand() ;
[1055]397 // if ( std::abs(x1-x2) <= eV ) dNdxCut = y1 + (y2 - y1)*G4UniformRand() ;
398 if ( std::abs(x1-x2) <= eV ) dNdxCut = y1 + (y2 - y1)*0.5 ;
[819]399 else dNdxCut = y1 + (transferCut - x1)*(y2 - y1)/(x2 - x1) ;
400 }
401 // G4cout<<""<<dNdxCut<<G4endl;
[1196]402 if(dNdxCut < 0.0) dNdxCut = 0.0;
[819]403 return dNdxCut ;
404}
405///////////////////////////////////////////////////////////////////////
406//
407// Returns integral dEdx for energy transfers >= transferCut
408
409G4double
410G4PAIModel::GetdEdxCut( G4int iPlace, G4double transferCut)
411{
412 G4int iTransfer;
413 G4double x1, x2, y1, y2, dEdxCut;
[1196]414 //G4cout<<"iPlace = "<<iPlace<<"; "<<"transferCut = "<<transferCut<<G4endl;
[819]415 // G4cout<<"size = "<<G4int((*fPAIdEdxTable)(iPlace)->GetVectorLength())
416 // <<G4endl;
417 for( iTransfer = 0 ;
418 iTransfer < G4int((*fPAIdEdxTable)(iPlace)->GetVectorLength()) ;
419 iTransfer++)
420 {
421 if(transferCut <= (*fPAIdEdxTable)(iPlace)->GetLowEdgeEnergy(iTransfer))
422 {
423 break ;
424 }
425 }
426 if ( iTransfer >= G4int((*fPAIdEdxTable)(iPlace)->GetVectorLength()) )
427 {
428 iTransfer = (*fPAIdEdxTable)(iPlace)->GetVectorLength() - 1 ;
429 }
430 y1 = (*(*fPAIdEdxTable)(iPlace))(iTransfer-1) ;
431 y2 = (*(*fPAIdEdxTable)(iPlace))(iTransfer) ;
[1196]432 if(y1 < 0.0) y1 = 0.0;
433 if(y2 < 0.0) y2 = 0.0;
434 //G4cout<<"y1 = "<<y1<<"; "<<"y2 = "<<y2<<G4endl;
[819]435 x1 = (*fPAIdEdxTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1) ;
436 x2 = (*fPAIdEdxTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ;
[1196]437 //G4cout<<"x1 = "<<x1<<"; "<<"x2 = "<<x2<<G4endl;
[819]438
439 if ( y1 == y2 ) dEdxCut = y2 ;
440 else
441 {
442 // if ( x1 == x2 ) dEdxCut = y1 + (y2 - y1)*G4UniformRand() ;
[1055]443 // if ( std::abs(x1-x2) <= eV ) dEdxCut = y1 + (y2 - y1)*G4UniformRand() ;
444 if ( std::abs(x1-x2) <= eV ) dEdxCut = y1 + (y2 - y1)*0.5 ;
[819]445 else dEdxCut = y1 + (transferCut - x1)*(y2 - y1)/(x2 - x1) ;
446 }
[1196]447 //G4cout<<""<<dEdxCut<<G4endl;
448 if(dEdxCut < 0.0) dEdxCut = 0.0;
[819]449 return dEdxCut ;
450}
451
452//////////////////////////////////////////////////////////////////////////////
453
[1055]454G4double G4PAIModel::ComputeDEDXPerVolume(const G4Material*,
455 const G4ParticleDefinition* p,
456 G4double kineticEnergy,
457 G4double cutEnergy)
[819]458{
459 G4int iTkin,iPlace;
[1055]460
461 //G4double cut = std::min(MaxSecondaryEnergy(p, kineticEnergy), cutEnergy);
462 G4double cut = cutEnergy;
463
[819]464 G4double massRatio = fMass/p->GetPDGMass();
465 G4double scaledTkin = kineticEnergy*massRatio;
466 G4double charge = p->GetPDGCharge();
[1055]467 G4double charge2 = charge*charge;
468 const G4MaterialCutsCouple* matCC = CurrentCouple();
[819]469
[1196]470 size_t jMat = 0;
471 for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat )
[819]472 {
473 if( matCC == fMaterialCutsCoupleVector[jMat] ) break;
474 }
[1196]475 //G4cout << "jMat= " << jMat
476 // << " jMax= " << fMaterialCutsCoupleVector.size()
477 // << " matCC: " << matCC;
478 //if(matCC) G4cout << " mat: " << matCC->GetMaterial()->GetName();
479 // G4cout << G4endl;
480 if(jMat == fMaterialCutsCoupleVector.size()) return 0.0;
[819]481
482 fPAIdEdxTable = fPAIdEdxBank[jMat];
483 fdEdxVector = fdEdxTable[jMat];
[1196]484 for(iTkin = 0 ; iTkin <= fTotBin ; iTkin++)
[819]485 {
486 if(scaledTkin < fParticleEnergyVector->GetLowEdgeEnergy(iTkin)) break ;
487 }
[1196]488 //G4cout << "E= " << scaledTkin << " iTkin= " << iTkin
489 // << " " << fdEdxVector->GetVectorLength()<<G4endl;
[819]490 iPlace = iTkin - 1;
491 if(iPlace < 0) iPlace = 0;
[1196]492 else if(iPlace >= fTotBin) iPlace = fTotBin-1;
[1055]493 G4double dEdx = charge2*( (*fdEdxVector)(iPlace) - GetdEdxCut(iPlace,cut) );
[819]494 if( dEdx < 0.) dEdx = 0.;
495 return dEdx;
496}
497
498/////////////////////////////////////////////////////////////////////////
499
[1055]500G4double G4PAIModel::CrossSectionPerVolume( const G4Material*,
501 const G4ParticleDefinition* p,
502 G4double kineticEnergy,
503 G4double cutEnergy,
504 G4double maxEnergy )
[819]505{
506 G4int iTkin,iPlace;
[1055]507 G4double tmax = std::min(MaxSecondaryEnergy(p, kineticEnergy), maxEnergy);
508 if(tmax <= cutEnergy) return 0.0;
[819]509 G4double massRatio = fMass/p->GetPDGMass();
510 G4double scaledTkin = kineticEnergy*massRatio;
511 G4double charge = p->GetPDGCharge();
512 G4double charge2 = charge*charge, cross, cross1, cross2;
[1055]513 const G4MaterialCutsCouple* matCC = CurrentCouple();
[819]514
[1196]515 size_t jMat = 0;
516 for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat )
[819]517 {
518 if( matCC == fMaterialCutsCoupleVector[jMat] ) break;
519 }
[1196]520 if(jMat == fMaterialCutsCoupleVector.size()) return 0.0;
[819]521
522 fPAItransferTable = fPAIxscBank[jMat];
523
[1196]524 for(iTkin = 0 ; iTkin <= fTotBin ; iTkin++)
[819]525 {
526 if(scaledTkin < fParticleEnergyVector->GetLowEdgeEnergy(iTkin)) break ;
527 }
528 iPlace = iTkin - 1;
529 if(iPlace < 0) iPlace = 0;
[1196]530 else if(iPlace >= fTotBin) iPlace = fTotBin-1;
[819]531
[1196]532 //G4cout<<"iPlace = "<<iPlace<<"; tmax = "
[819]533 // <<tmax<<"; cutEnergy = "<<cutEnergy<<G4endl;
534 cross1 = GetdNdxCut(iPlace,tmax) ;
[1196]535 //G4cout<<"cross1 = "<<cross1<<G4endl;
[819]536 cross2 = GetdNdxCut(iPlace,cutEnergy) ;
[1196]537 //G4cout<<"cross2 = "<<cross2<<G4endl;
[819]538 cross = (cross2-cross1)*charge2;
[1196]539 //G4cout<<"cross = "<<cross<<G4endl;
540 if( cross < DBL_MIN) cross = 0.0;
[819]541 // if( cross2 < DBL_MIN) cross2 = DBL_MIN;
542
543 // return cross2;
544 return cross;
545}
546
547///////////////////////////////////////////////////////////////////////////
548//
549// It is analog of PostStepDoIt in terms of secondary electron.
550//
551
552void G4PAIModel::SampleSecondaries(std::vector<G4DynamicParticle*>* vdp,
553 const G4MaterialCutsCouple* matCC,
554 const G4DynamicParticle* dp,
555 G4double tmin,
556 G4double maxEnergy)
557{
[1196]558 size_t jMat = 0;
559 for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat )
[819]560 {
561 if( matCC == fMaterialCutsCoupleVector[jMat] ) break;
562 }
[1196]563 if(jMat == fMaterialCutsCoupleVector.size()) return;
[819]564
565 fPAItransferTable = fPAIxscBank[jMat];
566 fdNdxCutVector = fdNdxCutTable[jMat];
567
568 G4double tmax = std::min(MaxSecondaryKinEnergy(dp), maxEnergy);
569 if( tmin >= tmax && fVerbose > 0)
570 {
571 G4cout<<"G4PAIModel::SampleSecondary: tmin >= tmax "<<G4endl;
572 }
573 G4ThreeVector direction= dp->GetMomentumDirection();
574 G4double particleMass = dp->GetMass();
575 G4double kineticEnergy = dp->GetKineticEnergy();
576
577 G4double massRatio = fMass/particleMass;
578 G4double scaledTkin = kineticEnergy*massRatio;
579 G4double totalEnergy = kineticEnergy + particleMass;
580 G4double pSquare = kineticEnergy*(totalEnergy+particleMass);
581
582 G4double deltaTkin = GetPostStepTransfer(scaledTkin);
583
584 // G4cout<<"G4PAIModel::SampleSecondaries; deltaKIn = "<<deltaTkin/keV<<" keV "<<G4endl;
585
586 if( deltaTkin <= 0. && fVerbose > 0)
587 {
588 G4cout<<"G4PAIModel::SampleSecondary e- deltaTkin = "<<deltaTkin<<G4endl;
589 }
590 if( deltaTkin <= 0.) return;
591
592 if( deltaTkin > tmax) deltaTkin = tmax;
593
594 G4double deltaTotalMomentum = sqrt(deltaTkin*(deltaTkin + 2. * electron_mass_c2 ));
595 G4double totalMomentum = sqrt(pSquare);
596 G4double costheta = deltaTkin*(totalEnergy + electron_mass_c2)
597 /(deltaTotalMomentum * totalMomentum);
598
599 if( costheta > 0.99999 ) costheta = 0.99999;
600 G4double sintheta = 0.0;
601 G4double sin2 = 1. - costheta*costheta;
602 if( sin2 > 0.) sintheta = sqrt(sin2);
603
604 // direction of the delta electron
605 G4double phi = twopi*G4UniformRand();
606 G4double dirx = sintheta*cos(phi), diry = sintheta*sin(phi), dirz = costheta;
607
608 G4ThreeVector deltaDirection(dirx,diry,dirz);
609 deltaDirection.rotateUz(direction);
610 deltaDirection.unit();
611
612 // primary change
613 kineticEnergy -= deltaTkin;
614 G4ThreeVector dir = totalMomentum*direction - deltaTotalMomentum*deltaDirection;
615 direction = dir.unit();
616 fParticleChange->SetProposedKineticEnergy(kineticEnergy);
617 fParticleChange->SetProposedMomentumDirection(direction);
618
619 // create G4DynamicParticle object for e- delta ray
620 G4DynamicParticle* deltaRay = new G4DynamicParticle;
621 deltaRay->SetDefinition(G4Electron::Electron());
622 deltaRay->SetKineticEnergy( deltaTkin ); // !!! trick for last steps /2.0 ???
623 deltaRay->SetMomentumDirection(deltaDirection);
624
625 vdp->push_back(deltaRay);
626}
627
628
629///////////////////////////////////////////////////////////////////////
630//
631// Returns post step PAI energy transfer > cut electron energy according to passed
632// scaled kinetic energy of particle
633
634G4double
635G4PAIModel::GetPostStepTransfer( G4double scaledTkin )
636{
637 // G4cout<<"G4PAIModel::GetPostStepTransfer"<<G4endl ;
638
639 G4int iTkin, iTransfer, iPlace ;
640 G4double transfer = 0.0, position, dNdxCut1, dNdxCut2, E1, E2, W1, W2, W ;
641
[1196]642 for(iTkin=0;iTkin<=fTotBin;iTkin++)
[819]643 {
644 if(scaledTkin < fParticleEnergyVector->GetLowEdgeEnergy(iTkin)) break ;
645 }
646 iPlace = iTkin - 1 ;
647 // G4cout<<"from search, iPlace = "<<iPlace<<G4endl ;
648 if(iPlace < 0) iPlace = 0;
[1196]649 else if(iPlace >= fTotBin) iPlace = fTotBin-1;
[819]650 dNdxCut1 = (*fdNdxCutVector)(iPlace) ;
651 // G4cout<<"dNdxCut1 = "<<dNdxCut1<<G4endl ;
652
653
654 if(iTkin == fTotBin) // Fermi plato, try from left
655 {
656 position = dNdxCut1*G4UniformRand() ;
657
658 for( iTransfer = 0;
659 iTransfer < G4int((*fPAItransferTable)(iPlace)->GetVectorLength()); iTransfer++ )
660 {
661 if(position >= (*(*fPAItransferTable)(iPlace))(iTransfer)) break ;
662 }
663 transfer = GetEnergyTransfer(iPlace,position,iTransfer);
664 }
665 else
666 {
667 dNdxCut2 = (*fdNdxCutVector)(iPlace+1) ;
668 // G4cout<<"dNdxCut2 = "<<dNdxCut2<<G4endl ;
669 if(iTkin == 0) // Tkin is too small, trying from right only
670 {
671 position = dNdxCut2*G4UniformRand() ;
672
673 for( iTransfer = 0;
674 iTransfer < G4int((*fPAItransferTable)(iPlace+1)->GetVectorLength()); iTransfer++ )
675 {
676 if(position >= (*(*fPAItransferTable)(iPlace+1))(iTransfer)) break ;
677 }
678 transfer = GetEnergyTransfer(iPlace+1,position,iTransfer);
679 }
680 else // general case: Tkin between two vectors of the material
681 {
682 E1 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin - 1) ;
683 E2 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin) ;
684 W = 1.0/(E2 - E1) ;
685 W1 = (E2 - scaledTkin)*W ;
686 W2 = (scaledTkin - E1)*W ;
687
688 position = ( dNdxCut1*W1 + dNdxCut2*W2 )*G4UniformRand() ;
689
690 // G4cout<<position<<"\t" ;
691
692 G4int iTrMax1, iTrMax2, iTrMax;
693
694 iTrMax1 = G4int((*fPAItransferTable)(iPlace)->GetVectorLength());
695 iTrMax2 = G4int((*fPAItransferTable)(iPlace+1)->GetVectorLength());
696
697 if (iTrMax1 >= iTrMax2) iTrMax = iTrMax2;
698 else iTrMax = iTrMax1;
699
700
701 for( iTransfer = 0; iTransfer < iTrMax; iTransfer++ )
702 {
703 if( position >=
704 ( (*(*fPAItransferTable)(iPlace))(iTransfer)*W1 +
705 (*(*fPAItransferTable)(iPlace+1))(iTransfer)*W2) ) break ;
706 }
707 transfer = GetEnergyTransfer(iPlace,position,iTransfer);
708 }
709 }
710 // G4cout<<"PAImodel PostStepTransfer = "<<transfer/keV<<" keV"<<G4endl ;
711 if(transfer < 0.0 ) transfer = 0.0 ;
712 // if(transfer < DBL_MIN ) transfer = DBL_MIN;
713
714 return transfer ;
715}
716
717///////////////////////////////////////////////////////////////////////
718//
719// Returns random PAI energy transfer according to passed
720// indexes of particle kinetic
721
722G4double
723G4PAIModel::GetEnergyTransfer( G4int iPlace, G4double position, G4int iTransfer )
724{
725 G4int iTransferMax;
726 G4double x1, x2, y1, y2, energyTransfer;
727
728 if(iTransfer == 0)
729 {
730 energyTransfer = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer);
731 }
732 else
733 {
734 iTransferMax = G4int((*fPAItransferTable)(iPlace)->GetVectorLength());
735
736 if ( iTransfer >= iTransferMax ) iTransfer = iTransferMax - 1;
737
738 y1 = (*(*fPAItransferTable)(iPlace))(iTransfer-1);
739 y2 = (*(*fPAItransferTable)(iPlace))(iTransfer);
740
741 x1 = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1);
742 x2 = (*fPAItransferTable)(iPlace)->GetLowEdgeEnergy(iTransfer);
743
744 if ( x1 == x2 ) energyTransfer = x2;
745 else
746 {
747 if ( y1 == y2 ) energyTransfer = x1 + (x2 - x1)*G4UniformRand();
748 else
749 {
750 energyTransfer = x1 + (position - y1)*(x2 - x1)/(y2 - y1);
751 }
752 }
753 }
754 return energyTransfer;
755}
756
757///////////////////////////////////////////////////////////////////////
758
759G4double G4PAIModel::SampleFluctuations( const G4Material* material,
760 const G4DynamicParticle* aParticle,
761 G4double&,
762 G4double& step,
763 G4double&)
764{
[1196]765 size_t jMat = 0;
766 for(;jMat < fMaterialCutsCoupleVector.size(); ++jMat )
[819]767 {
768 if( material == fMaterialCutsCoupleVector[jMat]->GetMaterial() ) break;
769 }
[1196]770 if(jMat == fMaterialCutsCoupleVector.size()) return 0.0;
[819]771
772 fPAItransferTable = fPAIxscBank[jMat];
773 fdNdxCutVector = fdNdxCutTable[jMat];
774
[1196]775 G4int iTkin, iTransfer, iPlace;
[819]776 G4long numOfCollisions=0;
777
[1196]778 //G4cout<<"G4PAIModel::SampleFluctuations"<<G4endl ;
779 //G4cout<<"in: "<<fMaterialCutsCoupleVector[jMat]->GetMaterial()->GetName()<<G4endl;
[819]780 G4double loss = 0.0, charge2 ;
781 G4double stepSum = 0., stepDelta, lambda, omega;
782 G4double position, E1, E2, W1, W2, W, dNdxCut1, dNdxCut2, meanNumber;
783 G4bool numb = true;
784 G4double Tkin = aParticle->GetKineticEnergy() ;
785 G4double MassRatio = fMass/aParticle->GetDefinition()->GetPDGMass() ;
786 G4double charge = aParticle->GetDefinition()->GetPDGCharge() ;
787 charge2 = charge*charge ;
788 G4double TkinScaled = Tkin*MassRatio ;
789
[1196]790 for(iTkin=0;iTkin<=fTotBin;iTkin++)
[819]791 {
792 if(TkinScaled < fParticleEnergyVector->GetLowEdgeEnergy(iTkin)) break ;
793 }
794 iPlace = iTkin - 1 ;
795 if(iPlace < 0) iPlace = 0;
[1196]796 else if(iPlace >= fTotBin) iPlace = fTotBin - 1;
797 //G4cout<<"from search, iPlace = "<<iPlace<<G4endl ;
[819]798 dNdxCut1 = (*fdNdxCutVector)(iPlace) ;
[1196]799 //G4cout<<"dNdxCut1 = "<<dNdxCut1<<G4endl ;
[819]800
801 if(iTkin == fTotBin) // Fermi plato, try from left
802 {
803 meanNumber =((*(*fPAItransferTable)(iPlace))(0)-dNdxCut1)*step*charge2;
804 if(meanNumber < 0.) meanNumber = 0. ;
805 // numOfCollisions = RandPoisson::shoot(meanNumber) ;
806 // numOfCollisions = G4Poisson(meanNumber) ;
807 if( meanNumber > 0.) lambda = step/meanNumber;
808 else lambda = DBL_MAX;
809 while(numb)
810 {
811 stepDelta = CLHEP::RandExponential::shoot(lambda);
812 stepSum += stepDelta;
813 if(stepSum >= step) break;
814 numOfCollisions++;
815 }
[1196]816 //G4cout<<"##1 numOfCollisions = "<<numOfCollisions<<G4endl ;
[819]817
818 while(numOfCollisions)
819 {
820 position = dNdxCut1+
821 ((*(*fPAItransferTable)(iPlace))(0)-dNdxCut1)*G4UniformRand() ;
822
823 for( iTransfer = 0;
824 iTransfer < G4int((*fPAItransferTable)(iPlace)->GetVectorLength()); iTransfer++ )
825 {
826 if(position >= (*(*fPAItransferTable)(iPlace))(iTransfer)) break ;
827 }
828 omega = GetEnergyTransfer(iPlace,position,iTransfer);
[1196]829 //G4cout<<"G4PAIModel::SampleFluctuations, omega = "<<omega/keV<<" keV; "<<"\t";
[819]830 loss += omega;
831 numOfCollisions-- ;
832 }
833 }
834 else
835 {
836 dNdxCut2 = (*fdNdxCutVector)(iPlace+1) ;
[1196]837 //G4cout<<"dNdxCut2 = "<<dNdxCut2<< " iTkin= "<<iTkin<<" iPlace= "<<iPlace<<G4endl;
[819]838
839 if(iTkin == 0) // Tkin is too small, trying from right only
840 {
841 meanNumber =((*(*fPAItransferTable)(iPlace+1))(0)-dNdxCut2)*step*charge2;
842 if( meanNumber < 0. ) meanNumber = 0. ;
843 // numOfCollisions = CLHEP::RandPoisson::shoot(meanNumber) ;
844 // numOfCollisions = G4Poisson(meanNumber) ;
[1196]845 if( meanNumber > 0.) lambda = step/meanNumber;
846 else lambda = DBL_MAX;
847 while(numb)
848 {
849 stepDelta = CLHEP::RandExponential::shoot(lambda);
850 stepSum += stepDelta;
851 if(stepSum >= step) break;
852 numOfCollisions++;
853 }
[819]854
[1196]855 //G4cout<<"##2 numOfCollisions = "<<numOfCollisions<<G4endl ;
[819]856
857 while(numOfCollisions)
858 {
859 position = dNdxCut2+
860 ((*(*fPAItransferTable)(iPlace+1))(0)-dNdxCut2)*G4UniformRand();
861
862 for( iTransfer = 0;
863 iTransfer < G4int((*fPAItransferTable)(iPlace+1)->GetVectorLength()); iTransfer++ )
864 {
865 if(position >= (*(*fPAItransferTable)(iPlace+1))(iTransfer)) break ;
866 }
867 omega = GetEnergyTransfer(iPlace,position,iTransfer);
[1196]868 //G4cout<<omega/keV<<"\t";
[819]869 loss += omega;
870 numOfCollisions-- ;
871 }
872 }
873 else // general case: Tkin between two vectors of the material
874 {
875 E1 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin - 1) ;
876 E2 = fParticleEnergyVector->GetLowEdgeEnergy(iTkin) ;
877 W = 1.0/(E2 - E1) ;
878 W1 = (E2 - TkinScaled)*W ;
879 W2 = (TkinScaled - E1)*W ;
880
[1196]881 //G4cout << fPAItransferTable->size() << G4endl;
882 //G4cout<<"(*(*fPAItransferTable)(iPlace))(0) = "<<
[819]883 // (*(*fPAItransferTable)(iPlace))(0)<<G4endl ;
[1196]884 //G4cout<<"(*(*fPAItransferTable)(iPlace+1))(0) = "<<
[819]885 // (*(*fPAItransferTable)(iPlace+1))(0)<<G4endl ;
886
887 meanNumber=( ((*(*fPAItransferTable)(iPlace))(0)-dNdxCut1)*W1 +
888 ((*(*fPAItransferTable)(iPlace+1))(0)-dNdxCut2)*W2 )*step*charge2;
889 if(meanNumber<0.0) meanNumber = 0.0;
890 // numOfCollisions = RandPoisson::shoot(meanNumber) ;
891 // numOfCollisions = G4Poisson(meanNumber) ;
[1196]892 if( meanNumber > 0.) lambda = step/meanNumber;
893 else lambda = DBL_MAX;
894 while(numb)
895 {
896 stepDelta = CLHEP::RandExponential::shoot(lambda);
897 stepSum += stepDelta;
898 if(stepSum >= step) break;
899 numOfCollisions++;
900 }
[819]901
[1196]902 //G4cout<<"##3 numOfCollisions = "<<numOfCollisions<<endl ;
[819]903
904 while(numOfCollisions)
905 {
906 position = dNdxCut1*W1 + dNdxCut2*W2 +
907 ( ( (*(*fPAItransferTable)(iPlace))(0)-dNdxCut1 )*W1 +
908 dNdxCut2+
909 ( (*(*fPAItransferTable)(iPlace+1))(0)-dNdxCut2 )*W2 )*G4UniformRand();
910
911 // G4cout<<position<<"\t" ;
912
913 for( iTransfer = 0;
914 iTransfer < G4int((*fPAItransferTable)(iPlace)->GetVectorLength()); iTransfer++ )
915 {
916 if( position >=
917 ( (*(*fPAItransferTable)(iPlace))(iTransfer)*W1 +
918 (*(*fPAItransferTable)(iPlace+1))(iTransfer)*W2) )
919 {
920 break ;
921 }
922 }
923 omega = GetEnergyTransfer(iPlace,position,iTransfer);
924 // G4cout<<omega/keV<<"\t";
925 loss += omega;
926 numOfCollisions-- ;
927 }
928 }
929 }
[1196]930 //G4cout<<"PAIModel AlongStepLoss = "<<loss/keV<<" keV, on step = "
[819]931 // <<step/mm<<" mm"<<G4endl ;
932 if(loss > Tkin) loss=Tkin;
933 if(loss < 0. ) loss = 0.;
934 return loss ;
935
936}
937
938//////////////////////////////////////////////////////////////////////
939//
940// Returns the statistical estimation of the energy loss distribution variance
941//
942
943
944G4double G4PAIModel::Dispersion( const G4Material* material,
945 const G4DynamicParticle* aParticle,
946 G4double& tmax,
947 G4double& step )
948{
949 G4double loss, sumLoss=0., sumLoss2=0., sigma2, meanLoss=0.;
950 for(G4int i = 0 ; i < fMeanNumber; i++)
951 {
952 loss = SampleFluctuations(material,aParticle,tmax,step,meanLoss);
953 sumLoss += loss;
954 sumLoss2 += loss*loss;
955 }
956 meanLoss = sumLoss/fMeanNumber;
957 sigma2 = meanLoss*meanLoss + (sumLoss2-2*sumLoss*meanLoss)/fMeanNumber;
958 return sigma2;
959}
960
[1055]961/////////////////////////////////////////////////////////////////////
[819]962
[1055]963G4double G4PAIModel::MaxSecondaryEnergy( const G4ParticleDefinition* p,
964 G4double kinEnergy)
965{
966 G4double tmax = kinEnergy;
967 if(p == fElectron) tmax *= 0.5;
968 else if(p != fPositron) {
969 G4double mass = p->GetPDGMass();
970 G4double ratio= electron_mass_c2/mass;
971 G4double gamma= kinEnergy/mass + 1.0;
972 tmax = 2.0*electron_mass_c2*(gamma*gamma - 1.) /
973 (1. + 2.0*gamma*ratio + ratio*ratio);
974 }
975 return tmax;
976}
977
978///////////////////////////////////////////////////////////////
979
980void G4PAIModel::DefineForRegion(const G4Region* r)
981{
982 fPAIRegionVector.push_back(r);
983}
984
[819]985//
986//
987/////////////////////////////////////////////////
988
989
990
991
992
993
Note: See TracBrowser for help on using the repository browser.