ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4AdjointBremsstrahlungModel.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4AdjointBremsstrahlungModel.cc
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 #include "G4AdjointCSManager.hh"
29 
30 #include "G4PhysicalConstants.hh"
31 #include "G4SystemOfUnits.hh"
32 
33 #include "G4Integrator.hh"
34 #include "G4TrackStatus.hh"
35 #include "G4ParticleChange.hh"
36 #include "G4AdjointElectron.hh"
37 #include "G4AdjointGamma.hh"
38 #include "G4Electron.hh"
39 #include "G4Timer.hh"
40 #include "G4SeltzerBergerModel.hh"
41 
42 
44 //
46  G4VEmAdjointModel("AdjointeBremModel")
47 {
48  SetUseMatrix(false);
50 
51  theDirectStdBremModel = aModel;
56  G4Region* r=0;
58 
59  SetApplyCutInRange(true);
60  highKinEnergy= 1.*GeV;
61  lowKinEnergy = 1.0*keV;
62 
63  lastCZ =0.;
64 
65 
70 
71 
73 
74 
75 }
77 //
79  G4VEmAdjointModel("AdjointeBremModel")
80 {
81  SetUseMatrix(false);
83 
89  G4Region* r=0;
91  // theDirectPenelopeBremModel =0;
92  SetApplyCutInRange(true);
93  highKinEnergy= 1.*GeV;
94  lowKinEnergy = 1.0*keV;
95  lastCZ =0.;
100 }
102 //
106 }
107 
109 //
111  G4bool IsScatProjToProjCase,
112  G4ParticleChange* fParticleChange)
113 {
114  if (!UseMatrix) return RapidSampleSecondaries(aTrack,IsScatProjToProjCase,fParticleChange);
115 
116  const G4DynamicParticle* theAdjointPrimary =aTrack.GetDynamicParticle();
118 
119 
120  G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
121  G4double adjointPrimTotalEnergy = theAdjointPrimary->GetTotalEnergy();
122 
123  if (adjointPrimKinEnergy>HighEnergyLimit*0.999){
124  return;
125  }
126 
127  G4double projectileKinEnergy = SampleAdjSecEnergyFromCSMatrix(adjointPrimKinEnergy,
128  IsScatProjToProjCase);
129  //Weight correction
130  //-----------------------
131  CorrectPostStepWeight(fParticleChange,
132  aTrack.GetWeight(),
133  adjointPrimKinEnergy,
134  projectileKinEnergy,
135  IsScatProjToProjCase);
136 
137 
138  //Kinematic
139  //---------
141  G4double projectileTotalEnergy = projectileM0+projectileKinEnergy;
142  G4double projectileP2 = projectileTotalEnergy*projectileTotalEnergy - projectileM0*projectileM0;
143  G4double projectileP = std::sqrt(projectileP2);
144 
145 
146  //Angle of the gamma direction with the projectile taken from G4eBremsstrahlungModel
147  //------------------------------------------------
148  G4double u;
149  const G4double a1 = 0.625 , a2 = 3.*a1 , d = 27. ;
150 
151  if (9./(9.+d) > G4UniformRand()) u = - std::log(G4UniformRand()*G4UniformRand())/a1;
152  else u = - std::log(G4UniformRand()*G4UniformRand())/a2;
153 
154  G4double theta = u*electron_mass_c2/projectileTotalEnergy;
155 
156  G4double sint = std::sin(theta);
157  G4double cost = std::cos(theta);
158 
160 
161  G4ThreeVector projectileMomentum;
162  projectileMomentum=G4ThreeVector(std::cos(phi)*sint,std::sin(phi)*sint,cost)*projectileP; //gamma frame
163  if (IsScatProjToProjCase) {//the adjoint primary is the scattered e-
164  G4ThreeVector gammaMomentum = (projectileTotalEnergy-adjointPrimTotalEnergy)*G4ThreeVector(0.,0.,1.);
165  G4ThreeVector dirProd=projectileMomentum-gammaMomentum;
166  G4double cost1 = std::cos(dirProd.angle(projectileMomentum));
167  G4double sint1 = std::sqrt(1.-cost1*cost1);
168  projectileMomentum=G4ThreeVector(std::cos(phi)*sint1,std::sin(phi)*sint1,cost1)*projectileP;
169 
170  }
171 
172  projectileMomentum.rotateUz(theAdjointPrimary->GetMomentumDirection());
173 
174 
175 
176  if (!IsScatProjToProjCase ){ //kill the primary and add a secondary
177  fParticleChange->ProposeTrackStatus(fStopAndKill);
178  fParticleChange->AddSecondary(new G4DynamicParticle(theAdjEquivOfDirectPrimPartDef,projectileMomentum));
179  }
180  else {
181  fParticleChange->ProposeEnergy(projectileKinEnergy);
182  fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
183 
184  }
185 }
187 //
189  G4bool IsScatProjToProjCase,
190  G4ParticleChange* fParticleChange)
191 {
192 
193  const G4DynamicParticle* theAdjointPrimary =aTrack.GetDynamicParticle();
195 
196 
197  G4double adjointPrimKinEnergy = theAdjointPrimary->GetKineticEnergy();
198  G4double adjointPrimTotalEnergy = theAdjointPrimary->GetTotalEnergy();
199 
200  if (adjointPrimKinEnergy>HighEnergyLimit*0.999){
201  return;
202  }
203 
204  G4double projectileKinEnergy =0.;
205  G4double gammaEnergy=0.;
206  G4double diffCSUsed=0.;
207  if (!IsScatProjToProjCase){
208  gammaEnergy=adjointPrimKinEnergy;
209  G4double Emax = GetSecondAdjEnergyMaxForProdToProjCase(adjointPrimKinEnergy);
210  G4double Emin= GetSecondAdjEnergyMinForProdToProjCase(adjointPrimKinEnergy);;
211  if (Emin>=Emax) return;
212  projectileKinEnergy=Emin*std::pow(Emax/Emin,G4UniformRand());
213  diffCSUsed=CS_biasing_factor*lastCZ/projectileKinEnergy;
214 
215  }
216  else { G4double Emax = GetSecondAdjEnergyMaxForScatProjToProjCase(adjointPrimKinEnergy);
218  if (Emin>=Emax) return;
219  G4double f1=(Emin-adjointPrimKinEnergy)/Emin;
220  G4double f2=(Emax-adjointPrimKinEnergy)/Emax/f1;
221  projectileKinEnergy=adjointPrimKinEnergy/(1.-f1*std::pow(f2,G4UniformRand()));
222  gammaEnergy=projectileKinEnergy-adjointPrimKinEnergy;
223  diffCSUsed=lastCZ*adjointPrimKinEnergy/projectileKinEnergy/gammaEnergy;
224 
225  }
226 
227 
228 
229 
230  //Weight correction
231  //-----------------------
232  //First w_corr is set to the ratio between adjoint total CS and fwd total CS
233  //if this has to be done in the model
234  //For the case of forced interaction this will be done in the PostStepDoIt of the
235  //forced interaction
236  //It is important to set the weight before the vreation of the secondary
237  //
241  }
242  //G4cout<<"Correction factor start in brem model "<<w_corr<<std::endl;
243 
244 
245  //Then another correction is needed due to the fact that a biaised differential CS has been used rather than the one consistent with the direct model
246  //Here we consider the true diffCS as the one obtained by the numericla differentiation over Tcut of the direct CS, corrected by the Migdal term.
247  //Basically any other differential CS diffCS could be used here (example Penelope).
248 
249  G4double diffCS = DiffCrossSectionPerVolumePrimToSecond(currentMaterial, projectileKinEnergy, gammaEnergy);
250  /*G4cout<<"diffCS "<<diffCS <<std::endl;
251  G4cout<<"diffCS_Used "<<diffCSUsed <<std::endl;*/
252  w_corr*=diffCS/diffCSUsed;
253 
254 
255  G4double new_weight = aTrack.GetWeight()*w_corr;
256  /*G4cout<<"New weight brem "<<new_weight<<std::endl;
257  G4cout<<"Weight correction brem "<<w_corr<<std::endl;*/
258  fParticleChange->SetParentWeightByProcess(false);
259  fParticleChange->SetSecondaryWeightByProcess(false);
260  fParticleChange->ProposeParentWeight(new_weight);
261 
262  //Kinematic
263  //---------
265  G4double projectileTotalEnergy = projectileM0+projectileKinEnergy;
266  G4double projectileP2 = projectileTotalEnergy*projectileTotalEnergy - projectileM0*projectileM0;
267  G4double projectileP = std::sqrt(projectileP2);
268 
269 
270  //Use the angular model of the forward model to generate the gamma direction
271  //---------------------------------------------------------------------------
272 //Dum dynamic particle to use the model
273  G4DynamicParticle * aDynPart = new G4DynamicParticle(G4Electron::Electron(),G4ThreeVector(0.,0.,1.)*projectileP);
274 
275  //Get the element from the direct model
277  projectileKinEnergy,currentTcutForDirectSecond);
278  G4int Z=elm->GetZasInt();
279  G4double energy = aDynPart->GetTotalEnergy()-gammaEnergy;
280  G4ThreeVector projectileMomentum =
281  theDirectEMModel->GetAngularDistribution()->SampleDirection(aDynPart,energy,Z,currentMaterial)*projectileP;
282  G4double phi = projectileMomentum.getPhi();
283 
284 /*
285  //Angle of the gamma direction with the projectile taken from G4eBremsstrahlungModel
286  //------------------------------------------------
287  G4double u;
288  const G4double a1 = 0.625 , a2 = 3.*a1 , d = 27. ;
289 
290  if (9./(9.+d) > G4UniformRand()) u = - std::log(G4UniformRand()*G4UniformRand())/a1;
291  else u = - std::log(G4UniformRand()*G4UniformRand())/a2;
292 
293  G4double theta = u*electron_mass_c2/projectileTotalEnergy;
294 
295  G4double sint = std::sin(theta);
296  G4double cost = std::cos(theta);
297 
298  G4double phi = twopi * G4UniformRand() ;
299  G4ThreeVector projectileMomentum;
300  projectileMomentum=G4ThreeVector(std::cos(phi)*sint,std::sin(phi)*sint,cost)*projectileP; //gamma frame
301 */
302  if (IsScatProjToProjCase) {//the adjoint primary is the scattered e-
303  G4ThreeVector gammaMomentum = (projectileTotalEnergy-adjointPrimTotalEnergy)*G4ThreeVector(0.,0.,1.);
304  G4ThreeVector dirProd=projectileMomentum-gammaMomentum;
305  G4double cost1 = std::cos(dirProd.angle(projectileMomentum));
306  G4double sint1 = std::sqrt(1.-cost1*cost1);
307  projectileMomentum=G4ThreeVector(std::cos(phi)*sint1,std::sin(phi)*sint1,cost1)*projectileP;
308  }
309 
310  projectileMomentum.rotateUz(theAdjointPrimary->GetMomentumDirection());
311 
312  if (!IsScatProjToProjCase ){ //kill the primary and add a secondary
313  fParticleChange->ProposeTrackStatus(fStopAndKill);
314  fParticleChange->AddSecondary(new G4DynamicParticle(theAdjEquivOfDirectPrimPartDef,projectileMomentum));
315  }
316  else {
317  fParticleChange->ProposeEnergy(projectileKinEnergy);
318  fParticleChange->ProposeMomentumDirection(projectileMomentum.unit());
319  }
320 }
322 //
324  G4double kinEnergyProj, // kinetic energy of the primary particle before the interaction
325  G4double kinEnergyProd // kinetic energy of the secondary particle
326  )
330  }
331 /*
332  return DiffCrossSectionPerVolumePrimToSecondApproximated2(aMaterial,
333  kinEnergyProj,
334  kinEnergyProd);
335 */
337  kinEnergyProj,
338  kinEnergyProd);
339 }
340 
342 //
344  const G4Material* aMaterial,
345  G4double kinEnergyProj, // kinetic energy of the primary particle before the interaction
346  G4double kinEnergyProd // kinetic energy of the secondary particle
347  )
348 {
349  G4double dCrossEprod=0.;
350  G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProjCase(kinEnergyProd);
351  G4double Emin_proj = GetSecondAdjEnergyMinForProdToProjCase(kinEnergyProd);
352 
353 
354  //In this approximation we consider that the secondary gammas are sampled with 1/Egamma energy distribution
355  //This is what is applied in the discrete standard model before the rejection test that make a correction
356  //The application of the same rejection function is not possible here.
357  //The differentiation of the CS over Ecut does not produce neither a good differential CS. That is due to the
358  // fact that in the discrete model the differential CS and the integrated CS are both fitted but separatly and
359  // therefore do not allow a correct numerical differentiation of the integrated CS to get the differential one.
360  // In the future we plan to use the brem secondary spectra from the G4Penelope implementation
361 
362  if (kinEnergyProj>Emin_proj && kinEnergyProj<=Emax_proj){
364  dCrossEprod=sigma/kinEnergyProd/std::log(kinEnergyProj/keV);
365  }
366  return dCrossEprod;
367 
368 }
369 
371 //
373  const G4Material* material,
374  G4double kinEnergyProj, // kinetic energy of the primary particle before the interaction
375  G4double kinEnergyProd // kinetic energy of the secondary particle
376  )
377 {
378  //In this approximation we derive the direct cross section over Tcut=gamma energy, en after apply the Migdla correction factor
379  //used in the direct model
380 
381  G4double dCrossEprod=0.;
382 
383  const G4ElementVector* theElementVector = material->GetElementVector();
384  const double* theAtomNumDensityVector = material->GetAtomicNumDensityVector();
385  G4double dum=0.;
386  G4double E1=kinEnergyProd,E2=kinEnergyProd*1.001;
387  G4double dE=E2-E1;
388  for (size_t i=0; i<material->GetNumberOfElements(); i++) {
389  G4double C1=theDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,kinEnergyProj,(*theElementVector)[i]->GetZ(),dum ,E1);
390  G4double C2=theDirectEMModel->ComputeCrossSectionPerAtom(theDirectPrimaryPartDef,kinEnergyProj,(*theElementVector)[i]->GetZ(),dum,E2);
391  dCrossEprod += theAtomNumDensityVector[i] * (C1-C2)/dE;
392  }
393 
394  return dCrossEprod;
395 
396 }
398 //
400  G4double primEnergy,
401  G4bool IsScatProjToProjCase)
402 { if (!isDirectModelInitialised) {
405  }
406  if (UseMatrix) return G4VEmAdjointModel::AdjointCrossSection(aCouple,primEnergy,IsScatProjToProjCase);
407  DefineCurrentMaterial(aCouple);
408  G4double Cross=0.;
409  lastCZ=theDirectEMModel->CrossSectionPerVolume(aCouple->GetMaterial(),theDirectPrimaryPartDef,100.*MeV,100.*MeV/std::exp(1.));//this give the constant above
410 
411  if (!IsScatProjToProjCase ){
412  G4double Emax_proj = GetSecondAdjEnergyMaxForProdToProjCase(primEnergy);
413  G4double Emin_proj = GetSecondAdjEnergyMinForProdToProjCase(primEnergy);
414  if (Emax_proj>Emin_proj && primEnergy > currentTcutForDirectSecond) Cross= CS_biasing_factor*lastCZ*std::log(Emax_proj/Emin_proj);
415  }
416  else {
419  if (Emax_proj>Emin_proj) Cross= lastCZ*std::log((Emax_proj-primEnergy)*Emin_proj/Emax_proj/(Emin_proj-primEnergy));
420 
421  }
422  return Cross;
423 }
424 
426  G4double primEnergy,
427  G4bool IsScatProjToProjCase)
428 {
429  return AdjointCrossSection(aCouple, primEnergy,IsScatProjToProjCase);
430  lastCZ=theDirectEMModel->CrossSectionPerVolume(aCouple->GetMaterial(),theDirectPrimaryPartDef,100.*MeV,100.*MeV/std::exp(1.));//this give the constant above
431  return G4VEmAdjointModel::GetAdjointCrossSection(aCouple, primEnergy,IsScatProjToProjCase);
432 
433 }
434 
435 
436