Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4AdjointBremsstrahlungModel.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
28
29#include "G4AdjointCSManager.hh"
30#include "G4AdjointElectron.hh"
31#include "G4AdjointGamma.hh"
32#include "G4Electron.hh"
33#include "G4EmModelManager.hh"
34#include "G4Gamma.hh"
35#include "G4ParticleChange.hh"
38#include "G4SystemOfUnits.hh"
39#include "G4TrackStatus.hh"
40
41////////////////////////////////////////////////////////////////////////////////
43 : G4VEmAdjointModel("AdjointeBremModel")
44{
45 fDirectModel = aModel;
46 Initialize();
47}
48
49////////////////////////////////////////////////////////////////////////////////
56
57////////////////////////////////////////////////////////////////////////////////
58void G4AdjointBremsstrahlungModel::Initialize()
59{
60 SetUseMatrix(false);
62
63 fEmModelManagerForFwdModels = new G4EmModelManager();
64 fEmModelManagerForFwdModels->AddEmModel(1, fDirectModel, nullptr, nullptr);
66
67 fElectron = G4Electron::Electron();
68 fGamma = G4Gamma::Gamma();
69
72 fDirectPrimaryPart = fElectron;
73 fSecondPartSameType = false;
74
76}
77
78////////////////////////////////////////////////////////////////////////////////
80{
81 if(fEmModelManagerForFwdModels)
82 delete fEmModelManagerForFwdModels;
83}
84
85////////////////////////////////////////////////////////////////////////////////
87 const G4Track& aTrack, G4bool isScatProjToProj,
88 G4ParticleChange* fParticleChange)
89{
90 if(!fUseMatrix)
91 return RapidSampleSecondaries(aTrack, isScatProjToProj, fParticleChange);
92
93 const G4DynamicParticle* theAdjointPrimary = aTrack.GetDynamicParticle();
95
96 G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
97 G4double adjointPrimTotalEnergy = theAdjointPrimary->GetTotalEnergy();
98
99 if(adjointPrimKinEnergy > GetHighEnergyLimit() * 0.999)
100 {
101 return;
102 }
103
104 G4double projectileKinEnergy =
105 SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy, isScatProjToProj);
106
107 // Weight correction
108 CorrectPostStepWeight(fParticleChange, aTrack.GetWeight(),
109 adjointPrimKinEnergy, projectileKinEnergy,
110 isScatProjToProj);
111
112 // Kinematic
114 G4double projectileTotalEnergy = projectileM0 + projectileKinEnergy;
115 G4double projectileP2 =
116 projectileTotalEnergy * projectileTotalEnergy - projectileM0 * projectileM0;
117 G4double projectileP = std::sqrt(projectileP2);
118
119 // Angle of the gamma direction with the projectile taken from
120 // G4eBremsstrahlungModel
121 G4double u;
122 if(0.25 > G4UniformRand())
123 u = -std::log(G4UniformRand() * G4UniformRand()) / 0.625;
124 else
125 u = -std::log(G4UniformRand() * G4UniformRand()) / 1.875;
126
127 G4double theta = u * electron_mass_c2 / projectileTotalEnergy;
128 G4double sint = std::sin(theta);
129 G4double cost = std::cos(theta);
130
131 G4double phi = twopi * G4UniformRand();
132
133 G4ThreeVector projectileMomentum =
134 G4ThreeVector(std::cos(phi) * sint, std::sin(phi) * sint, cost) *
135 projectileP; // gamma frame
136 if(isScatProjToProj)
137 { // the adjoint primary is the scattered e-
138 G4ThreeVector gammaMomentum =
139 (projectileTotalEnergy - adjointPrimTotalEnergy) *
140 G4ThreeVector(0., 0., 1.);
141 G4ThreeVector dirProd = projectileMomentum - gammaMomentum;
142 G4double cost1 = std::cos(dirProd.angle(projectileMomentum));
143 G4double sint1 = std::sqrt(1. - cost1 * cost1);
144 projectileMomentum =
145 G4ThreeVector(std::cos(phi) * sint1, std::sin(phi) * sint1, cost1) *
146 projectileP;
147 }
148
149 projectileMomentum.rotateUz(theAdjointPrimary->GetMomentumDirection());
150
151 if(!isScatProjToProj)
152 { // kill the primary and add a secondary
153 fParticleChange->ProposeTrackStatus(fStopAndKill);
154 fParticleChange->AddSecondary(
155 new G4DynamicParticle(fAdjEquivDirectPrimPart, projectileMomentum));
156 }
157 else
158 {
159 fParticleChange->ProposeEnergy(projectileKinEnergy);
160 fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
161 }
162}
163
164////////////////////////////////////////////////////////////////////////////////
166 const G4Track& aTrack, G4bool isScatProjToProj,
167 G4ParticleChange* fParticleChange)
168{
169 const G4DynamicParticle* theAdjointPrimary = aTrack.GetDynamicParticle();
171
172 G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
173 G4double adjointPrimTotalEnergy = theAdjointPrimary->GetTotalEnergy();
174
175 if(adjointPrimKinEnergy > GetHighEnergyLimit() * 0.999)
176 {
177 return;
178 }
179
180 G4double projectileKinEnergy = 0.;
181 G4double gammaEnergy = 0.;
182 G4double diffCSUsed = 0.;
183 if(!isScatProjToProj)
184 {
185 gammaEnergy = adjointPrimKinEnergy;
186 G4double Emax = GetSecondAdjEnergyMaxForProdToProj(adjointPrimKinEnergy);
187 G4double Emin = GetSecondAdjEnergyMinForProdToProj(adjointPrimKinEnergy);
188 if(Emin >= Emax)
189 return;
190 projectileKinEnergy = Emin * std::pow(Emax / Emin, G4UniformRand());
191 diffCSUsed = fCsBiasingFactor * fLastCZ / projectileKinEnergy;
192 }
193 else
194 {
195 G4double Emax =
196 GetSecondAdjEnergyMaxForScatProjToProj(adjointPrimKinEnergy);
197 G4double Emin =
199 if(Emin >= Emax)
200 return;
201 G4double f1 = (Emin - adjointPrimKinEnergy) / Emin;
202 G4double f2 = (Emax - adjointPrimKinEnergy) / Emax / f1;
203 projectileKinEnergy =
204 adjointPrimKinEnergy / (1. - f1 * std::pow(f2, G4UniformRand()));
205 gammaEnergy = projectileKinEnergy - adjointPrimKinEnergy;
206 diffCSUsed =
207 fLastCZ * adjointPrimKinEnergy / projectileKinEnergy / gammaEnergy;
208 }
209
210 // Weight correction:
211 // First w_corr is set to the ratio between adjoint total CS and fwd total CS
212 // if this has to be done in the model.
213 // For the case of forced interaction this will be done in the PostStepDoIt of
214 // the forced interaction. It is important to set the weight before the
215 // creation of the secondary
218 {
219 w_corr = fCSManager->GetPostStepWeightCorrection();
220 }
221
222 // Then another correction is needed due to the fact that a biaised
223 // differential CS has been used rather than the one consistent with the
224 // direct model Here we consider the true diffCS as the one obtained by the
225 // numerical differentiation over Tcut of the direct CS, corrected by the
226 // Migdal term. Basically any other differential CS could be used here
227 // (example Penelope).
229 fCurrentMaterial, projectileKinEnergy, gammaEnergy);
230 w_corr *= diffCS / diffCSUsed;
231
232 G4double new_weight = aTrack.GetWeight() * w_corr;
233 fParticleChange->SetParentWeightByProcess(false);
234 fParticleChange->SetSecondaryWeightByProcess(false);
235 fParticleChange->ProposeParentWeight(new_weight);
236
237 // Kinematic
239 G4double projectileTotalEnergy = projectileM0 + projectileKinEnergy;
240 G4double projectileP2 =
241 projectileTotalEnergy * projectileTotalEnergy - projectileM0 * projectileM0;
242 G4double projectileP = std::sqrt(projectileP2);
243
244 // Use the angular model of the forward model to generate the gamma direction
245 // Dummy dynamic particle to use the model
246 G4DynamicParticle* aDynPart =
247 new G4DynamicParticle(fElectron, G4ThreeVector(0., 0., 1.) * projectileP);
248
249 // Get the element from the direct model
251 fCurrentCouple, fElectron, projectileKinEnergy, fTcutSecond);
252 G4int Z = elm->GetZasInt();
253 G4double energy = aDynPart->GetTotalEnergy() - gammaEnergy;
254 G4ThreeVector projectileMomentum =
256 fCurrentMaterial) * projectileP;
257 G4double phi = projectileMomentum.getPhi();
258
259 if(isScatProjToProj)
260 { // the adjoint primary is the scattered e-
261 G4ThreeVector gammaMomentum =
262 (projectileTotalEnergy - adjointPrimTotalEnergy) *
263 G4ThreeVector(0., 0., 1.);
264 G4ThreeVector dirProd = projectileMomentum - gammaMomentum;
265 G4double cost1 = std::cos(dirProd.angle(projectileMomentum));
266 G4double sint1 = std::sqrt(1. - cost1 * cost1);
267 projectileMomentum =
268 G4ThreeVector(std::cos(phi) * sint1, std::sin(phi) * sint1, cost1) *
269 projectileP;
270 }
271
272 projectileMomentum.rotateUz(theAdjointPrimary->GetMomentumDirection());
273
274 if(!isScatProjToProj)
275 { // kill the primary and add a secondary
276 fParticleChange->ProposeTrackStatus(fStopAndKill);
277 fParticleChange->AddSecondary(
278 new G4DynamicParticle(fAdjEquivDirectPrimPart, projectileMomentum));
279 }
280 else
281 {
282 fParticleChange->ProposeEnergy(projectileKinEnergy);
283 fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
284 }
285}
286
287////////////////////////////////////////////////////////////////////////////////
289 const G4Material* aMaterial,
290 G4double kinEnergyProj, // kin energy of primary before interaction
291 G4double kinEnergyProd // kinetic energy of the secondary particle
292)
293{
294 if(!fIsDirectModelInitialised)
295 {
296 fEmModelManagerForFwdModels->Initialise(fElectron, fGamma, 0);
297 fIsDirectModelInitialised = true;
298 }
300 aMaterial, kinEnergyProj, kinEnergyProd);
301}
302
303////////////////////////////////////////////////////////////////////////////////
305 const G4MaterialCutsCouple* aCouple, G4double primEnergy,
306 G4bool isScatProjToProj)
307{
308 static constexpr G4double maxEnergy = 100. * MeV / 2.718281828459045;
309 // 2.78.. == std::exp(1.)
310 if(!fIsDirectModelInitialised)
311 {
312 fEmModelManagerForFwdModels->Initialise(fElectron, fGamma, 0);
313 fIsDirectModelInitialised = true;
314 }
315 if(fUseMatrix)
316 return G4VEmAdjointModel::AdjointCrossSection(aCouple, primEnergy,
317 isScatProjToProj);
318 DefineCurrentMaterial(aCouple);
319 G4double Cross = 0.;
320 // this gives the constant above
322 aCouple->GetMaterial(), fDirectPrimaryPart, 100. * MeV, maxEnergy);
323
324 if(!isScatProjToProj)
325 {
326 G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProj(primEnergy);
327 G4double Emin_proj = GetSecondAdjEnergyMinForProdToProj(primEnergy);
328 if(Emax_proj > Emin_proj && primEnergy > fTcutSecond)
329 Cross = fCsBiasingFactor * fLastCZ * std::log(Emax_proj / Emin_proj);
330 }
331 else
332 {
333 G4double Emax_proj = GetSecondAdjEnergyMaxForScatProjToProj(primEnergy);
334 G4double Emin_proj =
336 if(Emax_proj > Emin_proj)
337 Cross = fLastCZ * std::log((Emax_proj - primEnergy) * Emin_proj /
338 Emax_proj / (Emin_proj - primEnergy));
339 }
340 return Cross;
341}
CLHEP::Hep3Vector G4ThreeVector
@ fStopAndKill
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4UniformRand()
Definition Randomize.hh:52
Hep3Vector unit() const
double angle(const Hep3Vector &) const
double getPhi() const
Hep3Vector & rotateUz(const Hep3Vector &)
void SampleSecondaries(const G4Track &aTrack, G4bool isScatProjToProj, G4ParticleChange *fParticleChange) override
G4double DiffCrossSectionPerVolumePrimToSecond(const G4Material *aMaterial, G4double kinEnergyProj, G4double kinEnergyProd) override
G4double AdjointCrossSection(const G4MaterialCutsCouple *aCouple, G4double primEnergy, G4bool isScatProjToProj) override
void RapidSampleSecondaries(const G4Track &aTrack, G4bool isScatProjToProj, G4ParticleChange *fParticleChange)
G4double GetPostStepWeightCorrection()
static G4AdjointCSManager * GetAdjointCSManager()
static G4AdjointElectron * AdjointElectron()
static G4AdjointGamma * AdjointGamma()
const G4ThreeVector & GetMomentumDirection() const
G4double GetKineticEnergy() const
G4double GetTotalEnergy() const
static G4Electron * Electron()
Definition G4Electron.cc:91
G4int GetZasInt() const
Definition G4Element.hh:120
void AddEmModel(G4int, G4VEmModel *, G4VEmFluctuationModel *fm, const G4Region *r)
const G4DataVector * Initialise(const G4ParticleDefinition *part, const G4ParticleDefinition *secPart, G4int verb)
static G4Gamma * Gamma()
Definition G4Gamma.cc:81
const G4Material * GetMaterial() const
void AddSecondary(G4Track *aSecondary)
void ProposeEnergy(G4double finalEnergy)
void ProposeMomentumDirection(G4double Px, G4double Py, G4double Pz)
G4double GetWeight() const
const G4DynamicParticle * GetDynamicParticle() const
const G4MaterialCutsCouple * GetMaterialCutsCouple() const
virtual G4double GetSecondAdjEnergyMaxForProdToProj(G4double primAdjEnergy)
void SetUseMatrixPerElement(G4bool aBool)
G4ParticleDefinition * fAdjEquivDirectSecondPart
void SetUseMatrix(G4bool aBool)
virtual G4double GetSecondAdjEnergyMinForScatProjToProj(G4double primAdjEnergy, G4double tcut=0.)
G4ParticleDefinition * fAdjEquivDirectPrimPart
G4MaterialCutsCouple * fCurrentCouple
virtual G4double GetSecondAdjEnergyMaxForScatProjToProj(G4double primAdjEnergy)
G4Material * fCurrentMaterial
virtual G4double DiffCrossSectionPerVolumePrimToSecond(const G4Material *aMaterial, G4double kinEnergyProj, G4double kinEnergyProd)
virtual void CorrectPostStepWeight(G4ParticleChange *fParticleChange, G4double old_weight, G4double adjointPrimKinEnergy, G4double projectileKinEnergy, G4bool isScatProjToProj)
void DefineCurrentMaterial(const G4MaterialCutsCouple *couple)
virtual G4double AdjointCrossSection(const G4MaterialCutsCouple *aCouple, G4double primEnergy, G4bool isScatProjToProj)
virtual G4double GetSecondAdjEnergyMinForProdToProj(G4double primAdjEnergy)
G4ParticleDefinition * fDirectPrimaryPart
G4double SampleAdjSecEnergyFromCSMatrix(std::size_t MatrixIndex, G4double prim_energy, G4bool isScatProjToProj)
void SetApplyCutInRange(G4bool aBool)
virtual G4ThreeVector & SampleDirection(const G4DynamicParticle *dp, G4double finalTotalEnergy, G4int Z, const G4Material *)=0
G4VEmAngularDistribution * GetAngularDistribution()
virtual G4double CrossSectionPerVolume(const G4Material *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
const G4Element * SelectRandomAtom(const G4MaterialCutsCouple *, const G4ParticleDefinition *, G4double kineticEnergy, G4double cutEnergy=0.0, G4double maxEnergy=DBL_MAX)
void ProposeTrackStatus(G4TrackStatus status)
void SetSecondaryWeightByProcess(G4bool)
void SetParentWeightByProcess(G4bool)
void ProposeParentWeight(G4double finalWeight)