source: trunk/source/processes/electromagnetic/xrays/src/G4VXTRenergyLoss.cc@ 1347

Last change on this file since 1347 was 1337, checked in by garnier, 15 years ago

tag geant4.9.4 beta 1 + modifs locales

File size: 45.8 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// $Id: G4VXTRenergyLoss.cc,v 1.45 2010/06/16 15:34:15 gcosmo Exp $
28// GEANT4 tag $Name: geant4-09-04-beta-01 $
29//
30// History:
31// 2001-2002 R&D by V.Grichine
32// 19.06.03 V. Grichine, modifications in BuildTable for the integration
33// in respect of angle: range is increased, accuracy is
34// improved
35// 28.07.05, P.Gumplinger add G4ProcessType to constructor
36// 28.09.07, V.Ivanchenko general cleanup without change of algorithms
37//
38
39#include "G4Timer.hh"
40
41#include "G4VXTRenergyLoss.hh"
42#include "G4Poisson.hh"
43#include "G4MaterialTable.hh"
44#include "G4VDiscreteProcess.hh"
45#include "G4VParticleChange.hh"
46#include "G4VSolid.hh"
47
48#include "G4RotationMatrix.hh"
49#include "G4ThreeVector.hh"
50#include "G4AffineTransform.hh"
51#include "G4SandiaTable.hh"
52
53#include "G4PhysicsVector.hh"
54#include "G4PhysicsFreeVector.hh"
55#include "G4PhysicsLinearVector.hh"
56
57////////////////////////////////////////////////////////////////////////////
58//
59// Constructor, destructor
60
61G4VXTRenergyLoss::G4VXTRenergyLoss(G4LogicalVolume *anEnvelope,
62 G4Material* foilMat,G4Material* gasMat,
63 G4double a, G4double b,
64 G4int n,const G4String& processName,
65 G4ProcessType type) :
66 G4VDiscreteProcess(processName, type),
67 fGammaCutInKineticEnergy(0),
68 fGammaTkinCut(0),
69 fAngleDistrTable(0),
70 fEnergyDistrTable(0),
71 fPlatePhotoAbsCof(0),
72 fGasPhotoAbsCof(0),
73 fAngleForEnergyTable(0)
74{
75 verboseLevel = 1;
76
77 // Initialization of local constants
78 fTheMinEnergyTR = 1.0*keV;
79 fTheMaxEnergyTR = 100.0*keV;
80 fTheMaxAngle = 1.0e-3;
81 fTheMinAngle = 5.0e-6;
82 fBinTR = 50;
83
84 fMinProtonTkin = 100.0*GeV;
85 fMaxProtonTkin = 100.0*TeV;
86 fTotBin = 50;
87
88 // Proton energy vector initialization
89
90 fProtonEnergyVector = new G4PhysicsLogVector(fMinProtonTkin,
91 fMaxProtonTkin,
92 fTotBin );
93
94 fXTREnergyVector = new G4PhysicsLogVector(fTheMinEnergyTR,
95 fTheMaxEnergyTR,
96 fBinTR );
97
98 fPlasmaCof = 4.0*pi*fine_structure_const*hbarc*hbarc*hbarc/electron_mass_c2;
99
100 fCofTR = fine_structure_const/pi;
101
102 fEnvelope = anEnvelope ;
103
104 fPlateNumber = n ;
105 if(verboseLevel > 0)
106 G4cout<<"### G4VXTRenergyLoss: the number of TR radiator plates = "
107 <<fPlateNumber<<G4endl ;
108 if(fPlateNumber == 0)
109 {
110 G4Exception("G4VXTRenergyLoss: No plates in X-ray TR radiator") ;
111 }
112 // default is XTR dEdx, not flux after radiator
113
114 fExitFlux = false;
115 fAngleRadDistr = false;
116 fCompton = false;
117
118 fLambda = DBL_MAX;
119 // Mean thicknesses of plates and gas gaps
120
121 fPlateThick = a ;
122 fGasThick = b ;
123 fTotalDist = fPlateNumber*(fPlateThick+fGasThick) ;
124 if(verboseLevel > 0)
125 G4cout<<"total radiator thickness = "<<fTotalDist/cm<<" cm"<<G4endl ;
126
127 // index of plate material
128 fMatIndex1 = foilMat->GetIndex() ;
129 if(verboseLevel > 0)
130 G4cout<<"plate material = "<<foilMat->GetName()<<G4endl ;
131
132 // index of gas material
133 fMatIndex2 = gasMat->GetIndex() ;
134 if(verboseLevel > 0)
135 G4cout<<"gas material = "<<gasMat->GetName()<<G4endl ;
136
137 // plasma energy squared for plate material
138
139 fSigma1 = fPlasmaCof*foilMat->GetElectronDensity() ;
140 // fSigma1 = (20.9*eV)*(20.9*eV) ;
141 if(verboseLevel > 0)
142 G4cout<<"plate plasma energy = "<<std::sqrt(fSigma1)/eV<<" eV"<<G4endl ;
143
144 // plasma energy squared for gas material
145
146 fSigma2 = fPlasmaCof*gasMat->GetElectronDensity() ;
147 if(verboseLevel > 0)
148 G4cout<<"gas plasma energy = "<<std::sqrt(fSigma2)/eV<<" eV"<<G4endl ;
149
150 // Compute cofs for preparation of linear photo absorption
151
152 ComputePlatePhotoAbsCof() ;
153 ComputeGasPhotoAbsCof() ;
154
155 pParticleChange = &fParticleChange;
156
157}
158
159///////////////////////////////////////////////////////////////////////////
160
161G4VXTRenergyLoss::~G4VXTRenergyLoss()
162{
163 if(fEnvelope) delete fEnvelope;
164}
165
166///////////////////////////////////////////////////////////////////////////////
167//
168// Returns condition for application of the model depending on particle type
169
170
171G4bool G4VXTRenergyLoss::IsApplicable(const G4ParticleDefinition& particle)
172{
173 return ( particle.GetPDGCharge() != 0.0 ) ;
174}
175
176/////////////////////////////////////////////////////////////////////////////////
177//
178// Calculate step size for XTR process inside raaditor
179
180G4double G4VXTRenergyLoss::GetMeanFreePath(const G4Track& aTrack,
181 G4double, // previousStepSize,
182 G4ForceCondition* condition)
183{
184 G4int iTkin, iPlace;
185 G4double lambda, sigma, kinEnergy, mass, gamma;
186 G4double charge, chargeSq, massRatio, TkinScaled;
187 G4double E1,E2,W,W1,W2;
188
189 *condition = NotForced;
190
191 if( aTrack.GetVolume()->GetLogicalVolume() != fEnvelope ) lambda = DBL_MAX;
192 else
193 {
194 const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
195 kinEnergy = aParticle->GetKineticEnergy();
196 mass = aParticle->GetDefinition()->GetPDGMass();
197 gamma = 1.0 + kinEnergy/mass;
198 if(verboseLevel > 1)
199 {
200 G4cout<<" gamma = "<<gamma<<"; fGamma = "<<fGamma<<G4endl;
201 }
202
203 if ( std::fabs( gamma - fGamma ) < 0.05*gamma ) lambda = fLambda;
204 else
205 {
206 charge = aParticle->GetDefinition()->GetPDGCharge();
207 chargeSq = charge*charge;
208 massRatio = proton_mass_c2/mass;
209 TkinScaled = kinEnergy*massRatio;
210
211 for(iTkin = 0; iTkin < fTotBin; iTkin++)
212 {
213 if( TkinScaled < fProtonEnergyVector->GetLowEdgeEnergy(iTkin)) break ;
214 }
215 iPlace = iTkin - 1 ;
216
217 if(iTkin == 0) lambda = DBL_MAX; // Tkin is too small, neglect of TR photon generation
218 else // general case: Tkin between two vectors of the material
219 {
220 if(iTkin == fTotBin)
221 {
222 sigma = (*(*fEnergyDistrTable)(iPlace))(0)*chargeSq;
223 }
224 else
225 {
226 E1 = fProtonEnergyVector->GetLowEdgeEnergy(iTkin - 1) ;
227 E2 = fProtonEnergyVector->GetLowEdgeEnergy(iTkin) ;
228 W = 1.0/(E2 - E1) ;
229 W1 = (E2 - TkinScaled)*W ;
230 W2 = (TkinScaled - E1)*W ;
231 sigma = ( (*(*fEnergyDistrTable)(iPlace ))(0)*W1 +
232 (*(*fEnergyDistrTable)(iPlace+1))(0)*W2 )*chargeSq;
233
234 }
235 if (sigma < DBL_MIN) lambda = DBL_MAX;
236 else lambda = 1./sigma;
237 fLambda = lambda;
238 fGamma = gamma;
239 if(verboseLevel > 1)
240 {
241 G4cout<<" lambda = "<<lambda/mm<<" mm"<<G4endl;
242 }
243 }
244 }
245 }
246 return lambda;
247}
248
249//////////////////////////////////////////////////////////////////////////
250//
251// Interface for build table from physics list
252
253void G4VXTRenergyLoss::BuildPhysicsTable(const G4ParticleDefinition& pd)
254{
255 if(pd.GetPDGCharge() == 0.)
256 {
257 G4Exception("G4VXTRenergyLoss::BuildPhysicsTable", "Notification", JustWarning,
258 "XTR initialisation for neutral particle ?!" );
259 }
260 BuildTable();
261 if (fAngleRadDistr)
262 {
263 if(verboseLevel > 0)
264 G4cout<<"Build angle distribution according the transparent regular radiator"
265 <<G4endl;
266 BuildAngleTable();
267 }
268}
269
270
271//////////////////////////////////////////////////////////////////////////
272//
273// Build integral energy distribution of XTR photons
274
275void G4VXTRenergyLoss::BuildTable()
276{
277 G4int iTkin, iTR, iPlace;
278 G4double radiatorCof = 1.0; // for tuning of XTR yield
279
280 fEnergyDistrTable = new G4PhysicsTable(fTotBin);
281
282 fGammaTkinCut = 0.0;
283
284 // setting of min/max TR energies
285
286 if(fGammaTkinCut > fTheMinEnergyTR) fMinEnergyTR = fGammaTkinCut ;
287 else fMinEnergyTR = fTheMinEnergyTR ;
288
289 if(fGammaTkinCut > fTheMaxEnergyTR) fMaxEnergyTR = 2.0*fGammaTkinCut ;
290 else fMaxEnergyTR = fTheMaxEnergyTR ;
291
292 G4cout.precision(4) ;
293 G4Timer timer ;
294 timer.Start() ;
295
296 if(verboseLevel > 0) {
297 G4cout<<G4endl;
298 G4cout<<"Lorentz Factor"<<"\t"<<"XTR photon number"<<G4endl;
299 G4cout<<G4endl;
300 }
301 for( iTkin = 0 ; iTkin < fTotBin ; iTkin++ ) // Lorentz factor loop
302 {
303 G4PhysicsLogVector* energyVector = new G4PhysicsLogVector( fMinEnergyTR,
304 fMaxEnergyTR,
305 fBinTR ) ;
306
307 fGamma = 1.0 + (fProtonEnergyVector->
308 GetLowEdgeEnergy(iTkin)/proton_mass_c2) ;
309
310 fMaxThetaTR = 25.0/(fGamma*fGamma) ; // theta^2
311
312 fTheMinAngle = 1.0e-3 ; // was 5.e-6, e-6 !!!, e-5, e-4
313
314 if( fMaxThetaTR > fTheMaxAngle ) fMaxThetaTR = fTheMaxAngle;
315 else
316 {
317 if( fMaxThetaTR < fTheMinAngle ) fMaxThetaTR = fTheMinAngle;
318 }
319 G4PhysicsLinearVector* angleVector = new G4PhysicsLinearVector(0.0,
320 fMaxThetaTR,
321 fBinTR );
322
323 G4double energySum = 0.0;
324 G4double angleSum = 0.0;
325
326 G4Integrator<G4VXTRenergyLoss,G4double(G4VXTRenergyLoss::*)(G4double)> integral;
327
328 energyVector->PutValue(fBinTR-1,energySum);
329 angleVector->PutValue(fBinTR-1,angleSum);
330
331 for( iTR = fBinTR - 2 ; iTR >= 0 ; iTR-- )
332 {
333 energySum += radiatorCof*fCofTR*integral.Legendre10(
334 this,&G4VXTRenergyLoss::SpectralXTRdEdx,
335 energyVector->GetLowEdgeEnergy(iTR),
336 energyVector->GetLowEdgeEnergy(iTR+1) );
337
338 // angleSum += fCofTR*integral.Legendre96(
339 // this,&G4VXTRenergyLoss::AngleXTRdEdx,
340 // angleVector->GetLowEdgeEnergy(iTR),
341 // angleVector->GetLowEdgeEnergy(iTR+1) );
342
343 energyVector->PutValue(iTR,energySum/fTotalDist);
344 // angleVector ->PutValue(iTR,angleSum);
345 }
346 if(verboseLevel > 0)
347 {
348 G4cout
349 // <<iTkin<<"\t"
350 // <<"fGamma = "
351 <<fGamma<<"\t" // <<" fMaxThetaTR = "<<fMaxThetaTR
352 // <<"sumN = "
353 <<energySum // <<" ; sumA = "<<angleSum
354 <<G4endl;
355 }
356 iPlace = iTkin;
357 fEnergyDistrTable->insertAt(iPlace,energyVector);
358 // fAngleDistrTable->insertAt(iPlace,angleVector);
359 }
360 timer.Stop();
361 G4cout.precision(6);
362 if(verboseLevel > 0) {
363 G4cout<<G4endl;
364 G4cout<<"total time for build X-ray TR energy loss tables = "
365 <<timer.GetUserElapsed()<<" s"<<G4endl;
366 }
367 fGamma = 0.;
368 return ;
369}
370
371//////////////////////////////////////////////////////////////////////////
372//
373//
374
375void G4VXTRenergyLoss::BuildEnergyTable()
376{
377}
378
379////////////////////////////////////////////////////////////////////////
380//
381// Build XTR angular distribution at given energy based on the model
382// of transparent regular radiator
383
384void G4VXTRenergyLoss::BuildAngleTable()
385{
386 G4int iTkin, iTR;
387 G4double energy;
388
389 fGammaTkinCut = 0.0;
390
391 // setting of min/max TR energies
392
393 if(fGammaTkinCut > fTheMinEnergyTR) fMinEnergyTR = fGammaTkinCut;
394 else fMinEnergyTR = fTheMinEnergyTR;
395
396 if(fGammaTkinCut > fTheMaxEnergyTR) fMaxEnergyTR = 2.0*fGammaTkinCut;
397 else fMaxEnergyTR = fTheMaxEnergyTR;
398
399 G4cout.precision(4);
400 G4Timer timer;
401 timer.Start();
402 if(verboseLevel > 0) {
403 G4cout<<G4endl;
404 G4cout<<"Lorentz Factor"<<"\t"<<"XTR photon number"<<G4endl;
405 G4cout<<G4endl;
406 }
407 for( iTkin = 0 ; iTkin < fTotBin ; iTkin++ ) // Lorentz factor loop
408 {
409
410 fGamma = 1.0 + (fProtonEnergyVector->
411 GetLowEdgeEnergy(iTkin)/proton_mass_c2) ;
412
413 fMaxThetaTR = 25.0/(fGamma*fGamma) ; // theta^2
414
415 fTheMinAngle = 1.0e-3 ; // was 5.e-6, e-6 !!!, e-5, e-4
416
417 if( fMaxThetaTR > fTheMaxAngle ) fMaxThetaTR = fTheMaxAngle;
418 else
419 {
420 if( fMaxThetaTR < fTheMinAngle ) fMaxThetaTR = fTheMinAngle;
421 }
422
423 fAngleForEnergyTable = new G4PhysicsTable(fBinTR);
424
425 for( iTR = 0; iTR < fBinTR; iTR++ )
426 {
427 // energy = fMinEnergyTR*(iTR+1);
428
429 energy = fXTREnergyVector->GetLowEdgeEnergy(iTR);
430
431 G4PhysicsFreeVector* angleVector = new G4PhysicsFreeVector(fBinTR);
432
433 angleVector = GetAngleVector(energy,fBinTR);
434 // G4cout<<G4endl;
435
436 fAngleForEnergyTable->insertAt(iTR,angleVector) ;
437 }
438
439 fAngleBank.push_back(fAngleForEnergyTable);
440 }
441 timer.Stop();
442 G4cout.precision(6);
443 if(verboseLevel > 0) {
444 G4cout<<G4endl;
445 G4cout<<"total time for build XTR angle for given energy tables = "
446 <<timer.GetUserElapsed()<<" s"<<G4endl;
447 }
448 fGamma = 0.;
449
450 return;
451}
452
453/////////////////////////////////////////////////////////////////////////
454//
455// Vector of angles and angle integral distributions
456
457G4PhysicsFreeVector* G4VXTRenergyLoss::GetAngleVector(G4double energy, G4int n)
458{
459 G4double theta=0., result, tmp=0., cof1, cof2, cofMin, cofPHC, angleSum = 0.;
460 G4int iTheta, k, kMax, kMin;
461
462 G4PhysicsFreeVector* angleVector = new G4PhysicsFreeVector(n);
463
464 cofPHC = 4*pi*hbarc;
465 tmp = (fSigma1 - fSigma2)/cofPHC/energy;
466 cof1 = fPlateThick*tmp;
467 cof2 = fGasThick*tmp;
468
469 cofMin = energy*(fPlateThick + fGasThick)/fGamma/fGamma;
470 cofMin += (fPlateThick*fSigma1 + fGasThick*fSigma2)/energy;
471 cofMin /= cofPHC;
472
473 kMin = G4int(cofMin);
474 if (cofMin > kMin) kMin++;
475
476 kMax = kMin + fBinTR -1;
477 if(verboseLevel > 2)
478 {
479 G4cout<<"n-1 = "<<n-1<<"; theta = "
480 <<std::sqrt(fMaxThetaTR)*fGamma<<"; tmp = "
481 <<0.
482 <<"; angleSum = "<<angleSum<<G4endl;
483 }
484 angleVector->PutValue(n-1,fMaxThetaTR, angleSum);
485
486 for( iTheta = n - 2 ; iTheta >= 1 ; iTheta-- )
487 {
488
489 k = iTheta- 1 + kMin;
490
491 tmp = pi*fPlateThick*(k + cof2)/(fPlateThick + fGasThick);
492
493 result = (k - cof1)*(k - cof1)*(k + cof2)*(k + cof2);
494
495 tmp = std::sin(tmp)*std::sin(tmp)*std::abs(k-cofMin)/result;
496
497 if( k == kMin && kMin == G4int(cofMin) )
498 {
499 angleSum += 0.5*tmp; // 0.5*std::sin(tmp)*std::sin(tmp)*std::abs(k-cofMin)/result;
500 }
501 else
502 {
503 angleSum += tmp; // std::sin(tmp)*std::sin(tmp)*std::abs(k-cofMin)/result;
504 }
505 theta = std::abs(k-cofMin)*cofPHC/energy/(fPlateThick + fGasThick);
506 if(verboseLevel > 2)
507 {
508 G4cout<<"iTheta = "<<iTheta<<"; k = "<<k<<"; theta = "
509 <<std::sqrt(theta)*fGamma<<"; tmp = "
510 <<tmp // std::sin(tmp)*std::sin(tmp)*std::abs(k-cofMin)/result
511 <<"; angleSum = "<<angleSum<<G4endl;
512 }
513 angleVector->PutValue( iTheta, theta, angleSum );
514 }
515 if (theta > 0.)
516 {
517 angleSum += 0.5*tmp;
518 theta = 0.;
519 }
520 if(verboseLevel > 2)
521 {
522 G4cout<<"iTheta = "<<iTheta<<"; theta = "
523 <<std::sqrt(theta)*fGamma<<"; tmp = "
524 <<tmp
525 <<"; angleSum = "<<angleSum<<G4endl;
526 }
527 angleVector->PutValue( iTheta, theta, angleSum );
528
529 return angleVector;
530}
531
532////////////////////////////////////////////////////////////////////////
533//
534// Build XTR angular distribution based on the model of transparent regular radiator
535
536void G4VXTRenergyLoss::BuildGlobalAngleTable()
537{
538 G4int iTkin, iTR, iPlace;
539 G4double radiatorCof = 1.0; // for tuning of XTR yield
540 G4double angleSum;
541 fAngleDistrTable = new G4PhysicsTable(fTotBin);
542
543 fGammaTkinCut = 0.0;
544
545 // setting of min/max TR energies
546
547 if(fGammaTkinCut > fTheMinEnergyTR) fMinEnergyTR = fGammaTkinCut ;
548 else fMinEnergyTR = fTheMinEnergyTR ;
549
550 if(fGammaTkinCut > fTheMaxEnergyTR) fMaxEnergyTR = 2.0*fGammaTkinCut ;
551 else fMaxEnergyTR = fTheMaxEnergyTR ;
552
553 G4cout.precision(4) ;
554 G4Timer timer ;
555 timer.Start() ;
556 if(verboseLevel > 0) {
557 G4cout<<G4endl;
558 G4cout<<"Lorentz Factor"<<"\t"<<"XTR photon number"<<G4endl;
559 G4cout<<G4endl;
560 }
561 for( iTkin = 0 ; iTkin < fTotBin ; iTkin++ ) // Lorentz factor loop
562 {
563
564 fGamma = 1.0 + (fProtonEnergyVector->
565 GetLowEdgeEnergy(iTkin)/proton_mass_c2) ;
566
567 fMaxThetaTR = 25.0/(fGamma*fGamma) ; // theta^2
568
569 fTheMinAngle = 1.0e-3 ; // was 5.e-6, e-6 !!!, e-5, e-4
570
571 if( fMaxThetaTR > fTheMaxAngle ) fMaxThetaTR = fTheMaxAngle;
572 else
573 {
574 if( fMaxThetaTR < fTheMinAngle ) fMaxThetaTR = fTheMinAngle;
575 }
576 G4PhysicsLinearVector* angleVector = new G4PhysicsLinearVector(0.0,
577 fMaxThetaTR,
578 fBinTR );
579
580 angleSum = 0.0;
581
582 G4Integrator<G4VXTRenergyLoss,G4double(G4VXTRenergyLoss::*)(G4double)> integral;
583
584
585 angleVector->PutValue(fBinTR-1,angleSum);
586
587 for( iTR = fBinTR - 2 ; iTR >= 0 ; iTR-- )
588 {
589
590 angleSum += radiatorCof*fCofTR*integral.Legendre96(
591 this,&G4VXTRenergyLoss::AngleXTRdEdx,
592 angleVector->GetLowEdgeEnergy(iTR),
593 angleVector->GetLowEdgeEnergy(iTR+1) );
594
595 angleVector ->PutValue(iTR,angleSum);
596 }
597 if(verboseLevel > 1) {
598 G4cout
599 // <<iTkin<<"\t"
600 // <<"fGamma = "
601 <<fGamma<<"\t" // <<" fMaxThetaTR = "<<fMaxThetaTR
602 // <<"sumN = "<<energySum // <<" ; sumA = "
603 <<angleSum
604 <<G4endl;
605 }
606 iPlace = iTkin;
607 fAngleDistrTable->insertAt(iPlace,angleVector);
608 }
609 timer.Stop();
610 G4cout.precision(6);
611 if(verboseLevel > 0) {
612 G4cout<<G4endl;
613 G4cout<<"total time for build X-ray TR angle tables = "
614 <<timer.GetUserElapsed()<<" s"<<G4endl;
615 }
616 fGamma = 0.;
617
618 return;
619}
620
621
622//////////////////////////////////////////////////////////////////////////////
623//
624// The main function which is responsible for the treatment of a particle passage
625// trough G4Envelope with discrete generation of G4Gamma
626
627G4VParticleChange* G4VXTRenergyLoss::PostStepDoIt( const G4Track& aTrack,
628 const G4Step& aStep )
629{
630 G4int iTkin, iPlace;
631 G4double energyTR, theta,theta2, phi, dirX, dirY, dirZ;
632
633
634 fParticleChange.Initialize(aTrack);
635
636 if(verboseLevel > 1)
637 {
638 G4cout<<"Start of G4VXTRenergyLoss::PostStepDoIt "<<G4endl ;
639 G4cout<<"name of current material = "
640 <<aTrack.GetVolume()->GetLogicalVolume()->GetMaterial()->GetName()<<G4endl ;
641 }
642 if( aTrack.GetVolume()->GetLogicalVolume() != fEnvelope )
643 {
644 if(verboseLevel > 0)
645 {
646 G4cout<<"Go out from G4VXTRenergyLoss::PostStepDoIt: wrong volume "<<G4endl;
647 }
648 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
649 }
650 else
651 {
652 G4StepPoint* pPostStepPoint = aStep.GetPostStepPoint();
653 const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
654
655 // Now we are ready to Generate one TR photon
656
657 G4double kinEnergy = aParticle->GetKineticEnergy() ;
658 G4double mass = aParticle->GetDefinition()->GetPDGMass() ;
659 G4double gamma = 1.0 + kinEnergy/mass ;
660
661 if(verboseLevel > 1 )
662 {
663 G4cout<<"gamma = "<<gamma<<G4endl ;
664 }
665 G4double massRatio = proton_mass_c2/mass ;
666 G4double TkinScaled = kinEnergy*massRatio ;
667 G4ThreeVector position = pPostStepPoint->GetPosition();
668 G4ParticleMomentum direction = aParticle->GetMomentumDirection();
669 G4double startTime = pPostStepPoint->GetGlobalTime();
670
671 for( iTkin = 0; iTkin < fTotBin; iTkin++ )
672 {
673 if(TkinScaled < fProtonEnergyVector->GetLowEdgeEnergy(iTkin)) break;
674 }
675 iPlace = iTkin - 1;
676
677 if(iTkin == 0) // Tkin is too small, neglect of TR photon generation
678 {
679 if( verboseLevel > 0)
680 {
681 G4cout<<"Go out from G4VXTRenergyLoss::PostStepDoIt:iTkin = "<<iTkin<<G4endl;
682 }
683 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
684 }
685 else // general case: Tkin between two vectors of the material
686 {
687 fParticleChange.SetNumberOfSecondaries(1);
688
689 energyTR = GetXTRrandomEnergy(TkinScaled,iTkin);
690
691 if( verboseLevel > 1)
692 {
693 G4cout<<"energyTR = "<<energyTR/keV<<" keV"<<G4endl;
694 }
695 if (fAngleRadDistr)
696 {
697 // theta = std::fabs(G4RandGauss::shoot(0.0,pi/gamma));
698 theta2 = GetRandomAngle(energyTR,iTkin);
699 if(theta2 > 0.) theta = std::sqrt(theta2);
700 else theta = theta2;
701 }
702 else theta = std::fabs(G4RandGauss::shoot(0.0,pi/gamma));
703
704 if( theta >= 0.1 ) theta = 0.1;
705
706 // G4cout<<" : theta = "<<theta<<endl ;
707
708 phi = twopi*G4UniformRand();
709
710 dirX = std::sin(theta)*std::cos(phi);
711 dirY = std::sin(theta)*std::sin(phi);
712 dirZ = std::cos(theta);
713
714 G4ThreeVector directionTR(dirX,dirY,dirZ);
715 directionTR.rotateUz(direction);
716 directionTR.unit();
717
718 G4DynamicParticle* aPhotonTR = new G4DynamicParticle(G4Gamma::Gamma(),
719 directionTR, energyTR);
720
721 // A XTR photon is set on the particle track inside the radiator
722 // and is moved to the G4Envelope surface for standard X-ray TR models
723 // only. The case of fExitFlux=true
724
725 if( fExitFlux )
726 {
727 const G4RotationMatrix* rotM = pPostStepPoint->GetTouchable()->GetRotation();
728 G4ThreeVector transl = pPostStepPoint->GetTouchable()->GetTranslation();
729 G4AffineTransform transform = G4AffineTransform(rotM,transl);
730 transform.Invert();
731 G4ThreeVector localP = transform.TransformPoint(position);
732 G4ThreeVector localV = transform.TransformAxis(directionTR);
733
734 G4double distance = fEnvelope->GetSolid()->DistanceToOut(localP, localV);
735 if(verboseLevel > 1)
736 {
737 G4cout<<"distance to exit = "<<distance/mm<<" mm"<<G4endl;
738 }
739 position += distance*directionTR;
740 startTime += distance/c_light;
741 }
742 G4Track* aSecondaryTrack = new G4Track( aPhotonTR,
743 startTime, position );
744 aSecondaryTrack->SetTouchableHandle(
745 aStep.GetPostStepPoint()->GetTouchableHandle());
746 aSecondaryTrack->SetParentID( aTrack.GetTrackID() );
747
748 fParticleChange.AddSecondary(aSecondaryTrack);
749 fParticleChange.ProposeEnergy(kinEnergy);
750 }
751 }
752 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
753}
754
755///////////////////////////////////////////////////////////////////////
756//
757// This function returns the spectral and angle density of TR quanta
758// in X-ray energy region generated forward when a relativistic
759// charged particle crosses interface between two materials.
760// The high energy small theta approximation is applied.
761// (matter1 -> matter2, or 2->1)
762// varAngle =2* (1 - std::cos(theta)) or approximately = theta*theta
763//
764
765G4complex G4VXTRenergyLoss::OneInterfaceXTRdEdx( G4double energy,
766 G4double gamma,
767 G4double varAngle )
768{
769 G4complex Z1 = GetPlateComplexFZ(energy,gamma,varAngle) ;
770 G4complex Z2 = GetGasComplexFZ(energy,gamma,varAngle) ;
771
772 G4complex zOut = (Z1 - Z2)*(Z1 - Z2)
773 * (varAngle*energy/hbarc/hbarc) ;
774 return zOut ;
775
776}
777
778
779//////////////////////////////////////////////////////////////////////////////
780//
781// For photon energy distribution tables. Integrate first over angle
782//
783
784G4double G4VXTRenergyLoss::SpectralAngleXTRdEdx(G4double varAngle)
785{
786 G4double result = GetStackFactor(fEnergy,fGamma,varAngle);
787 if(result < 0.0) result = 0.0;
788 return result;
789}
790
791/////////////////////////////////////////////////////////////////////////
792//
793// For second integration over energy
794
795G4double G4VXTRenergyLoss::SpectralXTRdEdx(G4double energy)
796{
797 G4int i, iMax = 8;
798 G4double result = 0.0;
799
800 G4double lim[8] = { 0.0, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1.0 };
801
802 for( i = 0; i < iMax; i++ ) lim[i] *= fMaxThetaTR;
803
804 G4Integrator<G4VXTRenergyLoss,G4double(G4VXTRenergyLoss::*)(G4double)> integral;
805
806 fEnergy = energy;
807
808 for( i = 0; i < iMax-1; i++ )
809 {
810 result += integral.Legendre96(this,&G4VXTRenergyLoss::SpectralAngleXTRdEdx,
811 lim[i],lim[i+1]);
812 // result += integral.Legendre10(this,&G4VXTRenergyLoss::SpectralAngleXTRdEdx,
813 // lim[i],lim[i+1]);
814 }
815
816 return result;
817}
818
819//////////////////////////////////////////////////////////////////////////
820//
821// for photon angle distribution tables
822//
823
824G4double G4VXTRenergyLoss::AngleSpectralXTRdEdx(G4double energy)
825{
826 G4double result = GetStackFactor(energy,fGamma,fVarAngle);
827 if(result < 0) result = 0.0;
828 return result;
829}
830
831///////////////////////////////////////////////////////////////////////////
832//
833// The XTR angular distribution based on transparent regular radiator
834
835G4double G4VXTRenergyLoss::AngleXTRdEdx(G4double varAngle)
836{
837 // G4cout<<"angle2 = "<<varAngle<<"; fGamma = "<<fGamma<<G4endl;
838
839 G4double result;
840 G4double sum = 0., tmp1, tmp2, tmp=0., cof1, cof2, cofMin, cofPHC, energy1, energy2;
841 G4int k, kMax, kMin, i;
842
843 cofPHC = twopi*hbarc;
844
845 cof1 = (fPlateThick + fGasThick)*(1./fGamma/fGamma + varAngle);
846 cof2 = fPlateThick*fSigma1 + fGasThick*fSigma2;
847
848 // G4cout<<"cof1 = "<<cof1<<"; cof2 = "<<cof2<<"; cofPHC = "<<cofPHC<<G4endl;
849
850 cofMin = std::sqrt(cof1*cof2);
851 cofMin /= cofPHC;
852
853 kMin = G4int(cofMin);
854 if (cofMin > kMin) kMin++;
855
856 kMax = kMin + 9; // 9; // kMin + G4int(tmp);
857
858 // G4cout<<"cofMin = "<<cofMin<<"; kMin = "<<kMin<<"; kMax = "<<kMax<<G4endl;
859
860 for( k = kMin; k <= kMax; k++ )
861 {
862 tmp1 = cofPHC*k;
863 tmp2 = std::sqrt(tmp1*tmp1-cof1*cof2);
864 energy1 = (tmp1+tmp2)/cof1;
865 energy2 = (tmp1-tmp2)/cof1;
866
867 for(i = 0; i < 2; i++)
868 {
869 if( i == 0 )
870 {
871 if (energy1 > fTheMaxEnergyTR || energy1 < fTheMinEnergyTR) continue;
872 tmp1 = ( energy1*energy1*(1./fGamma/fGamma + varAngle) + fSigma1 )
873 * fPlateThick/(4*hbarc*energy1);
874 tmp2 = std::sin(tmp1);
875 tmp = energy1*tmp2*tmp2;
876 tmp2 = fPlateThick/(4*tmp1);
877 tmp1 = hbarc*energy1/( energy1*energy1*(1./fGamma/fGamma + varAngle) + fSigma2 );
878 tmp *= (tmp1-tmp2)*(tmp1-tmp2);
879 tmp1 = cof1/(4*hbarc) - cof2/(4*hbarc*energy1*energy1);
880 tmp2 = std::abs(tmp1);
881 if(tmp2 > 0.) tmp /= tmp2;
882 else continue;
883 }
884 else
885 {
886 if (energy2 > fTheMaxEnergyTR || energy2 < fTheMinEnergyTR) continue;
887 tmp1 = ( energy2*energy2*(1./fGamma/fGamma + varAngle) + fSigma1 )
888 * fPlateThick/(4*hbarc*energy2);
889 tmp2 = std::sin(tmp1);
890 tmp = energy2*tmp2*tmp2;
891 tmp2 = fPlateThick/(4*tmp1);
892 tmp1 = hbarc*energy2/( energy2*energy2*(1./fGamma/fGamma + varAngle) + fSigma2 );
893 tmp *= (tmp1-tmp2)*(tmp1-tmp2);
894 tmp1 = cof1/(4*hbarc) - cof2/(4*hbarc*energy2*energy2);
895 tmp2 = std::abs(tmp1);
896 if(tmp2 > 0.) tmp /= tmp2;
897 else continue;
898 }
899 sum += tmp;
900 }
901 // G4cout<<"k = "<<k<<"; energy1 = "<<energy1/keV<<" keV; energy2 = "<<energy2/keV
902 // <<" keV; tmp = "<<tmp<<"; sum = "<<sum<<G4endl;
903 }
904 result = 4.*pi*fPlateNumber*sum*varAngle;
905 result /= hbarc*hbarc;
906
907 // old code based on general numeric integration
908 // fVarAngle = varAngle;
909 // G4Integrator<G4VXTRenergyLoss,G4double(G4VXTRenergyLoss::*)(G4double)> integral;
910 // result = integral.Legendre10(this,&G4VXTRenergyLoss::AngleSpectralXTRdEdx,
911 // fMinEnergyTR,fMaxEnergyTR);
912 return result;
913}
914
915
916//////////////////////////////////////////////////////////////////////
917//////////////////////////////////////////////////////////////////////
918//////////////////////////////////////////////////////////////////////
919//
920// Calculates formation zone for plates. Omega is energy !!!
921
922G4double G4VXTRenergyLoss::GetPlateFormationZone( G4double omega ,
923 G4double gamma ,
924 G4double varAngle )
925{
926 G4double cof, lambda ;
927 lambda = 1.0/gamma/gamma + varAngle + fSigma1/omega/omega ;
928 cof = 2.0*hbarc/omega/lambda ;
929 return cof ;
930}
931
932//////////////////////////////////////////////////////////////////////
933//
934// Calculates complex formation zone for plates. Omega is energy !!!
935
936G4complex G4VXTRenergyLoss::GetPlateComplexFZ( G4double omega ,
937 G4double gamma ,
938 G4double varAngle )
939{
940 G4double cof, length,delta, real_v, image_v ;
941
942 length = 0.5*GetPlateFormationZone(omega,gamma,varAngle) ;
943 delta = length*GetPlateLinearPhotoAbs(omega) ;
944 cof = 1.0/(1.0 + delta*delta) ;
945
946 real_v = length*cof ;
947 image_v = real_v*delta ;
948
949 G4complex zone(real_v,image_v);
950 return zone ;
951}
952
953////////////////////////////////////////////////////////////////////////
954//
955// Computes matrix of Sandia photo absorption cross section coefficients for
956// plate material
957
958void G4VXTRenergyLoss::ComputePlatePhotoAbsCof()
959{
960 const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
961 const G4Material* mat = (*theMaterialTable)[fMatIndex1];
962 fPlatePhotoAbsCof = mat->GetSandiaTable();
963
964 return;
965}
966
967
968
969//////////////////////////////////////////////////////////////////////
970//
971// Returns the value of linear photo absorption coefficient (in reciprocal
972// length) for plate for given energy of X-ray photon omega
973
974G4double G4VXTRenergyLoss::GetPlateLinearPhotoAbs(G4double omega)
975{
976 // G4int i ;
977 G4double omega2, omega3, omega4 ;
978
979 omega2 = omega*omega ;
980 omega3 = omega2*omega ;
981 omega4 = omega2*omega2 ;
982
983 G4double* SandiaCof = fPlatePhotoAbsCof->GetSandiaCofForMaterial(omega);
984 G4double cross = SandiaCof[0]/omega + SandiaCof[1]/omega2 +
985 SandiaCof[2]/omega3 + SandiaCof[3]/omega4;
986 return cross;
987}
988
989
990//////////////////////////////////////////////////////////////////////
991//
992// Calculates formation zone for gas. Omega is energy !!!
993
994G4double G4VXTRenergyLoss::GetGasFormationZone( G4double omega ,
995 G4double gamma ,
996 G4double varAngle )
997{
998 G4double cof, lambda ;
999 lambda = 1.0/gamma/gamma + varAngle + fSigma2/omega/omega ;
1000 cof = 2.0*hbarc/omega/lambda ;
1001 return cof ;
1002}
1003
1004
1005//////////////////////////////////////////////////////////////////////
1006//
1007// Calculates complex formation zone for gas gaps. Omega is energy !!!
1008
1009G4complex G4VXTRenergyLoss::GetGasComplexFZ( G4double omega ,
1010 G4double gamma ,
1011 G4double varAngle )
1012{
1013 G4double cof, length,delta, real_v, image_v ;
1014
1015 length = 0.5*GetGasFormationZone(omega,gamma,varAngle) ;
1016 delta = length*GetGasLinearPhotoAbs(omega) ;
1017 cof = 1.0/(1.0 + delta*delta) ;
1018
1019 real_v = length*cof ;
1020 image_v = real_v*delta ;
1021
1022 G4complex zone(real_v,image_v);
1023 return zone ;
1024}
1025
1026
1027
1028////////////////////////////////////////////////////////////////////////
1029//
1030// Computes matrix of Sandia photo absorption cross section coefficients for
1031// gas material
1032
1033void G4VXTRenergyLoss::ComputeGasPhotoAbsCof()
1034{
1035 const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
1036 const G4Material* mat = (*theMaterialTable)[fMatIndex2];
1037 fGasPhotoAbsCof = mat->GetSandiaTable();
1038 return;
1039}
1040
1041//////////////////////////////////////////////////////////////////////
1042//
1043// Returns the value of linear photo absorption coefficient (in reciprocal
1044// length) for gas
1045
1046G4double G4VXTRenergyLoss::GetGasLinearPhotoAbs(G4double omega)
1047{
1048 G4double omega2, omega3, omega4 ;
1049
1050 omega2 = omega*omega ;
1051 omega3 = omega2*omega ;
1052 omega4 = omega2*omega2 ;
1053
1054 G4double* SandiaCof = fGasPhotoAbsCof->GetSandiaCofForMaterial(omega);
1055 G4double cross = SandiaCof[0]/omega + SandiaCof[1]/omega2 +
1056 SandiaCof[2]/omega3 + SandiaCof[3]/omega4;
1057 return cross;
1058
1059}
1060
1061//////////////////////////////////////////////////////////////////////
1062//
1063// Calculates the product of linear cof by formation zone for plate.
1064// Omega is energy !!!
1065
1066G4double G4VXTRenergyLoss::GetPlateZmuProduct( G4double omega ,
1067 G4double gamma ,
1068 G4double varAngle )
1069{
1070 return GetPlateFormationZone(omega,gamma,varAngle)
1071 * GetPlateLinearPhotoAbs(omega) ;
1072}
1073//////////////////////////////////////////////////////////////////////
1074//
1075// Calculates the product of linear cof by formation zone for plate.
1076// G4cout and output in file in some energy range.
1077
1078void G4VXTRenergyLoss::GetPlateZmuProduct()
1079{
1080 std::ofstream outPlate("plateZmu.dat", std::ios::out ) ;
1081 outPlate.setf( std::ios::scientific, std::ios::floatfield );
1082
1083 G4int i ;
1084 G4double omega, varAngle, gamma ;
1085 gamma = 10000. ;
1086 varAngle = 1/gamma/gamma ;
1087 if(verboseLevel > 0)
1088 G4cout<<"energy, keV"<<"\t"<<"Zmu for plate"<<G4endl ;
1089 for(i=0;i<100;i++)
1090 {
1091 omega = (1.0 + i)*keV ;
1092 if(verboseLevel > 1)
1093 G4cout<<omega/keV<<"\t"<<GetPlateZmuProduct(omega,gamma,varAngle)<<"\t";
1094 if(verboseLevel > 0)
1095 outPlate<<omega/keV<<"\t\t"<<GetPlateZmuProduct(omega,gamma,varAngle)<<G4endl ;
1096 }
1097 return ;
1098}
1099
1100//////////////////////////////////////////////////////////////////////
1101//
1102// Calculates the product of linear cof by formation zone for gas.
1103// Omega is energy !!!
1104
1105G4double G4VXTRenergyLoss::GetGasZmuProduct( G4double omega ,
1106 G4double gamma ,
1107 G4double varAngle )
1108{
1109 return GetGasFormationZone(omega,gamma,varAngle)*GetGasLinearPhotoAbs(omega) ;
1110}
1111//////////////////////////////////////////////////////////////////////
1112//
1113// Calculates the product of linear cof byformation zone for gas.
1114// G4cout and output in file in some energy range.
1115
1116void G4VXTRenergyLoss::GetGasZmuProduct()
1117{
1118 std::ofstream outGas("gasZmu.dat", std::ios::out ) ;
1119 outGas.setf( std::ios::scientific, std::ios::floatfield );
1120 G4int i ;
1121 G4double omega, varAngle, gamma ;
1122 gamma = 10000. ;
1123 varAngle = 1/gamma/gamma ;
1124 if(verboseLevel > 0)
1125 G4cout<<"energy, keV"<<"\t"<<"Zmu for gas"<<G4endl ;
1126 for(i=0;i<100;i++)
1127 {
1128 omega = (1.0 + i)*keV ;
1129 if(verboseLevel > 1)
1130 G4cout<<omega/keV<<"\t"<<GetGasZmuProduct(omega,gamma,varAngle)<<"\t" ;
1131 if(verboseLevel > 0)
1132 outGas<<omega/keV<<"\t\t"<<GetGasZmuProduct(omega,gamma,varAngle)<<G4endl ;
1133 }
1134 return ;
1135}
1136
1137////////////////////////////////////////////////////////////////////////
1138//
1139// Computes Compton cross section for plate material in 1/mm
1140
1141G4double G4VXTRenergyLoss::GetPlateCompton(G4double omega)
1142{
1143 G4int i, numberOfElements;
1144 G4double xSection = 0., nowZ, sumZ = 0.;
1145
1146 const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
1147 numberOfElements = (*theMaterialTable)[fMatIndex1]->GetNumberOfElements() ;
1148
1149 for( i = 0; i < numberOfElements; i++ )
1150 {
1151 nowZ = (*theMaterialTable)[fMatIndex1]->GetElement(i)->GetZ();
1152 sumZ += nowZ;
1153 xSection += GetComptonPerAtom(omega,nowZ); // *nowZ;
1154 }
1155 xSection /= sumZ;
1156 xSection *= (*theMaterialTable)[fMatIndex1]->GetElectronDensity();
1157 return xSection;
1158}
1159
1160
1161////////////////////////////////////////////////////////////////////////
1162//
1163// Computes Compton cross section for gas material in 1/mm
1164
1165G4double G4VXTRenergyLoss::GetGasCompton(G4double omega)
1166{
1167 G4int i, numberOfElements;
1168 G4double xSection = 0., nowZ, sumZ = 0.;
1169
1170 const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
1171 numberOfElements = (*theMaterialTable)[fMatIndex2]->GetNumberOfElements() ;
1172
1173 for( i = 0; i < numberOfElements; i++ )
1174 {
1175 nowZ = (*theMaterialTable)[fMatIndex2]->GetElement(i)->GetZ();
1176 sumZ += nowZ;
1177 xSection += GetComptonPerAtom(omega,nowZ); // *nowZ;
1178 }
1179 xSection /= sumZ;
1180 xSection *= (*theMaterialTable)[fMatIndex2]->GetElectronDensity();
1181 return xSection;
1182}
1183
1184////////////////////////////////////////////////////////////////////////
1185//
1186// Computes Compton cross section per atom with Z electrons for gamma with
1187// the energy GammaEnergy
1188
1189G4double G4VXTRenergyLoss::GetComptonPerAtom(G4double GammaEnergy, G4double Z)
1190{
1191 G4double CrossSection = 0.0 ;
1192 if ( Z < 0.9999 ) return CrossSection;
1193 if ( GammaEnergy < 0.1*keV ) return CrossSection;
1194 if ( GammaEnergy > (100.*GeV/Z) ) return CrossSection;
1195
1196 static const G4double a = 20.0 , b = 230.0 , c = 440.0;
1197
1198 static const G4double
1199 d1= 2.7965e-1*barn, d2=-1.8300e-1*barn, d3= 6.7527 *barn, d4=-1.9798e+1*barn,
1200 e1= 1.9756e-5*barn, e2=-1.0205e-2*barn, e3=-7.3913e-2*barn, e4= 2.7079e-2*barn,
1201 f1=-3.9178e-7*barn, f2= 6.8241e-5*barn, f3= 6.0480e-5*barn, f4= 3.0274e-4*barn;
1202
1203 G4double p1Z = Z*(d1 + e1*Z + f1*Z*Z), p2Z = Z*(d2 + e2*Z + f2*Z*Z),
1204 p3Z = Z*(d3 + e3*Z + f3*Z*Z), p4Z = Z*(d4 + e4*Z + f4*Z*Z);
1205
1206 G4double T0 = 15.0*keV;
1207 if (Z < 1.5) T0 = 40.0*keV;
1208
1209 G4double X = std::max(GammaEnergy, T0) / electron_mass_c2;
1210 CrossSection = p1Z*std::log(1.+2.*X)/X
1211 + (p2Z + p3Z*X + p4Z*X*X)/(1. + a*X + b*X*X + c*X*X*X);
1212
1213 // modification for low energy. (special case for Hydrogen)
1214
1215 if (GammaEnergy < T0)
1216 {
1217 G4double dT0 = 1.*keV;
1218 X = (T0+dT0) / electron_mass_c2 ;
1219 G4double sigma = p1Z*std::log(1.+2*X)/X
1220 + (p2Z + p3Z*X + p4Z*X*X)/(1. + a*X + b*X*X + c*X*X*X);
1221 G4double c1 = -T0*(sigma-CrossSection)/(CrossSection*dT0);
1222 G4double c2 = 0.150;
1223 if (Z > 1.5) c2 = 0.375-0.0556*std::log(Z);
1224 G4double y = std::log(GammaEnergy/T0);
1225 CrossSection *= std::exp(-y*(c1+c2*y));
1226 }
1227 // G4cout << "e= " << GammaEnergy << " Z= " << Z << " cross= " << CrossSection << G4endl;
1228 return CrossSection;
1229}
1230
1231
1232///////////////////////////////////////////////////////////////////////
1233//
1234// This function returns the spectral and angle density of TR quanta
1235// in X-ray energy region generated forward when a relativistic
1236// charged particle crosses interface between two materials.
1237// The high energy small theta approximation is applied.
1238// (matter1 -> matter2, or 2->1)
1239// varAngle =2* (1 - std::cos(theta)) or approximately = theta*theta
1240//
1241
1242G4double
1243G4VXTRenergyLoss::OneBoundaryXTRNdensity( G4double energy,G4double gamma,
1244 G4double varAngle ) const
1245{
1246 G4double formationLength1, formationLength2 ;
1247 formationLength1 = 1.0/
1248 (1.0/(gamma*gamma)
1249 + fSigma1/(energy*energy)
1250 + varAngle) ;
1251 formationLength2 = 1.0/
1252 (1.0/(gamma*gamma)
1253 + fSigma2/(energy*energy)
1254 + varAngle) ;
1255 return (varAngle/energy)*(formationLength1 - formationLength2)
1256 *(formationLength1 - formationLength2) ;
1257
1258}
1259
1260G4double G4VXTRenergyLoss::GetStackFactor( G4double energy, G4double gamma,
1261 G4double varAngle )
1262{
1263 // return stack factor corresponding to one interface
1264
1265 return std::real( OneInterfaceXTRdEdx(energy,gamma,varAngle) );
1266}
1267
1268//////////////////////////////////////////////////////////////////////////////
1269//
1270// For photon energy distribution tables. Integrate first over angle
1271//
1272
1273G4double G4VXTRenergyLoss::XTRNSpectralAngleDensity(G4double varAngle)
1274{
1275 return OneBoundaryXTRNdensity(fEnergy,fGamma,varAngle)*
1276 GetStackFactor(fEnergy,fGamma,varAngle) ;
1277}
1278
1279/////////////////////////////////////////////////////////////////////////
1280//
1281// For second integration over energy
1282
1283G4double G4VXTRenergyLoss::XTRNSpectralDensity(G4double energy)
1284{
1285 fEnergy = energy ;
1286 G4Integrator<G4VXTRenergyLoss,G4double(G4VXTRenergyLoss::*)(G4double)> integral ;
1287 return integral.Legendre96(this,&G4VXTRenergyLoss::XTRNSpectralAngleDensity,
1288 0.0,0.2*fMaxThetaTR) +
1289 integral.Legendre10(this,&G4VXTRenergyLoss::XTRNSpectralAngleDensity,
1290 0.2*fMaxThetaTR,fMaxThetaTR) ;
1291}
1292
1293//////////////////////////////////////////////////////////////////////////
1294//
1295// for photon angle distribution tables
1296//
1297
1298G4double G4VXTRenergyLoss::XTRNAngleSpectralDensity(G4double energy)
1299{
1300 return OneBoundaryXTRNdensity(energy,fGamma,fVarAngle)*
1301 GetStackFactor(energy,fGamma,fVarAngle) ;
1302}
1303
1304///////////////////////////////////////////////////////////////////////////
1305//
1306//
1307
1308G4double G4VXTRenergyLoss::XTRNAngleDensity(G4double varAngle)
1309{
1310 fVarAngle = varAngle ;
1311 G4Integrator<G4VXTRenergyLoss,G4double(G4VXTRenergyLoss::*)(G4double)> integral ;
1312 return integral.Legendre96(this,&G4VXTRenergyLoss::XTRNAngleSpectralDensity,
1313 fMinEnergyTR,fMaxEnergyTR) ;
1314}
1315
1316//////////////////////////////////////////////////////////////////////////////
1317//
1318// Check number of photons for a range of Lorentz factors from both energy
1319// and angular tables
1320
1321void G4VXTRenergyLoss::GetNumberOfPhotons()
1322{
1323 G4int iTkin ;
1324 G4double gamma, numberE ;
1325
1326 std::ofstream outEn("numberE.dat", std::ios::out ) ;
1327 outEn.setf( std::ios::scientific, std::ios::floatfield );
1328
1329 std::ofstream outAng("numberAng.dat", std::ios::out ) ;
1330 outAng.setf( std::ios::scientific, std::ios::floatfield );
1331
1332 for(iTkin=0;iTkin<fTotBin;iTkin++) // Lorentz factor loop
1333 {
1334 gamma = 1.0 + (fProtonEnergyVector->
1335 GetLowEdgeEnergy(iTkin)/proton_mass_c2) ;
1336 numberE = (*(*fEnergyDistrTable)(iTkin))(0) ;
1337 // numberA = (*(*fAngleDistrTable)(iTkin))(0) ;
1338 if(verboseLevel > 1)
1339 G4cout<<gamma<<"\t\t"<<numberE<<"\t" // <<numberA
1340 <<G4endl ;
1341 if(verboseLevel > 0)
1342 outEn<<gamma<<"\t\t"<<numberE<<G4endl ;
1343 }
1344 return ;
1345}
1346
1347/////////////////////////////////////////////////////////////////////////
1348//
1349// Returns randon energy of a X-ray TR photon for given scaled kinetic energy
1350// of a charged particle
1351
1352G4double G4VXTRenergyLoss::GetXTRrandomEnergy( G4double scaledTkin, G4int iTkin )
1353{
1354 G4int iTransfer, iPlace ;
1355 G4double transfer = 0.0, position, E1, E2, W1, W2, W ;
1356
1357 iPlace = iTkin - 1 ;
1358
1359 // G4cout<<"iPlace = "<<iPlace<<endl ;
1360
1361 if(iTkin == fTotBin) // relativistic plato, try from left
1362 {
1363 position = (*(*fEnergyDistrTable)(iPlace))(0)*G4UniformRand() ;
1364
1365 for(iTransfer=0;;iTransfer++)
1366 {
1367 if(position >= (*(*fEnergyDistrTable)(iPlace))(iTransfer)) break ;
1368 }
1369 transfer = GetXTRenergy(iPlace,position,iTransfer);
1370 }
1371 else
1372 {
1373 E1 = fProtonEnergyVector->GetLowEdgeEnergy(iTkin - 1) ;
1374 E2 = fProtonEnergyVector->GetLowEdgeEnergy(iTkin) ;
1375 W = 1.0/(E2 - E1) ;
1376 W1 = (E2 - scaledTkin)*W ;
1377 W2 = (scaledTkin - E1)*W ;
1378
1379 position =( (*(*fEnergyDistrTable)(iPlace))(0)*W1 +
1380 (*(*fEnergyDistrTable)(iPlace+1))(0)*W2 )*G4UniformRand() ;
1381
1382 // G4cout<<position<<"\t" ;
1383
1384 for(iTransfer=0;;iTransfer++)
1385 {
1386 if( position >=
1387 ( (*(*fEnergyDistrTable)(iPlace))(iTransfer)*W1 +
1388 (*(*fEnergyDistrTable)(iPlace+1))(iTransfer)*W2) ) break ;
1389 }
1390 transfer = GetXTRenergy(iPlace,position,iTransfer);
1391
1392 }
1393 // G4cout<<"XTR transfer = "<<transfer/keV<<" keV"<<endl ;
1394 if(transfer < 0.0 ) transfer = 0.0 ;
1395 return transfer ;
1396}
1397
1398////////////////////////////////////////////////////////////////////////
1399//
1400// Returns approximate position of X-ray photon energy during random sampling
1401// over integral energy distribution
1402
1403G4double G4VXTRenergyLoss::GetXTRenergy( G4int iPlace,
1404 G4double position,
1405 G4int iTransfer )
1406{
1407 G4double x1, x2, y1, y2, result ;
1408
1409 if(iTransfer == 0)
1410 {
1411 result = (*fEnergyDistrTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ;
1412 }
1413 else
1414 {
1415 y1 = (*(*fEnergyDistrTable)(iPlace))(iTransfer-1) ;
1416 y2 = (*(*fEnergyDistrTable)(iPlace))(iTransfer) ;
1417
1418 x1 = (*fEnergyDistrTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1) ;
1419 x2 = (*fEnergyDistrTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ;
1420
1421 if ( x1 == x2 ) result = x2 ;
1422 else
1423 {
1424 if ( y1 == y2 ) result = x1 + (x2 - x1)*G4UniformRand() ;
1425 else
1426 {
1427 result = x1 + (position - y1)*(x2 - x1)/(y2 - y1) ;
1428 }
1429 }
1430 }
1431 return result ;
1432}
1433
1434/////////////////////////////////////////////////////////////////////////
1435//
1436// Get XTR photon angle at given energy and Tkin
1437
1438G4double G4VXTRenergyLoss::GetRandomAngle( G4double energyXTR, G4int iTkin )
1439{
1440 G4int iTR, iAngle;
1441 G4double position, angle;
1442
1443 if (iTkin == fTotBin) iTkin--;
1444
1445 fAngleForEnergyTable = fAngleBank[iTkin];
1446
1447 for( iTR = 0; iTR < fBinTR; iTR++ )
1448 {
1449 if( energyXTR < fXTREnergyVector->GetLowEdgeEnergy(iTR) ) break;
1450 }
1451 if (iTR == fBinTR) iTR--;
1452
1453 position = (*(*fAngleForEnergyTable)(iTR))(0)*G4UniformRand() ;
1454
1455 for(iAngle = 0;;iAngle++)
1456 {
1457 if(position >= (*(*fAngleForEnergyTable)(iTR))(iAngle)) break ;
1458 }
1459 angle = GetAngleXTR(iTR,position,iAngle);
1460 return angle;
1461}
1462
1463////////////////////////////////////////////////////////////////////////
1464//
1465// Returns approximate position of X-ray photon angle at given energy during random sampling
1466// over integral energy distribution
1467
1468G4double G4VXTRenergyLoss::GetAngleXTR( G4int iPlace,
1469 G4double position,
1470 G4int iTransfer )
1471{
1472 G4double x1, x2, y1, y2, result ;
1473
1474 if(iTransfer == 0)
1475 {
1476 result = (*fAngleForEnergyTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ;
1477 }
1478 else
1479 {
1480 y1 = (*(*fAngleForEnergyTable)(iPlace))(iTransfer-1) ;
1481 y2 = (*(*fAngleForEnergyTable)(iPlace))(iTransfer) ;
1482
1483 x1 = (*fAngleForEnergyTable)(iPlace)->GetLowEdgeEnergy(iTransfer-1) ;
1484 x2 = (*fAngleForEnergyTable)(iPlace)->GetLowEdgeEnergy(iTransfer) ;
1485
1486 if ( x1 == x2 ) result = x2 ;
1487 else
1488 {
1489 if ( y1 == y2 ) result = x1 + (x2 - x1)*G4UniformRand() ;
1490 else
1491 {
1492 result = x1 + (position - y1)*(x2 - x1)/(y2 - y1) ;
1493 }
1494 }
1495 }
1496 return result ;
1497}
1498
1499
1500//
1501//
1502///////////////////////////////////////////////////////////////////////
1503
Note: See TracBrowser for help on using the repository browser.