Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/electromagnetic/adjoint/src/G4AdjointCSManager.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 
 28 #include "G4AdjointCSManager.hh"
 29 
 30 #include "G4AdjointCSMatrix.hh"
 31 #include "G4AdjointElectron.hh"
 32 #include "G4AdjointGamma.hh"
 33 #include "G4AdjointInterpolator.hh"
 34 #include "G4AdjointProton.hh"
 35 #include "G4Electron.hh"
 36 #include "G4Element.hh"
 37 #include "G4ElementTable.hh"
 38 #include "G4Gamma.hh"
 39 #include "G4ParticleDefinition.hh"
 40 #include "G4PhysicalConstants.hh"
 41 #include "G4PhysicsLogVector.hh"
 42 #include "G4PhysicsTable.hh"
 43 #include "G4ProductionCutsTable.hh"
 44 #include "G4Proton.hh"
 45 #include "G4SystemOfUnits.hh"
 46 #include "G4VEmAdjointModel.hh"
 47 #include "G4VEmProcess.hh"
 48 #include "G4VEnergyLossProcess.hh"
 49 
 50 G4ThreadLocal G4AdjointCSManager* G4AdjointCSManager::fInstance = nullptr;
 51 
 52 constexpr G4double G4AdjointCSManager::fTmin;
 53 constexpr G4double G4AdjointCSManager::fTmax;
 54 constexpr G4int G4AdjointCSManager::fNbins;
 55 
 56 ///////////////////////////////////////////////////////
 57 G4AdjointCSManager* G4AdjointCSManager::GetAdjointCSManager()
 58 {
 59   if(fInstance == nullptr)
 60   {
 61     static G4ThreadLocalSingleton<G4AdjointCSManager> inst;
 62     fInstance = inst.Instance();
 63   }
 64   return fInstance;
 65 }
 66 
 67 ///////////////////////////////////////////////////////
 68 G4AdjointCSManager::G4AdjointCSManager()
 69 {
 70   RegisterAdjointParticle(G4AdjointElectron::AdjointElectron());
 71   RegisterAdjointParticle(G4AdjointGamma::AdjointGamma());
 72   RegisterAdjointParticle(G4AdjointProton::AdjointProton());
 73 }
 74 
 75 ///////////////////////////////////////////////////////
 76 G4AdjointCSManager::~G4AdjointCSManager()
 77 {
 78   for (auto& p : fAdjointCSMatricesForProdToProj) {
 79     for (auto p1 : p) {
 80       if (p1) {
 81         delete p1;
 82         p1 = nullptr;
 83       }
 84     }
 85     p.clear();
 86   }
 87   fAdjointCSMatricesForProdToProj.clear();
 88 
 89   for (auto& p : fAdjointCSMatricesForScatProjToProj) {
 90     for (auto p1 : p) {
 91       if (p1) {
 92         delete p1;
 93         p1 = nullptr;
 94       }
 95     }
 96     p.clear();
 97   }
 98   fAdjointCSMatricesForScatProjToProj.clear();
 99 
100   for (auto p : fAdjointModels) {
101     if (p) {
102       delete p;
103       p = nullptr;
104     }
105   }
106   fAdjointModels.clear();
107 
108   for (auto p : fTotalAdjSigmaTable) {
109     p->clearAndDestroy();
110     delete p;
111     p = nullptr;
112   }
113   fTotalAdjSigmaTable.clear();
114 
115   for (auto p : fSigmaTableForAdjointModelScatProjToProj) {
116     p->clearAndDestroy();
117     delete p;
118     p = nullptr;
119   }
120   fSigmaTableForAdjointModelScatProjToProj.clear();
121 
122   for (auto p : fSigmaTableForAdjointModelProdToProj) {
123     p->clearAndDestroy();
124     delete p;
125     p = nullptr;
126   }
127   fSigmaTableForAdjointModelProdToProj.clear();
128 
129   for (auto p : fTotalFwdSigmaTable) {
130     p->clearAndDestroy();
131     delete p;
132     p = nullptr;
133   }
134   fTotalFwdSigmaTable.clear();
135 
136   for (auto p : fForwardProcesses) {
137     delete p;
138     p = nullptr;
139   }
140   fForwardProcesses.clear();
141 
142   for (auto p : fForwardLossProcesses) {
143     delete p;
144     p = nullptr;
145   }
146   fForwardLossProcesses.clear();
147 }
148 
149 ///////////////////////////////////////////////////////
150 std::size_t G4AdjointCSManager::RegisterEmAdjointModel(G4VEmAdjointModel* aModel)
151 {
152   fAdjointModels.push_back(aModel);
153   fSigmaTableForAdjointModelScatProjToProj.push_back(new G4PhysicsTable);
154   fSigmaTableForAdjointModelProdToProj.push_back(new G4PhysicsTable);
155   return fAdjointModels.size() - 1;
156 }
157 
158 ///////////////////////////////////////////////////////
159 void G4AdjointCSManager::RegisterEmProcess(G4VEmProcess* aProcess,
160                                            G4ParticleDefinition* aFwdPartDef)
161 {
162   G4ParticleDefinition* anAdjPartDef =
163     GetAdjointParticleEquivalent(aFwdPartDef);
164   if(anAdjPartDef && aProcess)
165   {
166     RegisterAdjointParticle(anAdjPartDef);
167 
168     for(std::size_t i = 0; i < fAdjointParticlesInAction.size(); ++i)
169     {
170       if(anAdjPartDef->GetParticleName() ==
171          fAdjointParticlesInAction[i]->GetParticleName())
172         fForwardProcesses[i]->push_back(aProcess);
173     }
174   }
175 }
176 
177 ///////////////////////////////////////////////////////
178 void G4AdjointCSManager::RegisterEnergyLossProcess(
179   G4VEnergyLossProcess* aProcess, G4ParticleDefinition* aFwdPartDef)
180 {
181   G4ParticleDefinition* anAdjPartDef =
182     GetAdjointParticleEquivalent(aFwdPartDef);
183   if(anAdjPartDef && aProcess)
184   {
185     RegisterAdjointParticle(anAdjPartDef);
186     for(std::size_t i = 0; i < fAdjointParticlesInAction.size(); ++i)
187     {
188       if(anAdjPartDef->GetParticleName() ==
189          fAdjointParticlesInAction[i]->GetParticleName())
190                               fForwardLossProcesses[i]->push_back(aProcess);
191 
192     }
193   }
194 }
195 
196 ///////////////////////////////////////////////////////
197 void G4AdjointCSManager::RegisterAdjointParticle(G4ParticleDefinition* aPartDef)
198 {
199   G4bool found = false;
200   for(auto p : fAdjointParticlesInAction)
201   {
202     if(p->GetParticleName() == aPartDef->GetParticleName())
203     {
204       found = true;
205     }
206   }
207   if(!found)
208   {
209     fForwardLossProcesses.push_back(new std::vector<G4VEnergyLossProcess*>());
210     fTotalFwdSigmaTable.push_back(new G4PhysicsTable);
211     fTotalAdjSigmaTable.push_back(new G4PhysicsTable);
212     fForwardProcesses.push_back(new std::vector<G4VEmProcess*>());
213     fAdjointParticlesInAction.push_back(aPartDef);
214     fEminForFwdSigmaTables.push_back(std::vector<G4double>());
215     fEminForAdjSigmaTables.push_back(std::vector<G4double>());
216     fEkinofFwdSigmaMax.push_back(std::vector<G4double>());
217     fEkinofAdjSigmaMax.push_back(std::vector<G4double>());
218   }
219 }
220 
221 ///////////////////////////////////////////////////////
222 void G4AdjointCSManager::BuildCrossSectionMatrices()
223 {
224   if(fCSMatricesBuilt)
225     return;
226   // The Tcut and Tmax matrices will be computed probably just once.
227   // When Tcut changes, some PhysicsTable will be recomputed
228   // for each MaterialCutCouple but not all the matrices.
229   // The Tcut defines a lower limit in the energy of the projectile before
230   // scattering. In the Projectile to Scattered Projectile case we have
231   //      E_ScatProj<E_Proj-Tcut
232   // Therefore in the adjoint case we have
233   //      Eproj> E_ScatProj+Tcut
234   // This implies that when computing the adjoint CS we should integrate over
235   // Epro from E_ScatProj+Tcut to Emax
236   // In the Projectile to Secondary case Tcut plays a role only in the fact that
237   // Esecond should be greater than Tcut to have the possibility to have any
238   // adjoint process.
239   // To avoid recomputing matrices for all changes of MaterialCutCouple,
240   // we propose to compute the matrices only once for the minimum possible Tcut
241   // and then to interpolate the probability for a new Tcut (implemented in
242   // G4VAdjointEmModel)
243 
244   fAdjointCSMatricesForScatProjToProj.clear();
245   fAdjointCSMatricesForProdToProj.clear();
246   const G4ElementTable* theElementTable   = G4Element::GetElementTable();
247   const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable();
248 
249   G4cout << "========== Computation of cross section matrices for adjoint "
250             "models =========="
251          << G4endl;
252   for(const auto& aModel : fAdjointModels)
253   {
254     G4cout << "Build adjoint cross section matrices for " << aModel->GetName()
255            << G4endl;
256     if(aModel->GetUseMatrix())
257     {
258       std::vector<G4AdjointCSMatrix*>* aListOfMat1 =
259         new std::vector<G4AdjointCSMatrix*>();
260       std::vector<G4AdjointCSMatrix*>* aListOfMat2 =
261         new std::vector<G4AdjointCSMatrix*>();
262       if(aModel->GetUseMatrixPerElement())
263       {
264         if(aModel->GetUseOnlyOneMatrixForAllElements())
265         {
266           std::vector<G4AdjointCSMatrix*> two_matrices =
267             BuildCrossSectionsModelAndElement(aModel, 1, 1, 80);
268           aListOfMat1->push_back(two_matrices[0]);
269           aListOfMat2->push_back(two_matrices[1]);
270         }
271         else
272         {
273           for(const auto& anElement : *theElementTable)
274           {
275             G4int Z = G4lrint(anElement->GetZ());
276             G4int A = G4lrint(anElement->GetN());
277             std::vector<G4AdjointCSMatrix*> two_matrices =
278               BuildCrossSectionsModelAndElement(aModel, Z, A, 40);
279             aListOfMat1->push_back(two_matrices[0]);
280             aListOfMat2->push_back(two_matrices[1]);
281           }
282         }
283       }
284       else
285       {  // Per material case
286         for(const auto& aMaterial : *theMaterialTable)
287         {
288           std::vector<G4AdjointCSMatrix*> two_matrices =
289             BuildCrossSectionsModelAndMaterial(aModel, aMaterial, 40);
290           aListOfMat1->push_back(two_matrices[0]);
291           aListOfMat2->push_back(two_matrices[1]);
292         }
293       }
294       fAdjointCSMatricesForProdToProj.push_back(*aListOfMat1);
295       fAdjointCSMatricesForScatProjToProj.push_back(*aListOfMat2);
296       aModel->SetCSMatrices(aListOfMat1, aListOfMat2);
297     }
298     else
299     {
300       G4cout << "The model " << aModel->GetName()
301              << " does not use cross section matrices" << G4endl;
302       std::vector<G4AdjointCSMatrix*> two_empty_matrices;
303       fAdjointCSMatricesForProdToProj.push_back(two_empty_matrices);
304       fAdjointCSMatricesForScatProjToProj.push_back(std::move(two_empty_matrices));
305     }
306   }
307   G4cout << "              All adjoint cross section matrices are computed!"
308          << G4endl;
309   G4cout
310     << "======================================================================"
311     << G4endl;
312 
313   fCSMatricesBuilt = true;
314 }
315 
316 ///////////////////////////////////////////////////////
317 void G4AdjointCSManager::BuildTotalSigmaTables()
318 {
319   if(fSigmaTableBuilt)
320     return;
321 
322   const G4ProductionCutsTable* theCoupleTable =
323     G4ProductionCutsTable::GetProductionCutsTable();
324 
325   // Prepare the Sigma table for all AdjointEMModel, will be filled later on
326   for(std::size_t i = 0; i < fAdjointModels.size(); ++i)
327   {
328     fSigmaTableForAdjointModelScatProjToProj[i]->clearAndDestroy();
329     fSigmaTableForAdjointModelProdToProj[i]->clearAndDestroy();
330     for(std::size_t j = 0; j < theCoupleTable->GetTableSize(); ++j)
331     {
332       fSigmaTableForAdjointModelScatProjToProj[i]->push_back(
333         new G4PhysicsLogVector(fTmin, fTmax, fNbins));
334       fSigmaTableForAdjointModelProdToProj[i]->push_back(
335         new G4PhysicsLogVector(fTmin, fTmax, fNbins));
336     }
337   }
338 
339   for(std::size_t i = 0; i < fAdjointParticlesInAction.size(); ++i)
340   {
341     G4ParticleDefinition* thePartDef = fAdjointParticlesInAction[i];
342     DefineCurrentParticle(thePartDef);
343     fTotalFwdSigmaTable[i]->clearAndDestroy();
344     fTotalAdjSigmaTable[i]->clearAndDestroy();
345     fEminForFwdSigmaTables[i].clear();
346     fEminForAdjSigmaTables[i].clear();
347     fEkinofFwdSigmaMax[i].clear();
348     fEkinofAdjSigmaMax[i].clear();
349 
350     for(std::size_t j = 0; j < theCoupleTable->GetTableSize(); ++j)
351     {
352       const G4MaterialCutsCouple* couple =
353         theCoupleTable->GetMaterialCutsCouple((G4int)j);
354 
355       // make first the total fwd CS table for FwdProcess
356       G4PhysicsVector* aVector = new G4PhysicsLogVector(fTmin, fTmax, fNbins);
357       G4bool Emin_found        = false;
358       G4double sigma_max       = 0.;
359       G4double e_sigma_max     = 0.;
360       for(std::size_t l = 0; l < fNbins; ++l)
361       {
362         G4double totCS = 0.;
363         G4double e     = aVector->Energy(l);
364         for(std::size_t k = 0; k < fForwardProcesses[i]->size(); ++k)
365         {
366           totCS += (*fForwardProcesses[i])[k]->GetCrossSection(e, couple);
367         }
368         for(std::size_t k = 0; k < fForwardLossProcesses[i]->size(); ++k)
369         {
370           if(thePartDef == fAdjIon)
371           {  // e is considered already as the scaled energy
372             std::size_t mat_index = couple->GetIndex();
373             G4VEmModel* currentModel =
374               (*fForwardLossProcesses[i])[k]->SelectModelForMaterial(e,
375                                                                      mat_index);
376             G4double chargeSqRatio = currentModel->GetChargeSquareRatio(
377               fFwdIon, couple->GetMaterial(), e / fMassRatio);
378             (*fForwardLossProcesses[i])[k]->SetDynamicMassCharge(fMassRatio,
379                                                                  chargeSqRatio);
380           }
381           G4double e1 = e / fMassRatio;
382           totCS += (*fForwardLossProcesses[i])[k]->GetLambda(e1, couple);
383         }
384         aVector->PutValue(l, totCS);
385         if(totCS > sigma_max)
386         {
387           sigma_max   = totCS;
388           e_sigma_max = e;
389         }
390         if(totCS > 0 && !Emin_found)
391         {
392           fEminForFwdSigmaTables[i].push_back(e);
393           Emin_found = true;
394         }
395       }
396 
397       fEkinofFwdSigmaMax[i].push_back(e_sigma_max);
398 
399       if(!Emin_found)
400         fEminForFwdSigmaTables[i].push_back(fTmax);
401 
402       fTotalFwdSigmaTable[i]->push_back(aVector);
403 
404       Emin_found                = false;
405       sigma_max                 = 0;
406       e_sigma_max               = 0.;
407       G4PhysicsVector* aVector1 = new G4PhysicsLogVector(fTmin, fTmax, fNbins);
408       for(std::size_t eindex = 0; eindex < fNbins; ++eindex)
409       {
410         G4double e     = aVector1->Energy(eindex);
411         G4double totCS = ComputeTotalAdjointCS(
412           couple, thePartDef,
413           e * 0.9999999 / fMassRatio);  // fMassRatio needed for ions
414         aVector1->PutValue(eindex, totCS);
415         if(totCS > sigma_max)
416         {
417           sigma_max   = totCS;
418           e_sigma_max = e;
419         }
420         if(totCS > 0 && !Emin_found)
421         {
422           fEminForAdjSigmaTables[i].push_back(e);
423           Emin_found = true;
424         }
425       }
426       fEkinofAdjSigmaMax[i].push_back(e_sigma_max);
427       if(!Emin_found)
428         fEminForAdjSigmaTables[i].push_back(fTmax);
429 
430       fTotalAdjSigmaTable[i]->push_back(aVector1);
431     }
432   }
433   fSigmaTableBuilt = true;
434 }
435 
436 ///////////////////////////////////////////////////////
437 G4double G4AdjointCSManager::GetTotalAdjointCS(
438   G4ParticleDefinition* aPartDef, G4double Ekin,
439   const G4MaterialCutsCouple* aCouple)
440 {
441   DefineCurrentMaterial(aCouple);
442   DefineCurrentParticle(aPartDef);
443   return (((*fTotalAdjSigmaTable[fCurrentParticleIndex])[fCurrentMatIndex])
444             ->Value(Ekin * fMassRatio));
445 }
446 
447 ///////////////////////////////////////////////////////
448 G4double G4AdjointCSManager::GetTotalForwardCS(
449   G4ParticleDefinition* aPartDef, G4double Ekin,
450   const G4MaterialCutsCouple* aCouple)
451 {
452   DefineCurrentMaterial(aCouple);
453   DefineCurrentParticle(aPartDef);
454   return (((*fTotalFwdSigmaTable[fCurrentParticleIndex])[fCurrentMatIndex])
455             ->Value(Ekin * fMassRatio));
456 }
457 
458 ///////////////////////////////////////////////////////
459 G4double G4AdjointCSManager::GetAdjointSigma(
460   G4double Ekin_nuc, std::size_t index_model, G4bool is_scat_proj_to_proj,
461   const G4MaterialCutsCouple* aCouple)
462 {
463   DefineCurrentMaterial(aCouple);
464   if(is_scat_proj_to_proj)
465     return (((*fSigmaTableForAdjointModelScatProjToProj[index_model])
466                [fCurrentMatIndex])->Value(Ekin_nuc));
467   else
468     return (
469       ((*fSigmaTableForAdjointModelProdToProj[index_model])[fCurrentMatIndex])
470         ->Value(Ekin_nuc));
471 }
472 
473 ///////////////////////////////////////////////////////
474 void G4AdjointCSManager::GetEminForTotalCS(G4ParticleDefinition* aPartDef,
475                                            const G4MaterialCutsCouple* aCouple,
476                                            G4double& emin_adj,
477                                            G4double& emin_fwd)
478 {
479   DefineCurrentMaterial(aCouple);
480   DefineCurrentParticle(aPartDef);
481   emin_adj = fEminForAdjSigmaTables[fCurrentParticleIndex][fCurrentMatIndex] /
482              fMassRatio;
483   emin_fwd = fEminForFwdSigmaTables[fCurrentParticleIndex][fCurrentMatIndex] /
484              fMassRatio;
485 }
486 
487 ///////////////////////////////////////////////////////
488 void G4AdjointCSManager::GetMaxFwdTotalCS(G4ParticleDefinition* aPartDef,
489                                           const G4MaterialCutsCouple* aCouple,
490                                           G4double& e_sigma_max,
491                                           G4double& sigma_max)
492 {
493   DefineCurrentMaterial(aCouple);
494   DefineCurrentParticle(aPartDef);
495   e_sigma_max = fEkinofFwdSigmaMax[fCurrentParticleIndex][fCurrentMatIndex];
496   sigma_max = ((*fTotalFwdSigmaTable[fCurrentParticleIndex])[fCurrentMatIndex])
497                 ->Value(e_sigma_max);
498   e_sigma_max /= fMassRatio;
499 }
500 
501 ///////////////////////////////////////////////////////
502 void G4AdjointCSManager::GetMaxAdjTotalCS(G4ParticleDefinition* aPartDef,
503                                           const G4MaterialCutsCouple* aCouple,
504                                           G4double& e_sigma_max,
505                                           G4double& sigma_max)
506 {
507   DefineCurrentMaterial(aCouple);
508   DefineCurrentParticle(aPartDef);
509   e_sigma_max = fEkinofAdjSigmaMax[fCurrentParticleIndex][fCurrentMatIndex];
510   sigma_max = ((*fTotalAdjSigmaTable[fCurrentParticleIndex])[fCurrentMatIndex])
511                 ->Value(e_sigma_max);
512   e_sigma_max /= fMassRatio;
513 }
514 
515 ///////////////////////////////////////////////////////
516 G4double G4AdjointCSManager::GetCrossSectionCorrection(
517   G4ParticleDefinition* aPartDef, G4double PreStepEkin,
518   const G4MaterialCutsCouple* aCouple, G4bool& fwd_is_used)
519 {
520   static G4double lastEkin = 0.;
521   static G4ParticleDefinition* lastPartDef;
522 
523   G4double corr_fac = 1.;
524   if(fForwardCSMode && aPartDef)
525   {
526     if(lastEkin != PreStepEkin || aPartDef != lastPartDef ||
527        aCouple != fCurrentCouple)
528     {
529       DefineCurrentMaterial(aCouple);
530       G4double preadjCS = GetTotalAdjointCS(aPartDef, PreStepEkin, aCouple);
531       G4double prefwdCS = GetTotalForwardCS(aPartDef, PreStepEkin, aCouple);
532       lastEkin          = PreStepEkin;
533       lastPartDef       = aPartDef;
534       if(prefwdCS > 0. && preadjCS > 0.)
535       {
536         fForwardCSUsed          = true;
537         fLastCSCorrectionFactor = prefwdCS / preadjCS;
538       }
539       else
540       {
541         fForwardCSUsed          = false;
542         fLastCSCorrectionFactor = 1.;
543       }
544     }
545     corr_fac = fLastCSCorrectionFactor;
546   }
547   else
548   {
549     fForwardCSUsed          = false;
550     fLastCSCorrectionFactor = 1.;
551   }
552   fwd_is_used = fForwardCSUsed;
553   return corr_fac;
554 }
555 
556 ///////////////////////////////////////////////////////
557 G4double G4AdjointCSManager::GetContinuousWeightCorrection(
558   G4ParticleDefinition* aPartDef, G4double PreStepEkin, G4double AfterStepEkin,
559   const G4MaterialCutsCouple* aCouple, G4double step_length)
560 {
561   G4double corr_fac    = 1.;
562   G4double after_fwdCS = GetTotalForwardCS(aPartDef, AfterStepEkin, aCouple);
563   G4double pre_adjCS   = GetTotalAdjointCS(aPartDef, PreStepEkin, aCouple);
564   if(!fForwardCSUsed || pre_adjCS == 0. || after_fwdCS == 0.)
565   {
566     G4double pre_fwdCS = GetTotalForwardCS(aPartDef, PreStepEkin, aCouple);
567     corr_fac *= std::exp((pre_adjCS - pre_fwdCS) * step_length);
568     fLastCSCorrectionFactor = 1.;
569   }
570   else
571   {
572     fLastCSCorrectionFactor = after_fwdCS / pre_adjCS;
573   }
574   return corr_fac;
575 }
576 
577 ///////////////////////////////////////////////////////
578 G4double G4AdjointCSManager::GetPostStepWeightCorrection()
579 {
580   return 1. / fLastCSCorrectionFactor;
581 }
582 
583 ///////////////////////////////////////////////////////
584 G4double G4AdjointCSManager::ComputeAdjointCS(
585   G4Material* aMaterial, G4VEmAdjointModel* aModel, G4double PrimEnergy,
586   G4double Tcut, G4bool isScatProjToProj, std::vector<G4double>& CS_Vs_Element)
587 {
588   G4double EminSec = 0.;
589   G4double EmaxSec = 0.;
590 
591   static G4double lastPrimaryEnergy = 0.;
592   static G4double lastTcut          = 0.;
593   static G4Material* lastMaterial   = nullptr;
594 
595   if(isScatProjToProj)
596   {
597     EminSec = aModel->GetSecondAdjEnergyMinForScatProjToProj(PrimEnergy, Tcut);
598     EmaxSec = aModel->GetSecondAdjEnergyMaxForScatProjToProj(PrimEnergy);
599   }
600   else if(PrimEnergy > Tcut || !aModel->GetApplyCutInRange())
601   {
602     EminSec = aModel->GetSecondAdjEnergyMinForProdToProj(PrimEnergy);
603     EmaxSec = aModel->GetSecondAdjEnergyMaxForProdToProj(PrimEnergy);
604   }
605   if(EminSec >= EmaxSec)
606     return 0.;
607 
608   G4bool need_to_compute = false;
609   if(aMaterial != lastMaterial || PrimEnergy != lastPrimaryEnergy ||
610      Tcut != lastTcut)
611   {
612     lastMaterial      = aMaterial;
613     lastPrimaryEnergy = PrimEnergy;
614     lastTcut          = Tcut;
615     fIndexOfAdjointEMModelInAction.clear();
616     fIsScatProjToProj.clear();
617     fLastAdjointCSVsModelsAndElements.clear();
618     need_to_compute = true;
619   }
620 
621   std::size_t ind = 0;
622   if(!need_to_compute)
623   {
624     need_to_compute = true;
625     for(std::size_t i = 0; i < fIndexOfAdjointEMModelInAction.size(); ++i)
626     {
627       std::size_t ind1 = fIndexOfAdjointEMModelInAction[i];
628       if(aModel == fAdjointModels[ind1] &&
629          isScatProjToProj == fIsScatProjToProj[i])
630       {
631         need_to_compute = false;
632         CS_Vs_Element   = fLastAdjointCSVsModelsAndElements[ind];
633       }
634       ++ind;
635     }
636   }
637 
638   if(need_to_compute)
639   {
640     std::size_t ind_model = 0;
641     for(std::size_t i = 0; i < fAdjointModels.size(); ++i)
642     {
643       if(aModel == fAdjointModels[i])
644       {
645         ind_model = i;
646         break;
647       }
648     }
649     G4double Tlow = Tcut;
650     if(!fAdjointModels[ind_model]->GetApplyCutInRange())
651       Tlow = fAdjointModels[ind_model]->GetLowEnergyLimit();
652     fIndexOfAdjointEMModelInAction.push_back(ind_model);
653     fIsScatProjToProj.push_back(isScatProjToProj);
654     CS_Vs_Element.clear();
655     if(!aModel->GetUseMatrix())
656     {
657       CS_Vs_Element.push_back(aModel->AdjointCrossSection(
658         fCurrentCouple, PrimEnergy, isScatProjToProj));
659     }
660     else if(aModel->GetUseMatrixPerElement())
661     {
662       std::size_t n_el = aMaterial->GetNumberOfElements();
663       if(aModel->GetUseOnlyOneMatrixForAllElements())
664       {
665         G4AdjointCSMatrix* theCSMatrix;
666         if(isScatProjToProj)
667         {
668           theCSMatrix = fAdjointCSMatricesForScatProjToProj[ind_model][0];
669         }
670         else
671           theCSMatrix = fAdjointCSMatricesForProdToProj[ind_model][0];
672         G4double CS = 0.;
673         if(PrimEnergy > Tlow)
674           CS = ComputeAdjointCS(PrimEnergy, theCSMatrix, Tlow);
675         G4double factor = 0.;
676         for(G4int i = 0; i < (G4int)n_el; ++i)
677         {  // this could be computed only once
678           factor += aMaterial->GetElement(i)->GetZ() *
679                     aMaterial->GetVecNbOfAtomsPerVolume()[i];
680         }
681         CS *= factor;
682         CS_Vs_Element.push_back(CS);
683       }
684       else
685       {
686         for(G4int i = 0; i < (G4int)n_el; ++i)
687         {
688           std::size_t ind_el = aMaterial->GetElement(i)->GetIndex();
689           G4AdjointCSMatrix* theCSMatrix;
690           if(isScatProjToProj)
691           {
692             theCSMatrix =
693               fAdjointCSMatricesForScatProjToProj[ind_model][ind_el];
694           }
695           else
696             theCSMatrix = fAdjointCSMatricesForProdToProj[ind_model][ind_el];
697           G4double CS = 0.;
698           if(PrimEnergy > Tlow)
699             CS = ComputeAdjointCS(PrimEnergy, theCSMatrix, Tlow);
700           CS_Vs_Element.push_back(CS *
701                                   (aMaterial->GetVecNbOfAtomsPerVolume()[i]));
702         }
703       }
704     }
705     else
706     {
707       std::size_t ind_mat = aMaterial->GetIndex();
708       G4AdjointCSMatrix* theCSMatrix;
709       if(isScatProjToProj)
710       {
711         theCSMatrix = fAdjointCSMatricesForScatProjToProj[ind_model][ind_mat];
712       }
713       else
714         theCSMatrix = fAdjointCSMatricesForProdToProj[ind_model][ind_mat];
715       G4double CS = 0.;
716       if(PrimEnergy > Tlow)
717         CS = ComputeAdjointCS(PrimEnergy, theCSMatrix, Tlow);
718       CS_Vs_Element.push_back(CS);
719     }
720     fLastAdjointCSVsModelsAndElements.push_back(CS_Vs_Element);
721   }
722 
723   G4double CS = 0.;
724   for(const auto& cs_vs_el : CS_Vs_Element)
725   {
726     // We could put the progressive sum of the CS instead of the CS of an
727     // element itself
728     CS += cs_vs_el;
729   }
730   return CS;
731 }
732 
733 ///////////////////////////////////////////////////////
734 G4Element* G4AdjointCSManager::SampleElementFromCSMatrices(
735   G4Material* aMaterial, G4VEmAdjointModel* aModel, G4double PrimEnergy,
736   G4double Tcut, G4bool isScatProjToProj)
737 {
738   std::vector<G4double> CS_Vs_Element;
739   G4double CS    = ComputeAdjointCS(aMaterial, aModel, PrimEnergy, Tcut,
740                                  isScatProjToProj, CS_Vs_Element);
741   G4double SumCS = 0.;
742   std::size_t ind     = 0;
743   for(std::size_t i = 0; i < CS_Vs_Element.size(); ++i)
744   {
745     SumCS += CS_Vs_Element[i];
746     if(G4UniformRand() <= SumCS / CS)
747     {
748       ind = i;
749       break;
750     }
751   }
752 
753   return const_cast<G4Element*>(aMaterial->GetElement((G4int)ind));
754 }
755 
756 ///////////////////////////////////////////////////////
757 G4double G4AdjointCSManager::ComputeTotalAdjointCS(
758   const G4MaterialCutsCouple* aCouple, G4ParticleDefinition* aPartDef,
759   G4double Ekin)
760 {
761   G4double TotalCS = 0.;
762 
763   DefineCurrentMaterial(aCouple);
764 
765   std::vector<G4double> CS_Vs_Element;
766   G4double CS;
767   G4VEmAdjointModel* adjModel = nullptr;
768   for(std::size_t i = 0; i < fAdjointModels.size(); ++i)
769   {
770     G4double Tlow = 0.;
771     adjModel      = fAdjointModels[i];
772     if(!adjModel->GetApplyCutInRange())
773       Tlow = adjModel->GetLowEnergyLimit();
774     else
775     {
776       G4ParticleDefinition* theDirSecondPartDef = GetForwardParticleEquivalent(
777         adjModel->GetAdjointEquivalentOfDirectSecondaryParticleDefinition());
778       std::size_t idx = 56;
779       if(theDirSecondPartDef->GetParticleName() == "gamma")
780         idx = 0;
781       else if(theDirSecondPartDef->GetParticleName() == "e-")
782         idx = 1;
783       else if(theDirSecondPartDef->GetParticleName() == "e+")
784         idx = 2;
785       if(idx < 56)
786       {
787         const std::vector<G4double>* aVec =
788           G4ProductionCutsTable::GetProductionCutsTable()->GetEnergyCutsVector(
789             idx);
790         Tlow = (*aVec)[aCouple->GetIndex()];
791       }
792     }
793     if(Ekin <= adjModel->GetHighEnergyLimit() &&
794        Ekin >= adjModel->GetLowEnergyLimit())
795     {
796       if(aPartDef ==
797          adjModel->GetAdjointEquivalentOfDirectPrimaryParticleDefinition())
798       {
799         CS = ComputeAdjointCS(fCurrentMaterial, adjModel, Ekin, Tlow, true,
800                               CS_Vs_Element);
801         TotalCS += CS;
802         (*fSigmaTableForAdjointModelScatProjToProj[i])[fCurrentMatIndex]
803           ->PutValue(fNbins, CS);
804       }
805       if(aPartDef ==
806          adjModel->GetAdjointEquivalentOfDirectSecondaryParticleDefinition())
807       {
808         CS = ComputeAdjointCS(fCurrentMaterial, adjModel, Ekin, Tlow, false,
809                               CS_Vs_Element);
810         TotalCS += CS;
811         (*fSigmaTableForAdjointModelProdToProj[i])[fCurrentMatIndex]->PutValue(
812           fNbins, CS);
813       }
814     }
815     else
816     {
817       (*fSigmaTableForAdjointModelScatProjToProj[i])[fCurrentMatIndex]
818         ->PutValue(fNbins, 0.);
819       (*fSigmaTableForAdjointModelProdToProj[i])[fCurrentMatIndex]->PutValue(
820         fNbins, 0.);
821     }
822   }
823   return TotalCS;
824 }
825 
826 ///////////////////////////////////////////////////////
827 std::vector<G4AdjointCSMatrix*>
828 G4AdjointCSManager::BuildCrossSectionsModelAndElement(G4VEmAdjointModel* aModel,
829                                                       G4int Z, G4int A,
830                                                       G4int nbin_pro_decade)
831 {
832   G4AdjointCSMatrix* theCSMatForProdToProjBackwardScattering =
833     new G4AdjointCSMatrix(false);
834   G4AdjointCSMatrix* theCSMatForScatProjToProjBackwardScattering =
835     new G4AdjointCSMatrix(true);
836 
837   // make the vector of primary energy of the adjoint particle. 
838   G4double EkinMin        = aModel->GetLowEnergyLimit();
839   G4double EkinMaxForScat = aModel->GetHighEnergyLimit() * 0.999;
840   G4double EkinMaxForProd = aModel->GetHighEnergyLimit() * 0.999;
841   if(aModel->GetSecondPartOfSameType())
842     EkinMaxForProd = EkinMaxForProd / 2.;
843 
844   // Product to projectile backward scattering
845   G4double dE = std::pow(10., 1. / nbin_pro_decade);
846   G4double E2 =
847     std::pow(10., double(int(std::log10(EkinMin) * nbin_pro_decade) + 1) /
848                     nbin_pro_decade) / dE;
849   G4double E1 = EkinMin;
850   // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
851   while(E1 < EkinMaxForProd)
852   {
853     E1 = std::max(EkinMin, E2);
854     E1 = std::min(EkinMaxForProd, E1);
855     std::vector<std::vector<double>*> aMat =
856       aModel->ComputeAdjointCrossSectionVectorPerAtomForSecond(E1, Z, A,
857                                                                nbin_pro_decade);
858     if(aMat.size() >= 2)
859     {
860       std::vector<double>* log_ESecVec = aMat[0];
861       std::vector<double>* log_CSVec   = aMat[1];
862       G4double log_adjointCS           = log_CSVec->back();
863       // normalise CSVec such that it becomes a probability vector
864       for(std::size_t j = 0; j < log_CSVec->size(); ++j)
865       {
866         if(j == 0)
867           (*log_CSVec)[j] = 0.;
868         else
869           (*log_CSVec)[j] =
870             std::log(1. - std::exp((*log_CSVec)[j] - log_adjointCS) + 1e-50);
871       }
872       (*log_CSVec)[log_CSVec->size() - 1] =
873         (*log_CSVec)[log_CSVec->size() - 2] - std::log(1000.);
874       theCSMatForProdToProjBackwardScattering->AddData(
875         std::log(E1), log_adjointCS, log_ESecVec, log_CSVec, 0);
876     }
877     E1 = E2;
878     E2 *= dE;
879   }
880 
881   // Scattered projectile to projectile backward scattering
882   E2 = std::pow(10., G4double(int(std::log10(EkinMin) * nbin_pro_decade) + 1) /
883                        nbin_pro_decade) / dE;
884   E1 = EkinMin;
885   // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
886   while(E1 < EkinMaxForScat)
887   {
888     E1 = std::max(EkinMin, E2);
889     E1 = std::min(EkinMaxForScat, E1);
890     std::vector<std::vector<G4double>*> aMat =
891       aModel->ComputeAdjointCrossSectionVectorPerAtomForScatProj(
892         E1, Z, A, nbin_pro_decade);
893     if(aMat.size() >= 2)
894     {
895       std::vector<G4double>* log_ESecVec = aMat[0];
896       std::vector<G4double>* log_CSVec   = aMat[1];
897       G4double log_adjointCS             = log_CSVec->back();
898       // normalise CSVec such that it becomes a probability vector
899       for(std::size_t j = 0; j < log_CSVec->size(); ++j)
900       {
901         if(j == 0)
902           (*log_CSVec)[j] = 0.;
903         else
904           (*log_CSVec)[j] =
905             std::log(1. - std::exp((*log_CSVec)[j] - log_adjointCS) + 1e-50);
906       }
907       (*log_CSVec)[log_CSVec->size() - 1] =
908         (*log_CSVec)[log_CSVec->size() - 2] - std::log(1000.);
909       theCSMatForScatProjToProjBackwardScattering->AddData(
910         std::log(E1), log_adjointCS, log_ESecVec, log_CSVec, 0);
911     }
912     E1 = E2;
913     E2 *= dE;
914   }
915 
916   std::vector<G4AdjointCSMatrix*> res;
917   res.push_back(theCSMatForProdToProjBackwardScattering);
918   res.push_back(theCSMatForScatProjToProjBackwardScattering);
919 
920   return res;
921 }
922 
923 ///////////////////////////////////////////////////////
924 std::vector<G4AdjointCSMatrix*>
925 G4AdjointCSManager::BuildCrossSectionsModelAndMaterial(
926   G4VEmAdjointModel* aModel, G4Material* aMaterial, G4int nbin_pro_decade)
927 {
928   G4AdjointCSMatrix* theCSMatForProdToProjBackwardScattering =
929     new G4AdjointCSMatrix(false);
930   G4AdjointCSMatrix* theCSMatForScatProjToProjBackwardScattering =
931     new G4AdjointCSMatrix(true);
932 
933   G4double EkinMin        = aModel->GetLowEnergyLimit();
934   G4double EkinMaxForScat = aModel->GetHighEnergyLimit() * 0.999;
935   G4double EkinMaxForProd = aModel->GetHighEnergyLimit() * 0.999;
936   if(aModel->GetSecondPartOfSameType())
937     EkinMaxForProd /= 2.;
938 
939   // Product to projectile backward scattering
940   G4double dE = std::pow(10., 1. / nbin_pro_decade);
941   G4double E2 =
942     std::pow(10., double(int(std::log10(EkinMin) * nbin_pro_decade) + 1) /
943                     nbin_pro_decade) / dE;
944   G4double E1 = EkinMin;
945   // Loop checking, 07-Aug-2015, Vladimir Ivanchenko
946   while(E1 < EkinMaxForProd)
947   {
948     E1 = std::max(EkinMin, E2);
949     E1 = std::min(EkinMaxForProd, E1);
950     std::vector<std::vector<G4double>*> aMat =
951       aModel->ComputeAdjointCrossSectionVectorPerVolumeForSecond(
952         aMaterial, E1, nbin_pro_decade);
953     if(aMat.size() >= 2)
954     {
955       std::vector<G4double>* log_ESecVec = aMat[0];
956       std::vector<G4double>* log_CSVec   = aMat[1];
957       G4double log_adjointCS             = log_CSVec->back();
958 
959       // normalise CSVec such that it becomes a probability vector
960       for(std::size_t j = 0; j < log_CSVec->size(); ++j)
961       {
962         if(j == 0)
963           (*log_CSVec)[j] = 0.;
964         else
965           (*log_CSVec)[j] =
966             std::log(1. - std::exp((*log_CSVec)[j] - log_adjointCS));
967       }
968       (*log_CSVec)[log_CSVec->size() - 1] =
969         (*log_CSVec)[log_CSVec->size() - 2] - std::log(1000.);
970       theCSMatForProdToProjBackwardScattering->AddData(
971         std::log(E1), log_adjointCS, log_ESecVec, log_CSVec, 0);
972     }
973 
974     E1 = E2;
975     E2 *= dE;
976   }
977 
978   // Scattered projectile to projectile backward scattering
979   E2 =
980     std::pow(10., G4double(G4int(std::log10(EkinMin) * nbin_pro_decade) + 1) /
981                     nbin_pro_decade) /
982     dE;
983   E1 = EkinMin;
984   while(E1 < EkinMaxForScat)
985   {
986     E1 = std::max(EkinMin, E2);
987     E1 = std::min(EkinMaxForScat, E1);
988     std::vector<std::vector<G4double>*> aMat =
989       aModel->ComputeAdjointCrossSectionVectorPerVolumeForScatProj(
990         aMaterial, E1, nbin_pro_decade);
991     if(aMat.size() >= 2)
992     {
993       std::vector<G4double>* log_ESecVec = aMat[0];
994       std::vector<G4double>* log_CSVec   = aMat[1];
995       G4double log_adjointCS             = log_CSVec->back();
996 
997       for(std::size_t j = 0; j < log_CSVec->size(); ++j)
998       {
999         if(j == 0)
1000           (*log_CSVec)[j] = 0.;
1001         else
1002           (*log_CSVec)[j] =
1003             std::log(1. - std::exp((*log_CSVec)[j] - log_adjointCS));
1004       }
1005       (*log_CSVec)[log_CSVec->size() - 1] =
1006         (*log_CSVec)[log_CSVec->size() - 2] - std::log(1000.);
1007 
1008       theCSMatForScatProjToProjBackwardScattering->AddData(
1009         std::log(E1), log_adjointCS, log_ESecVec, log_CSVec, 0);
1010     }
1011     E1 = E2;
1012     E2 *= dE;
1013   }
1014 
1015   std::vector<G4AdjointCSMatrix*> res;
1016   res.push_back(theCSMatForProdToProjBackwardScattering);
1017   res.push_back(theCSMatForScatProjToProjBackwardScattering);
1018 
1019   return res;
1020 }
1021 
1022 ///////////////////////////////////////////////////////
1023 G4ParticleDefinition* G4AdjointCSManager::GetAdjointParticleEquivalent(
1024   G4ParticleDefinition* theFwdPartDef)
1025 {
1026   if(theFwdPartDef->GetParticleName() == "e-")
1027     return G4AdjointElectron::AdjointElectron();
1028   else if(theFwdPartDef->GetParticleName() == "gamma")
1029     return G4AdjointGamma::AdjointGamma();
1030   else if(theFwdPartDef->GetParticleName() == "proton")
1031     return G4AdjointProton::AdjointProton();
1032   else if(theFwdPartDef == fFwdIon)
1033     return fAdjIon;
1034   return nullptr;
1035 }
1036 
1037 ///////////////////////////////////////////////////////
1038 G4ParticleDefinition* G4AdjointCSManager::GetForwardParticleEquivalent(
1039   G4ParticleDefinition* theAdjPartDef)
1040 {
1041   if(theAdjPartDef->GetParticleName() == "adj_e-")
1042     return G4Electron::Electron();
1043   else if(theAdjPartDef->GetParticleName() == "adj_gamma")
1044     return G4Gamma::Gamma();
1045   else if(theAdjPartDef->GetParticleName() == "adj_proton")
1046     return G4Proton::Proton();
1047   else if(theAdjPartDef == fAdjIon)
1048     return fFwdIon;
1049   return nullptr;
1050 }
1051 
1052 ///////////////////////////////////////////////////////
1053 void G4AdjointCSManager::DefineCurrentMaterial(
1054   const G4MaterialCutsCouple* couple)
1055 {
1056   if(couple != fCurrentCouple)
1057   {
1058     fCurrentCouple          = const_cast<G4MaterialCutsCouple*>(couple);
1059     fCurrentMaterial        = const_cast<G4Material*>(couple->GetMaterial());
1060     fCurrentMatIndex        = couple->GetIndex();
1061     fLastCSCorrectionFactor = 1.;
1062   }
1063 }
1064 
1065 ///////////////////////////////////////////////////////
1066 void G4AdjointCSManager::DefineCurrentParticle(
1067   const G4ParticleDefinition* aPartDef)
1068 {
1069  
1070   if(aPartDef != fCurrentParticleDef)
1071   {
1072     fCurrentParticleDef = const_cast<G4ParticleDefinition*>(aPartDef);
1073     fMassRatio         = 1.;
1074     if(aPartDef == fAdjIon)
1075       fMassRatio = proton_mass_c2 / aPartDef->GetPDGMass();
1076     fCurrentParticleIndex = 1000000;
1077     for(std::size_t i = 0; i < fAdjointParticlesInAction.size(); ++i)
1078     {
1079       if(aPartDef == fAdjointParticlesInAction[i])
1080         fCurrentParticleIndex = i;
1081     }
1082   }
1083 }
1084 
1085 ////////////////////////////////////////////////////////////////////////////////
1086 G4double G4AdjointCSManager::ComputeAdjointCS(
1087   G4double aPrimEnergy, G4AdjointCSMatrix* anAdjointCSMatrix, G4double Tcut)
1088 {
1089   std::vector<double>* theLogPrimEnergyVector =
1090     anAdjointCSMatrix->GetLogPrimEnergyVector();
1091   if(theLogPrimEnergyVector->empty())
1092   {
1093     G4cout << "No data are contained in the given AdjointCSMatrix!" << G4endl;
1094     return 0.;
1095   }
1096   G4double log_Tcut = std::log(Tcut);
1097   G4double log_E    = std::log(aPrimEnergy);
1098 
1099   if(aPrimEnergy <= Tcut || log_E > theLogPrimEnergyVector->back())
1100     return 0.;
1101 
1102   G4AdjointInterpolator* theInterpolator = G4AdjointInterpolator::GetInstance();
1103 
1104   std::size_t ind =
1105     theInterpolator->FindPositionForLogVector(log_E, *theLogPrimEnergyVector);
1106   G4double aLogPrimEnergy1, aLogPrimEnergy2;
1107   G4double aLogCS1, aLogCS2;
1108   G4double log01, log02;
1109   std::vector<G4double>* aLogSecondEnergyVector1 = nullptr;
1110   std::vector<G4double>* aLogSecondEnergyVector2 = nullptr;
1111   std::vector<G4double>* aLogProbVector1         = nullptr;
1112   std::vector<G4double>* aLogProbVector2         = nullptr;
1113   std::vector<std::size_t>* aLogProbVectorIndex1 = nullptr;
1114   std::vector<std::size_t>* aLogProbVectorIndex2 = nullptr;
1115 
1116   anAdjointCSMatrix->GetData((G4int)ind, aLogPrimEnergy1, aLogCS1, log01,
1117                              aLogSecondEnergyVector1, aLogProbVector1,
1118                              aLogProbVectorIndex1);
1119   anAdjointCSMatrix->GetData(G4int(ind + 1), aLogPrimEnergy2, aLogCS2, log02,
1120                              aLogSecondEnergyVector2, aLogProbVector2,
1121                              aLogProbVectorIndex2);
1122   if (! (aLogProbVector1 && aLogProbVector2 &&
1123              aLogSecondEnergyVector1 && aLogSecondEnergyVector2)){
1124      return  0.;
1125   }
1126 
1127   if(anAdjointCSMatrix->IsScatProjToProj())
1128   {  // case where the Tcut plays a role
1129     G4double log_minimum_prob1, log_minimum_prob2;
1130     log_minimum_prob1 = theInterpolator->InterpolateForLogVector(
1131       log_Tcut, *aLogSecondEnergyVector1, *aLogProbVector1);
1132     log_minimum_prob2 = theInterpolator->InterpolateForLogVector(
1133       log_Tcut, *aLogSecondEnergyVector2, *aLogProbVector2);
1134     aLogCS1 += log_minimum_prob1;
1135     aLogCS2 += log_minimum_prob2;
1136   }
1137 
1138   G4double log_adjointCS = theInterpolator->LinearInterpolation(
1139     log_E, aLogPrimEnergy1, aLogPrimEnergy2, aLogCS1, aLogCS2);
1140   return std::exp(log_adjointCS);
1141 }
1142