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