Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/electromagnetic/adjoint/src/G4VEmAdjointModel.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 #include "G4VEmAdjointModel.hh"
 28 
 29 #include "G4AdjointCSManager.hh"
 30 #include "G4AdjointElectron.hh"
 31 #include "G4AdjointGamma.hh"
 32 #include "G4AdjointInterpolator.hh"
 33 #include "G4AdjointPositron.hh"
 34 #include "G4Electron.hh"
 35 #include "G4Gamma.hh"
 36 #include "G4Integrator.hh"
 37 #include "G4ParticleChange.hh"
 38 #include "G4ProductionCutsTable.hh"
 39 #include "G4TrackStatus.hh"
 40 
 41 ////////////////////////////////////////////////////////////////////////////////
 42 G4VEmAdjointModel::G4VEmAdjointModel(const G4String& nam)
 43   : fName(nam)
 44 {
 45   fCSManager = G4AdjointCSManager::GetAdjointCSManager();
 46   fCSManager->RegisterEmAdjointModel(this);
 47 }
 48 
 49 ///////////////////////////////////e////////////////////////////////////////////
 50 G4VEmAdjointModel::~G4VEmAdjointModel()
 51 {
 52   delete fCSMatrixProdToProjBackScat;
 53   fCSMatrixProdToProjBackScat = nullptr;
 54 
 55   delete fCSMatrixProjToProjBackScat;
 56   fCSMatrixProjToProjBackScat = nullptr;
 57 }
 58 
 59 ////////////////////////////////////////////////////////////////////////////////
 60 G4double G4VEmAdjointModel::AdjointCrossSection(
 61   const G4MaterialCutsCouple* aCouple, G4double primEnergy,
 62   G4bool isScatProjToProj)
 63 {
 64   DefineCurrentMaterial(aCouple);
 65   fPreStepEnergy = primEnergy;
 66 
 67   std::vector<G4double>* CS_Vs_Element = &fElementCSProdToProj;
 68   if(isScatProjToProj)
 69     CS_Vs_Element = &fElementCSScatProjToProj;
 70   fLastCS =
 71     fCSManager->ComputeAdjointCS(fCurrentMaterial, this, primEnergy,
 72                                  fTcutSecond, isScatProjToProj, *CS_Vs_Element);
 73   if(isScatProjToProj)
 74     fLastAdjointCSForScatProjToProj = fLastCS;
 75   else
 76     fLastAdjointCSForProdToProj = fLastCS;
 77 
 78   return fLastCS;
 79 }
 80 
 81 ////////////////////////////////////////////////////////////////////////////////
 82 G4double G4VEmAdjointModel::DiffCrossSectionPerAtomPrimToSecond(
 83   G4double kinEnergyProj, G4double kinEnergyProd, G4double Z, G4double A)
 84 {
 85   G4double dSigmadEprod = 0.;
 86   G4double Emax_proj    = GetSecondAdjEnergyMaxForProdToProj(kinEnergyProd);
 87   G4double Emin_proj    = GetSecondAdjEnergyMinForProdToProj(kinEnergyProd);
 88 
 89   // the produced particle should have a kinetic energy less than the projectile
 90   if(kinEnergyProj > Emin_proj && kinEnergyProj <= Emax_proj)
 91   {
 92     G4double E1     = kinEnergyProd;
 93     G4double E2     = kinEnergyProd * 1.000001;
 94     G4double sigma1 = fDirectModel->ComputeCrossSectionPerAtom(
 95       fDirectPrimaryPart, kinEnergyProj, Z, A, E1, 1.e20);
 96     G4double sigma2 = fDirectModel->ComputeCrossSectionPerAtom(
 97       fDirectPrimaryPart, kinEnergyProj, Z, A, E2, 1.e20);
 98 
 99     dSigmadEprod = (sigma1 - sigma2) / (E2 - E1);
100   }
101   return dSigmadEprod;
102 }
103 
104 ////////////////////////////////////////////////////////////////////////////////
105 G4double G4VEmAdjointModel::DiffCrossSectionPerAtomPrimToScatPrim(
106   G4double kinEnergyProj, G4double kinEnergyScatProj, G4double Z, G4double A)
107 {
108   G4double kinEnergyProd = kinEnergyProj - kinEnergyScatProj;
109   G4double dSigmadEprod;
110   if(kinEnergyProd <= 0.)
111     dSigmadEprod = 0.;
112   else
113     dSigmadEprod =
114       DiffCrossSectionPerAtomPrimToSecond(kinEnergyProj, kinEnergyProd, Z, A);
115   return dSigmadEprod;
116 }
117 
118 ////////////////////////////////////////////////////////////////////////////////
119 G4double G4VEmAdjointModel::DiffCrossSectionPerVolumePrimToSecond(
120   const G4Material* aMaterial, G4double kinEnergyProj, G4double kinEnergyProd)
121 {
122   G4double dSigmadEprod = 0.;
123   G4double Emax_proj    = GetSecondAdjEnergyMaxForProdToProj(kinEnergyProd);
124   G4double Emin_proj    = GetSecondAdjEnergyMinForProdToProj(kinEnergyProd);
125 
126   if(kinEnergyProj > Emin_proj && kinEnergyProj <= Emax_proj)
127   {
128     G4double E1     = kinEnergyProd;
129     G4double E2     = kinEnergyProd * 1.0001;
130     G4double sigma1 = fDirectModel->CrossSectionPerVolume(
131       aMaterial, fDirectPrimaryPart, kinEnergyProj, E1, 1.e20);
132     G4double sigma2 = fDirectModel->CrossSectionPerVolume(
133       aMaterial, fDirectPrimaryPart, kinEnergyProj, E2, 1.e20);
134     dSigmadEprod = (sigma1 - sigma2) / (E2 - E1);
135   }
136   return dSigmadEprod;
137 }
138 
139 ////////////////////////////////////////////////////////////////////////////////
140 G4double G4VEmAdjointModel::DiffCrossSectionPerVolumePrimToScatPrim(
141   const G4Material* aMaterial, G4double kinEnergyProj,
142   G4double kinEnergyScatProj)
143 {
144   G4double kinEnergyProd = kinEnergyProj - kinEnergyScatProj;
145   G4double dSigmadEprod;
146   if(kinEnergyProd <= 0.)
147     dSigmadEprod = 0.;
148   else
149     dSigmadEprod = DiffCrossSectionPerVolumePrimToSecond(
150       aMaterial, kinEnergyProj, kinEnergyProd);
151   return dSigmadEprod;
152 }
153 
154 ////////////////////////////////////////////////////////////////////////////////
155 G4double G4VEmAdjointModel::DiffCrossSectionFunction1(G4double kinEnergyProj)
156 {
157   G4double bias_factor =
158     fCsBiasingFactor * fKinEnergyProdForIntegration / kinEnergyProj;
159 
160   if(fUseMatrixPerElement)
161   {
162     return DiffCrossSectionPerAtomPrimToSecond(
163              kinEnergyProj, fKinEnergyProdForIntegration, fZSelectedNucleus,
164              fASelectedNucleus) *
165            bias_factor;
166   }
167   else
168   {
169     return DiffCrossSectionPerVolumePrimToSecond(
170              fSelectedMaterial, kinEnergyProj, fKinEnergyProdForIntegration) *
171            bias_factor;
172   }
173 }
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 G4double G4VEmAdjointModel::DiffCrossSectionFunction2(G4double kinEnergyProj)
177 {
178   G4double bias_factor =
179     fCsBiasingFactor * fKinEnergyScatProjForIntegration / kinEnergyProj;
180   if(fUseMatrixPerElement)
181   {
182     return DiffCrossSectionPerAtomPrimToScatPrim(
183              kinEnergyProj, fKinEnergyScatProjForIntegration, fZSelectedNucleus,
184              fASelectedNucleus) *
185            bias_factor;
186   }
187   else
188   {
189     return DiffCrossSectionPerVolumePrimToScatPrim(
190              fSelectedMaterial, kinEnergyProj,
191              fKinEnergyScatProjForIntegration) *
192            bias_factor;
193   }
194 }
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 std::vector<std::vector<G4double>*>
198 G4VEmAdjointModel::ComputeAdjointCrossSectionVectorPerAtomForSecond(
199   G4double kinEnergyProd, G4double Z, G4double A,
200   G4int nbin_pro_decade)  // nb bins per order of magnitude of energy
201 {
202   G4Integrator<G4VEmAdjointModel, G4double (G4VEmAdjointModel::*)(G4double)>
203     integral;
204   fASelectedNucleus            = G4lrint(A);
205   fZSelectedNucleus            = G4lrint(Z);
206   fKinEnergyProdForIntegration = kinEnergyProd;
207 
208   // compute the vector of integrated cross sections
209   G4double minEProj = GetSecondAdjEnergyMinForProdToProj(kinEnergyProd);
210   G4double maxEProj = GetSecondAdjEnergyMaxForProdToProj(kinEnergyProd);
211   G4double E1       = minEProj;
212   std::vector<G4double>* log_ESec_vector = new std::vector<G4double>();
213   std::vector<G4double>* log_Prob_vector = new std::vector<G4double>();
214   log_ESec_vector->push_back(std::log(E1));
215   log_Prob_vector->push_back(-50.);
216 
217   G4double E2 =
218     std::pow(10., G4double(G4int(std::log10(minEProj) * nbin_pro_decade) + 1) /
219                     nbin_pro_decade);
220   G4double fE = std::pow(10., 1. / nbin_pro_decade);
221 
222   if(std::pow(fE, 5.) > (maxEProj / minEProj))
223     fE = std::pow(maxEProj / minEProj, 0.2);
224 
225   G4double int_cross_section = 0.;
226   // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
227   while(E1 < maxEProj * 0.9999999)
228   {
229     int_cross_section +=
230       integral.Simpson(this, &G4VEmAdjointModel::DiffCrossSectionFunction1, E1,
231                        std::min(E2, maxEProj * 0.99999999), 5);
232     log_ESec_vector->push_back(std::log(std::min(E2, maxEProj)));
233     log_Prob_vector->push_back(std::log(int_cross_section));
234     E1 = E2;
235     E2 *= fE;
236   }
237   std::vector<std::vector<G4double>*> res_mat;
238   if(int_cross_section > 0.)
239   {
240     res_mat.push_back(log_ESec_vector);
241     res_mat.push_back(log_Prob_vector);
242   }
243   else {
244   delete  log_ESec_vector;
245   delete  log_Prob_vector;
246   }
247   return res_mat;
248 }
249 
250 /////////////////////////////////////////////////////////////////////////////////////
251 std::vector<std::vector<G4double>*>
252 G4VEmAdjointModel::ComputeAdjointCrossSectionVectorPerAtomForScatProj(
253   G4double kinEnergyScatProj, G4double Z, G4double A,
254   G4int nbin_pro_decade)  // nb bins pro order of magnitude of energy
255 {
256   G4Integrator<G4VEmAdjointModel, G4double (G4VEmAdjointModel::*)(G4double)>
257     integral;
258   fASelectedNucleus                = G4lrint(A);
259   fZSelectedNucleus                = G4lrint(Z);
260   fKinEnergyScatProjForIntegration = kinEnergyScatProj;
261 
262   // compute the vector of integrated cross sections
263   G4double minEProj = GetSecondAdjEnergyMinForScatProjToProj(kinEnergyScatProj);
264   G4double maxEProj = GetSecondAdjEnergyMaxForScatProjToProj(kinEnergyScatProj);
265   G4double dEmax    = maxEProj - kinEnergyScatProj;
266   G4double dEmin    = GetLowEnergyLimit();
267   G4double dE1      = dEmin;
268   G4double dE2      = dEmin;
269 
270   std::vector<G4double>* log_ESec_vector = new std::vector<G4double>();
271   std::vector<G4double>* log_Prob_vector = new std::vector<G4double>();
272   log_ESec_vector->push_back(std::log(dEmin));
273   log_Prob_vector->push_back(-50.);
274   G4int nbins = std::max(G4int(std::log10(dEmax / dEmin)) * nbin_pro_decade, 5);
275   G4double fE = std::pow(dEmax / dEmin, 1. / nbins);
276 
277   G4double int_cross_section = 0.;
278   // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
279   while(dE1 < dEmax * 0.9999999999999)
280   {
281     dE2 = dE1 * fE;
282     int_cross_section +=
283       integral.Simpson(this, &G4VEmAdjointModel::DiffCrossSectionFunction2,
284                        minEProj + dE1, std::min(minEProj + dE2, maxEProj), 5);
285     log_ESec_vector->push_back(std::log(std::min(dE2, maxEProj - minEProj)));
286     log_Prob_vector->push_back(std::log(int_cross_section));
287     dE1 = dE2;
288   }
289 
290   std::vector<std::vector<G4double>*> res_mat;
291   if(int_cross_section > 0.)
292   {
293     res_mat.push_back(log_ESec_vector);
294     res_mat.push_back(log_Prob_vector);
295   }
296   else {
297     delete  log_ESec_vector;
298     delete  log_Prob_vector;
299   }
300 
301   return res_mat;
302 }
303 
304 ////////////////////////////////////////////////////////////////////////////////
305 std::vector<std::vector<G4double>*>
306 G4VEmAdjointModel::ComputeAdjointCrossSectionVectorPerVolumeForSecond(
307   G4Material* aMaterial, G4double kinEnergyProd,
308   G4int nbin_pro_decade)  // nb bins pro order of magnitude of energy
309 {
310   G4Integrator<G4VEmAdjointModel, G4double (G4VEmAdjointModel::*)(G4double)>
311     integral;
312   fSelectedMaterial            = aMaterial;
313   fKinEnergyProdForIntegration = kinEnergyProd;
314 
315   // compute the vector of integrated cross sections
316   G4double minEProj = GetSecondAdjEnergyMinForProdToProj(kinEnergyProd);
317   G4double maxEProj = GetSecondAdjEnergyMaxForProdToProj(kinEnergyProd);
318   G4double E1       = minEProj;
319   std::vector<G4double>* log_ESec_vector = new std::vector<G4double>();
320   std::vector<G4double>* log_Prob_vector = new std::vector<G4double>();
321   log_ESec_vector->push_back(std::log(E1));
322   log_Prob_vector->push_back(-50.);
323 
324   G4double E2 =
325     std::pow(10., G4double(G4int(std::log10(minEProj) * nbin_pro_decade) + 1) /
326                     nbin_pro_decade);
327   G4double fE = std::pow(10., 1. / nbin_pro_decade);
328 
329   if(std::pow(fE, 5.) > (maxEProj / minEProj))
330     fE = std::pow(maxEProj / minEProj, 0.2);
331 
332   G4double int_cross_section = 0.;
333   // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
334   while(E1 < maxEProj * 0.9999999)
335   {
336     int_cross_section +=
337       integral.Simpson(this, &G4VEmAdjointModel::DiffCrossSectionFunction1, E1,
338                        std::min(E2, maxEProj * 0.99999999), 5);
339     log_ESec_vector->push_back(std::log(std::min(E2, maxEProj)));
340     log_Prob_vector->push_back(std::log(int_cross_section));
341     E1 = E2;
342     E2 *= fE;
343   }
344   std::vector<std::vector<G4double>*> res_mat;
345 
346   if(int_cross_section > 0.)
347   {
348     res_mat.push_back(log_ESec_vector);
349     res_mat.push_back(log_Prob_vector);
350   }
351   else {
352     delete  log_ESec_vector;
353     delete  log_Prob_vector;
354   }
355   return res_mat;
356 }
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 std::vector<std::vector<G4double>*>
360 G4VEmAdjointModel::ComputeAdjointCrossSectionVectorPerVolumeForScatProj(
361   G4Material* aMaterial, G4double kinEnergyScatProj,
362   G4int nbin_pro_decade)  // nb bins pro order of magnitude of energy
363 {
364   G4Integrator<G4VEmAdjointModel, G4double (G4VEmAdjointModel::*)(G4double)>
365     integral;
366   fSelectedMaterial                = aMaterial;
367   fKinEnergyScatProjForIntegration = kinEnergyScatProj;
368 
369   // compute the vector of integrated cross sections
370   G4double minEProj = GetSecondAdjEnergyMinForScatProjToProj(kinEnergyScatProj);
371   G4double maxEProj = GetSecondAdjEnergyMaxForScatProjToProj(kinEnergyScatProj);
372 
373   G4double dEmax = maxEProj - kinEnergyScatProj;
374   G4double dEmin = GetLowEnergyLimit();
375   G4double dE1   = dEmin;
376   G4double dE2   = dEmin;
377 
378   std::vector<G4double>* log_ESec_vector = new std::vector<G4double>();
379   std::vector<G4double>* log_Prob_vector = new std::vector<G4double>();
380   log_ESec_vector->push_back(std::log(dEmin));
381   log_Prob_vector->push_back(-50.);
382   G4int nbins = std::max(int(std::log10(dEmax / dEmin)) * nbin_pro_decade, 5);
383   G4double fE = std::pow(dEmax / dEmin, 1. / nbins);
384 
385   G4double int_cross_section = 0.;
386   // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
387   while(dE1 < dEmax * 0.9999999999999)
388   {
389     dE2 = dE1 * fE;
390     int_cross_section +=
391       integral.Simpson(this, &G4VEmAdjointModel::DiffCrossSectionFunction2,
392                        minEProj + dE1, std::min(minEProj + dE2, maxEProj), 5);
393     log_ESec_vector->push_back(std::log(std::min(dE2, maxEProj - minEProj)));
394     log_Prob_vector->push_back(std::log(int_cross_section));
395     dE1 = dE2;
396   }
397 
398   std::vector<std::vector<G4double>*> res_mat;
399   if(int_cross_section > 0.)
400   {
401     res_mat.push_back(log_ESec_vector);
402     res_mat.push_back(log_Prob_vector);
403   }
404   else {
405     delete  log_ESec_vector;
406     delete  log_Prob_vector;
407   }
408 
409   return res_mat;
410 }
411 
412 //////////////////////////////////////////////////////////////////////////////
413 G4double G4VEmAdjointModel::SampleAdjSecEnergyFromCSMatrix(
414   std::size_t MatrixIndex, G4double aPrimEnergy, G4bool isScatProjToProj)
415 {
416   G4AdjointCSMatrix* theMatrix = (*fCSMatrixProdToProjBackScat)[MatrixIndex];
417   if(isScatProjToProj)
418     theMatrix = (*fCSMatrixProjToProjBackScat)[MatrixIndex];
419   std::vector<G4double>* theLogPrimEnergyVector =
420     theMatrix->GetLogPrimEnergyVector();
421 
422   if(theLogPrimEnergyVector->empty())
423   {
424     G4cout << "No data are contained in the given AdjointCSMatrix!" << G4endl;
425     G4cout << "The sampling procedure will be stopped." << G4endl;
426     return 0.;
427   }
428 
429   G4AdjointInterpolator* theInterpolator = G4AdjointInterpolator::GetInstance();
430   G4double aLogPrimEnergy                = std::log(aPrimEnergy);
431   G4int ind = (G4int)theInterpolator->FindPositionForLogVector(
432     aLogPrimEnergy, *theLogPrimEnergyVector);
433 
434   G4double aLogPrimEnergy1, aLogPrimEnergy2;
435   G4double aLogCS1, aLogCS2;
436   G4double log01, log02;
437   std::vector<G4double>* aLogSecondEnergyVector1 = nullptr;
438   std::vector<G4double>* aLogSecondEnergyVector2 = nullptr;
439   std::vector<G4double>* aLogProbVector1         = nullptr;
440   std::vector<G4double>* aLogProbVector2         = nullptr;
441   std::vector<std::size_t>* aLogProbVectorIndex1    = nullptr;
442   std::vector<std::size_t>* aLogProbVectorIndex2    = nullptr;
443 
444   theMatrix->GetData(ind, aLogPrimEnergy1, aLogCS1, log01,
445                      aLogSecondEnergyVector1, aLogProbVector1,
446            aLogProbVectorIndex1 );
447   theMatrix->GetData(ind + 1, aLogPrimEnergy2, aLogCS2, log02,
448                      aLogSecondEnergyVector2, aLogProbVector2,
449                      aLogProbVectorIndex2);
450 
451   if (! (aLogProbVector1 && aLogProbVector2 &&
452            aLogSecondEnergyVector1 && aLogSecondEnergyVector2)){
453    return  0.;
454   }
455 
456   G4double rand_var     = G4UniformRand();
457   G4double log_rand_var = std::log(rand_var);
458   G4double log_Tcut     = std::log(fTcutSecond);
459   G4double Esec         = 0.;
460   G4double log_dE1, log_dE2;
461   G4double log_rand_var1, log_rand_var2;
462   G4double log_E1, log_E2;
463   log_rand_var1 = log_rand_var;
464   log_rand_var2 = log_rand_var;
465 
466   G4double Emin = 0.;
467   G4double Emax = 0.;
468   if(theMatrix->IsScatProjToProj())
469   {  // case where Tcut plays a role
470     Emin = GetSecondAdjEnergyMinForScatProjToProj(aPrimEnergy, fTcutSecond);
471     Emax = GetSecondAdjEnergyMaxForScatProjToProj(aPrimEnergy);
472     G4double dE = 0.;
473     if(Emin < Emax)
474     {
475       if(fApplyCutInRange)
476       {
477         if(fSecondPartSameType && fTcutSecond > aPrimEnergy)
478           return aPrimEnergy;
479 
480         log_rand_var1 = log_rand_var +
481                         theInterpolator->InterpolateForLogVector(
482                           log_Tcut, *aLogSecondEnergyVector1, *aLogProbVector1);
483         log_rand_var2 = log_rand_var +
484                         theInterpolator->InterpolateForLogVector(
485                           log_Tcut, *aLogSecondEnergyVector2, *aLogProbVector2);
486       }
487       log_dE1 = theInterpolator->Interpolate(log_rand_var1, *aLogProbVector1,
488                                              *aLogSecondEnergyVector1, "Lin");
489       log_dE2 = theInterpolator->Interpolate(log_rand_var2, *aLogProbVector2,
490                                              *aLogSecondEnergyVector2, "Lin");
491       dE      = std::exp(theInterpolator->LinearInterpolation(
492         aLogPrimEnergy, aLogPrimEnergy1, aLogPrimEnergy2, log_dE1, log_dE2));
493     }
494 
495     Esec = aPrimEnergy + dE;
496     Esec = std::max(Esec, Emin);
497     Esec = std::min(Esec, Emax);
498   }
499   else
500   {  // Tcut condition is already full-filled
501 
502     log_E1 = theInterpolator->Interpolate(log_rand_var, *aLogProbVector1,
503                                           *aLogSecondEnergyVector1, "Lin");
504     log_E2 = theInterpolator->Interpolate(log_rand_var, *aLogProbVector2,
505                                           *aLogSecondEnergyVector2, "Lin");
506 
507     Esec = std::exp(theInterpolator->LinearInterpolation(
508       aLogPrimEnergy, aLogPrimEnergy1, aLogPrimEnergy2, log_E1, log_E2));
509     Emin = GetSecondAdjEnergyMinForProdToProj(aPrimEnergy);
510     Emax = GetSecondAdjEnergyMaxForProdToProj(aPrimEnergy);
511     Esec = std::max(Esec, Emin);
512     Esec = std::min(Esec, Emax);
513   }
514   return Esec;
515 }
516 
517 //////////////////////////////////////////////////////////////////////////////
518 G4double G4VEmAdjointModel::SampleAdjSecEnergyFromCSMatrix(
519   G4double aPrimEnergy, G4bool isScatProjToProj)
520 {
521   SelectCSMatrix(isScatProjToProj);
522   return SampleAdjSecEnergyFromCSMatrix(fCSMatrixUsed, aPrimEnergy,
523                                         isScatProjToProj);
524 }
525 
526 //////////////////////////////////////////////////////////////////////////////
527 void G4VEmAdjointModel::SelectCSMatrix(G4bool isScatProjToProj)
528 {
529   fCSMatrixUsed = 0;
530   if(!fUseMatrixPerElement)
531     fCSMatrixUsed = fCurrentMaterial->GetIndex();
532   else if(!fOneMatrixForAllElements)
533   {  // Select Material
534     std::vector<G4double>* CS_Vs_Element = &fElementCSScatProjToProj;
535     fLastCS                              = fLastAdjointCSForScatProjToProj;
536     if(!isScatProjToProj)
537     {
538       CS_Vs_Element = &fElementCSProdToProj;
539       fLastCS       = fLastAdjointCSForProdToProj;
540     }
541     G4double SumCS = 0.;
542     std::size_t ind = 0;
543     for(std::size_t i = 0; i < CS_Vs_Element->size(); ++i)
544     {
545       SumCS += (*CS_Vs_Element)[i];
546       if(G4UniformRand() <= SumCS / fLastCS)
547       {
548         ind = i;
549         break;
550       }
551     }
552     fCSMatrixUsed = fCurrentMaterial->GetElement((G4int)ind)->GetIndex();
553   }
554 }
555 
556 //////////////////////////////////////////////////////////////////////////////
557 G4double G4VEmAdjointModel::SampleAdjSecEnergyFromDiffCrossSectionPerAtom(
558   G4double prim_energy, G4bool isScatProjToProj)
559 {
560   // here we try to use the rejection method
561   constexpr G4int iimax = 1000;
562   G4double E            = 0.;
563   G4double x, xmin, greject;
564   if(isScatProjToProj)
565   {
566     G4double Emax = GetSecondAdjEnergyMaxForScatProjToProj(prim_energy);
567     G4double Emin = prim_energy + fTcutSecond;
568     xmin          = Emin / Emax;
569     G4double grejmax =
570       DiffCrossSectionPerAtomPrimToScatPrim(Emin, prim_energy, 1) * prim_energy;
571 
572     G4int ii = 0;
573     do
574     {
575       // q = G4UniformRand();
576       x = 1. / (G4UniformRand() * (1. / xmin - 1.) + 1.);
577       E = x * Emax;
578       greject =
579         DiffCrossSectionPerAtomPrimToScatPrim(E, prim_energy, 1) * prim_energy;
580       ++ii;
581       if(ii >= iimax)
582       {
583         break;
584       }
585     }
586     // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
587     while(greject < G4UniformRand() * grejmax);
588   }
589   else
590   {
591     G4double Emax = GetSecondAdjEnergyMaxForProdToProj(prim_energy);
592     G4double Emin = GetSecondAdjEnergyMinForProdToProj(prim_energy);
593     xmin          = Emin / Emax;
594     G4double grejmax =
595       DiffCrossSectionPerAtomPrimToSecond(Emin, prim_energy, 1);
596     G4int ii = 0;
597     do
598     {
599       x       = std::pow(xmin, G4UniformRand());
600       E       = x * Emax;
601       greject = DiffCrossSectionPerAtomPrimToSecond(E, prim_energy, 1);
602       ++ii;
603       if(ii >= iimax)
604       {
605         break;
606       }
607     }
608     // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
609     while(greject < G4UniformRand() * grejmax);
610   }
611 
612   return E;
613 }
614 
615 ////////////////////////////////////////////////////////////////////////////////
616 void G4VEmAdjointModel::CorrectPostStepWeight(G4ParticleChange* fParticleChange,
617                                               G4double old_weight,
618                                               G4double adjointPrimKinEnergy,
619                                               G4double projectileKinEnergy,
620                                               G4bool isScatProjToProj)
621 {
622   G4double new_weight = old_weight;
623   G4double w_corr =
624     fCSManager->GetPostStepWeightCorrection() / fCsBiasingFactor;
625 
626   fLastCS = fLastAdjointCSForScatProjToProj;
627   if(!isScatProjToProj)
628     fLastCS = fLastAdjointCSForProdToProj;
629   if((adjointPrimKinEnergy - fPreStepEnergy) / fPreStepEnergy > 0.001)
630   {
631     G4double post_stepCS = AdjointCrossSection(
632       fCurrentCouple, adjointPrimKinEnergy, isScatProjToProj);
633     if(post_stepCS > 0. && fLastCS > 0.)
634       w_corr *= post_stepCS / fLastCS;
635   }
636 
637   new_weight *= w_corr;
638   new_weight *= projectileKinEnergy / adjointPrimKinEnergy;
639   // This is needed due to the biasing of diff CS
640   // by the factor adjointPrimKinEnergy/projectileKinEnergy
641 
642   fParticleChange->SetParentWeightByProcess(false);
643   fParticleChange->SetSecondaryWeightByProcess(false);
644   fParticleChange->ProposeParentWeight(new_weight);
645 }
646 
647 //////////////////////////////////////////////////////////////////////////////
648 G4double G4VEmAdjointModel::GetSecondAdjEnergyMaxForScatProjToProj(
649   G4double kinEnergyScatProj)
650 {
651   G4double maxEProj = GetHighEnergyLimit();
652   if(fSecondPartSameType)
653     maxEProj = std::min(kinEnergyScatProj * 2., maxEProj);
654   return maxEProj;
655 }
656 
657 //////////////////////////////////////////////////////////////////////////////
658 G4double G4VEmAdjointModel::GetSecondAdjEnergyMinForScatProjToProj(
659   G4double primAdjEnergy, G4double tcut)
660 {
661   G4double Emin = primAdjEnergy;
662   if(fApplyCutInRange)
663     Emin += tcut;
664   return Emin;
665 }
666 
667 //////////////////////////////////////////////////////////////////////////////
668 G4double G4VEmAdjointModel::GetSecondAdjEnergyMaxForProdToProj(G4double)
669 {
670   return fHighEnergyLimit;
671 }
672 
673 //////////////////////////////////////////////////////////////////////////////
674 G4double G4VEmAdjointModel::GetSecondAdjEnergyMinForProdToProj(
675   G4double primAdjEnergy)
676 {
677   G4double minEProj = primAdjEnergy;
678   if(fSecondPartSameType)
679     minEProj = primAdjEnergy * 2.;
680   return minEProj;
681 }
682 
683 ////////////////////////////////////////////////////////////////////////////////////////////
684 void G4VEmAdjointModel::DefineCurrentMaterial(
685   const G4MaterialCutsCouple* couple)
686 {
687   if(couple != fCurrentCouple)
688   {
689     fCurrentCouple   = const_cast<G4MaterialCutsCouple*>(couple);
690     fCurrentMaterial = const_cast<G4Material*>(couple->GetMaterial());
691     std::size_t idx       = 56;
692     fTcutSecond      = 1.e-11;
693     if(fAdjEquivDirectSecondPart)
694     {
695       if(fAdjEquivDirectSecondPart == G4AdjointGamma::AdjointGamma())
696         idx = 0;
697       else if(fAdjEquivDirectSecondPart == G4AdjointElectron::AdjointElectron())
698         idx = 1;
699       else if(fAdjEquivDirectSecondPart == G4AdjointPositron::AdjointPositron())
700         idx = 2;
701       if(idx < 56)
702       {
703         const std::vector<G4double>* aVec =
704           G4ProductionCutsTable::GetProductionCutsTable()->GetEnergyCutsVector(
705             idx);
706         fTcutSecond = (*aVec)[couple->GetIndex()];
707       }
708     }
709   }
710 }
711 
712 ////////////////////////////////////////////////////////////////////////////////////////////
713 void G4VEmAdjointModel::SetHighEnergyLimit(G4double aVal)
714 {
715   fHighEnergyLimit = aVal;
716   if(fDirectModel)
717     fDirectModel->SetHighEnergyLimit(aVal);
718 }
719 
720 ////////////////////////////////////////////////////////////////////////////////////////////
721 void G4VEmAdjointModel::SetLowEnergyLimit(G4double aVal)
722 {
723   fLowEnergyLimit = aVal;
724   if(fDirectModel)
725     fDirectModel->SetLowEnergyLimit(aVal);
726 }
727 
728 ////////////////////////////////////////////////////////////////////////////////////////////
729 void G4VEmAdjointModel::SetAdjointEquivalentOfDirectPrimaryParticleDefinition(
730   G4ParticleDefinition* aPart)
731 {
732   fAdjEquivDirectPrimPart = aPart;
733   if(fAdjEquivDirectPrimPart->GetParticleName() == "adj_e-")
734     fDirectPrimaryPart = G4Electron::Electron();
735   else if(fAdjEquivDirectPrimPart->GetParticleName() == "adj_gamma")
736     fDirectPrimaryPart = G4Gamma::Gamma();
737 }
738