SuSAv2MECPXSec.cxx
Go to the documentation of this file.
1 //_________________________________________________________________________
2 /*
3  Copyright (c) 2003-2018, The GENIE Collaboration
4  For the full text of the license visit http://copyright.genie-mc.org
5  or see $GENIE/LICENSE
6 
7  For the class documentation see the corresponding header file.
8 */
9 //_________________________________________________________________________
10 
24 
25 using namespace genie;
26 
27 //_________________________________________________________________________
28 SuSAv2MECPXSec::SuSAv2MECPXSec() : XSecAlgorithmI("genie::SuSAv2MECPXSec")
29 {
30 }
31 //_________________________________________________________________________
33  : XSecAlgorithmI("genie::SuSAv2MECPXSec", config)
34 {
35 }
36 //_________________________________________________________________________
38 {
39 }
40 //_________________________________________________________________________
42  KinePhaseSpace_t kps) const
43 {
44  // Don't try to do the calculation if we've been handed an interaction that
45  // doesn't make sense
46  if ( !this->ValidProcess(interaction) ) return 0.;
47 
48  // Get the hadron tensor for the selected nuclide. Check the probe PDG code
49  // to know whether to use the tensor for CC neutrino scattering or for
50  // electron scattering
51  int target_pdg = interaction->InitState().Tgt().Pdg();
52  int probe_pdg = interaction->InitState().ProbePdg();
53  int A_request = pdg::IonPdgCodeToA(target_pdg);
54  int Z_request = pdg::IonPdgCodeToZ(target_pdg);
55  bool need_to_scale = false;
56 
57  HadronTensorType_t tensor_type = kHT_Undefined;
58  if ( pdg::IsNeutrino(probe_pdg) || pdg::IsAntiNeutrino(probe_pdg) ) {
59  tensor_type = kHT_MEC_FullAll;
60  //pn_tensor_type = kHT_MEC_Fullpn;
61  //tensor_type = kHT_MEC_FullAll_wImag;
62  //pn_tensor_type = kHT_MEC_FullAll_wImag;
63  }
64  else {
65  // If the probe is not a neutrino, assume that it's an electron
66  // For the moment all electron interactions are pp final state
67  tensor_type = kHT_MEC_EM;
68  //pn_tensor_type = kHT_MEC_EM;
69  }
70 
71  // Currently we only have the relative pair contributions for C12.
72  int tensor_pdg = kPdgTgtC12;
73  if(tensor_pdg != target_pdg) need_to_scale = true;
74 
75  // The SuSAv2-MEC hadron tensors are defined using the same conventions
76  // as the Valencia MEC model, so we can use the same sort of tensor
77  // object to describe them.
78  const LabFrameHadronTensorI* tensor
79  = dynamic_cast<const LabFrameHadronTensorI*>( fHadronTensorModel->GetTensor(tensor_pdg,
80  tensor_type) );
81 
82  /// \todo add the different pair configurations for e-scattering
83 
84  // If retrieving the tensor failed, complain and return zero
85  if ( !tensor ) {
86  LOG("SuSAv2MEC", pWARN) << "Failed to load a hadronic tensor for the"
87  " nuclide " << tensor_pdg;
88  return 0.;
89  }
90 
91  // Check that the input kinematical point is within the range
92  // in which hadron tensors are known (for chosen target)
93  double Ev = interaction->InitState().ProbeE(kRfLab);
94  double Tl = interaction->Kine().GetKV(kKVTl);
95  double costl = interaction->Kine().GetKV(kKVctl);
96  double ml = interaction->FSPrimLepton()->Mass();
97  double Q0 = 0.;
98  double Q3 = 0.;
99 
100  // The Q-Value essentially corrects q0 to account for nuclear
101  // binding energy in the Valencia model but this effect is already
102  // in Guille's tensors so its set it to 0.
103  // However, additional corrections may be necessary:
104  double Delta_Q_value = Qvalue( * interaction ) ;
105 
106  genie::utils::mec::Getq0q3FromTlCostl(Tl, costl, Ev, ml, Q0, Q3);
107 
108  double Q0min = tensor->q0Min();
109  double Q0max = tensor->q0Max();
110  double Q3min = tensor->qMagMin();
111  double Q3max = tensor->qMagMax();
112  if (Q0-Delta_Q_value < Q0min || Q0-Delta_Q_value > Q0max || Q3 < Q3min || Q3 > Q3max) {
113  return 0.0;
114  }
115 
116  // *** Enforce the global Q^2 cut (important for EM scattering) ***
117  // Choose the appropriate minimum Q^2 value based on the interaction
118  // mode (this is important for EM interactions since the differential
119  // cross section blows up as Q^2 --> 0)
120  double Q2min = genie::controls::kMinQ2Limit; // CC/NC limit
121  if ( interaction->ProcInfo().IsEM() ) Q2min = genie::utils::kinematics
122  ::electromagnetic::kMinQ2Limit; // EM limit
123 
124  // Neglect shift due to binding energy. The cut is on the actual
125  // value of Q^2, not the effective one to use in the tensor contraction.
126  double Q2 = Q3*Q3 - Q0*Q0;
127  if ( Q2 < Q2min ) return 0.;
128 
129  // By default, we will compute the full cross-section. If a {p,n} hit
130  // dinucleon was set we will calculate the cross-section for that
131  // component only
132 
133  bool pn = (interaction->InitState().Tgt().HitNucPdg() == kPdgClusterNP);
134 
135  // Compute the cross section using the hadron tensor
136  double xsec = tensor->dSigma_dT_dCosTheta_rosenbluth(interaction, Delta_Q_value);
137 
138  // This scaling should be okay-ish for the total xsec, but it misses
139  // the energy shift. To get this we should really just build releveant
140  // hadron tensors but there may be some ways to approximate it.
141  // For more details see Guille's thesis: https://idus.us.es/xmlui/handle/11441/74826
142  if ( need_to_scale ) {
144  const FermiMomentumTable * kft = kftp->GetTable(fKFTable);
145  double KF_tgt = kft->FindClosestKF(target_pdg, kPdgProton);
146  double KF_ten = kft->FindClosestKF(tensor_pdg, kPdgProton);
147  LOG("SuSAv2MEC", pDEBUG) << "KF_tgt = " << KF_tgt;
148  LOG("SuSAv2MEC", pDEBUG) << "KF_ten = " << KF_ten;
149  double A_ten = pdg::IonPdgCodeToA(tensor_pdg);
150  double scaleFact = (A_request/A_ten)*(KF_tgt/KF_ten)*(KF_tgt/KF_ten);
151  xsec *= scaleFact;
152  }
153 
154  // Apply given overall scaling factor
155  xsec *= fXSecScale;
156 
157  // Scale given a scaling algorithm:
158  if( fMECScaleAlg ) xsec *= fMECScaleAlg->GetScaling( * interaction ) ;
159 
160  if ( kps != kPSTlctl ) {
161  LOG("SuSAv2MEC", pWARN)
162  << "Doesn't support transformation from "
163  << KinePhaseSpace::AsString(kPSTlctl) << " to "
164  << KinePhaseSpace::AsString(kps);
165  xsec = 0.;
166  }
167 
168  return xsec;
169 }
170 //_________________________________________________________________________
172 {
173 
174  // Currently we only have the relative pair contributions for C12.
175  // We hope to add mode later, but for the moment assume the relative
176  // contributions are A-independant.
177 
178  int probe_pdg = interaction->InitState().ProbePdg();
179 
180  HadronTensorType_t tensor_type = kHT_Undefined;
181  HadronTensorType_t pn_tensor_type = kHT_Undefined;
182  if ( pdg::IsNeutrino(probe_pdg) || pdg::IsAntiNeutrino(probe_pdg) ) {
183  tensor_type = kHT_MEC_FullAll;
184  pn_tensor_type = kHT_MEC_Fullpn;
185  }
186  else {
187  // If the probe is not a neutrino, assume that it's an electron
188  // For the moment all electron interactions are pp final state
189  tensor_type = kHT_MEC_EM;
190  pn_tensor_type = kHT_MEC_EM;
191  }
192 
193  // The SuSAv2-MEC hadron tensors are defined using the same conventions
194  // as the Valencia MEC model, so we can use the same sort of tensor
195  // object to describe them.
196  const LabFrameHadronTensorI* tensor
198  tensor_type) );
199 
200  const LabFrameHadronTensorI* tensor_pn
202  pn_tensor_type) );
203 
204 
205  /// \todo add the different pair configurations for e-scattering
206 
207  // If retrieving the tensor failed, complain and return zero
208  if ( !tensor ) {
209  LOG("SuSAv2MEC", pWARN) << "Failed to load a hadronic tensor for the"
210  " nuclide " << kPdgTgtC12;
211  return 0.;
212  }
213 
214  // Check that the input kinematical point is within the range
215  // in which hadron tensors are known (for chosen target)
216  double Ev = interaction->InitState().ProbeE(kRfLab);
217  double Tl = interaction->Kine().GetKV(kKVTl);
218  double costl = interaction->Kine().GetKV(kKVctl);
219  double ml = interaction->FSPrimLepton()->Mass();
220  double Q0 = 0.;
221  double Q3 = 0.;
222 
223  genie::utils::mec::Getq0q3FromTlCostl(Tl, costl, Ev, ml, Q0, Q3);
224 
225  double Q0min = tensor->q0Min();
226  double Q0max = tensor->q0Max();
227  double Q3min = tensor->qMagMin();
228  double Q3max = tensor->qMagMax();
229  if (Q0 < Q0min || Q0 > Q0max || Q3 < Q3min || Q3 > Q3max) {
230  return 1.0;
231  }
232 
233  // The Q-Value essentially corrects q0 to account for nuclear
234  // binding energy in the Valencia model but this effect is already
235  // in Guille's tensors so its set it to 0.
236  // However, additional corrections may be necessary:
237  double Delta_Q_value = Qvalue( * interaction ) ;
238 
239  // Compute the cross section using the hadron tensor
240  double xsec_all = tensor->dSigma_dT_dCosTheta_rosenbluth(interaction, Delta_Q_value);
241  double xsec_pn = tensor_pn->dSigma_dT_dCosTheta_rosenbluth(interaction, Delta_Q_value);
242 
243  //hadron tensor precision can sometimes lead to 0 xsec_pn but finite xsec
244  //seems to cause issues downstream ...
245  if(xsec_pn==0) xsec_pn = 0.00001*xsec_all;
246 
247  double ratio = (1e10*xsec_pn)/(1e10*xsec_all);
248 
249  return ratio;
250 }
251 //_________________________________________________________________________
253 {
254  double xsec = fXSecIntegrator->Integrate(this,interaction);
255  return xsec;
256 }
257 //_________________________________________________________________________
259 {
260  if ( interaction->TestBit(kISkipProcessChk) ) return true;
261 
262  const ProcessInfo& proc_info = interaction->ProcInfo();
263  if ( !proc_info.IsMEC() ) {
264  return false;
265  }
266 
267  int probe = interaction->InitState().ProbePdg();
268 
269  bool is_nu = pdg::IsNeutrino( probe );
270  bool is_nub = pdg::IsAntiNeutrino( probe );
271  bool is_chgl = pdg::IsChargedLepton( probe );
272 
273  bool prc_ok = ( proc_info.IsWeakCC() && (is_nu || is_nub) )
274  || ( proc_info.IsEM() && is_chgl );
275 
276  if ( !prc_ok ) return false;
277 
278  return true;
279 }
280 //_________________________________________________________________________
282 {
283  // Get the hadron tensor for the selected nuclide. Check the probe PDG code
284  // to know whether to use the tensor for CC neutrino scattering or for
285  // electron scattering
286  int target_pdg = interaction.InitState().Tgt().Pdg();
287  int probe_pdg = interaction.InitState().ProbePdg();
288  int tensor_pdg = kPdgTgtC12;
289  int A_request = pdg::IonPdgCodeToA(target_pdg);
290 
291  double Eb_tgt=0;
292  double Eb_ten=0;
293 
294  /// \todo Add more hadron tensors so this scaling is not so terrible
295  // At the moment all we have is Carbon so this is all just a place holder ...
296  if ( A_request == 4 ) {
297  Eb_tgt=fEbHe; Eb_ten=fEbC;
298  // This is for helium 4, but use carbon tensor, may not be ideal ...
299  }
300  else if (A_request < 9) {
301  Eb_tgt=fEbLi; Eb_ten=fEbC;
302  }
303  else if (A_request >= 9 && A_request < 15) {
304  Eb_tgt=fEbC; Eb_ten=fEbC;
305  }
306  else if(A_request >= 15 && A_request < 22) {
307  //tensor_pdg = kPdgTgtO16;
308  // Oxygen tensor has some issues - xsec @ 50 GeV = 45.2835 x 1E-38 cm^2
309  // This is ~ 24 times higher than C
310  // I think it's just a missing scale factor but I need to check.
311  Eb_tgt=fEbO; Eb_ten=fEbC;
312  }
313  else if(A_request >= 22 && A_request < 40) {
314  Eb_tgt=fEbMg; Eb_ten=fEbC;
315  }
316  else if(A_request >= 40 && A_request < 56) {
317  Eb_tgt=fEbAr; Eb_ten=fEbC;
318  }
319  else if(A_request >= 56 && A_request < 119) {
320  Eb_tgt=fEbFe; Eb_ten=fEbC;
321  }
322  else if(A_request >= 119 && A_request < 206) {
323  Eb_tgt=fEbSn; Eb_ten=fEbC;
324  }
325  else if(A_request >= 206) {
326  Eb_tgt=fEbPb; Eb_ten=fEbC;
327  }
328 
329  // SD: The Q-Value essentially corrects q0 to account for nuclear
330  // binding energy in the Valencia model but this effect is already
331  // in Guille's tensors so I'll set it to 0.
332  // However, if I want to scale I need to account for the altered
333  // binding energy. To first order I can use the Delta_Q_value for this.
334  // But this is 2p2h - so binding energy counts twice - use 2*1p1h
335  // value (although what should be done here is still not clear).
336 
337  double Delta_Q_value = 2*(Eb_tgt-Eb_ten);
338 
339  // Apply Qvalue relative shift if needed:
340  if( fQvalueShifter ) {
341  // We have the option to add an additional shift on top of the binding energy correction
342  // The QvalueShifter, is a relative shift to the Q_value.
343  // The Q_value was already taken into account in the hadron tensor. Here we recalculate it
344  // to get the right absolute shift.
345  double tensor_Q_value = genie::utils::mec::Qvalue(tensor_pdg,probe_pdg);
346  double total_Q_value = tensor_Q_value + Delta_Q_value ;
347  double Q_value_shift = total_Q_value * fQvalueShifter -> Shift( interaction.InitState().Tgt() ) ;
348  Delta_Q_value += Q_value_shift ;
349  }
350 
351  // We apply an extra Q-value shift here to account for differences between
352  // the 12C EM MEC tensors currently in use (which have a "baked in" Q-value
353  // already incorporated) and the treatment in Guille's thesis. Differences
354  // between the two lead to a few-tens-of-MeV shift in the energy transfer
355  // distribution for EM MEC. The shift is done in terms of the binding energy
356  // value associated with the original tensor (Eb_ten). Corrections for
357  // scaling to a different target are already handled above.
358  // - S. Gardiner, 1 July 2020
359  bool isEM = interaction.ProcInfo().IsEM();
360  if ( isEM ) Delta_Q_value -= 2. * Eb_ten;
361 
362  return Delta_Q_value ;
363 }
364 //_________________________________________________________________________
366 {
367  Algorithm::Configure(config);
368  this->LoadConfig();
369 }
370 //____________________________________________________________________________
372 {
373  Algorithm::Configure(config);
374  this->LoadConfig();
375 }
376 //_________________________________________________________________________
378 {
379  bool good_config = true ;
380  // Cross section scaling factor
381  GetParamDef("MEC-XSecScale", fXSecScale, 1.) ;
382 
383  fHadronTensorModel = dynamic_cast<const HadronTensorModelI*> ( this->SubAlg("HadronTensorAlg") );
384  if( !fHadronTensorModel ) {
385  good_config = false ;
386  LOG("SuSAv2MECPXSec", pERROR) << "The required HadronTensorAlg does not exist. AlgoID is : " << SubAlg("HadronTensorAlg")->Id();
387  }
388 
389  fXSecIntegrator = dynamic_cast<const XSecIntegratorI*> (this->SubAlg("NumericalIntegrationAlg"));
390  if( !fXSecIntegrator ) {
391  good_config = false ;
392  LOG("SuSAv2MECPXSec", pERROR) << "The required NumericalIntegrationAlg does not exist. AlgId is : " << SubAlg("NumericalIntegrationAlg")->Id() ;
393  }
394 
395  //Fermi momentum tables for scaling
396  this->GetParam( "FermiMomentumTable", fKFTable);
397 
398  //binding energy lookups for scaling
399  this->GetParam( "RFG-NucRemovalE@Pdg=1000020040", fEbHe );
400  this->GetParam( "RFG-NucRemovalE@Pdg=1000030060", fEbLi );
401  this->GetParam( "RFG-NucRemovalE@Pdg=1000060120", fEbC );
402  this->GetParam( "RFG-NucRemovalE@Pdg=1000080160", fEbO );
403  this->GetParam( "RFG-NucRemovalE@Pdg=1000120240", fEbMg );
404  this->GetParam( "RFG-NucRemovalE@Pdg=1000180400", fEbAr );
405  this->GetParam( "RFG-NucRemovalE@Pdg=1000200400", fEbCa );
406  this->GetParam( "RFG-NucRemovalE@Pdg=1000260560", fEbFe );
407  this->GetParam( "RFG-NucRemovalE@Pdg=1000280580", fEbNi );
408  this->GetParam( "RFG-NucRemovalE@Pdg=1000501190", fEbSn );
409  this->GetParam( "RFG-NucRemovalE@Pdg=1000791970", fEbAu );
410  this->GetParam( "RFG-NucRemovalE@Pdg=1000822080", fEbPb );
411 
412  // Read optional MECScaleVsW:
413  fMECScaleAlg = nullptr;
414  if( GetConfig().Exists("MECScaleAlg") ) {
415  fMECScaleAlg = dynamic_cast<const XSecScaleI *> ( this->SubAlg("MECScaleAlg") );
416  if( !fMECScaleAlg ) {
417  good_config = false ;
418  LOG("Susav2MECPXSec", pERROR) << "The required MECScaleAlg cannot be casted. AlgID is : " << SubAlg("MECScaleAlg")->Id() ;
419  }
420  }
421 
422  // Read optional QvalueShifter:
423  fQvalueShifter = nullptr;
424  if( GetConfig().Exists("QvalueShifterAlg") ) {
425  fQvalueShifter = dynamic_cast<const QvalueShifter *> ( this->SubAlg("QvalueShifterAlg") );
426  if( !fQvalueShifter ) {
427  good_config = false ;
428  LOG("SuSAv2MECPXSec", pERROR) << "The required QvalueShifterAlg does not exist. AlgId is : " << SubAlg("QvalueShifterAlg")->Id() ;
429  }
430  }
431 
432  if( ! good_config ) {
433  LOG("SuSAv2MECPXSec", pERROR) << "Configuration has failed.";
434  exit(78) ;
435  }
436 
437 }
Cross Section Calculation Interface.
bool IsWeakCC(void) const
bool IsNeutrino(int pdgc)
Definition: PDGUtils.cxx:107
THE MAIN GENIE PROJECT NAMESPACE
Definition: AlgCmp.h:25
#define pERROR
Definition: Messenger.h:59
Cross Section Integrator Interface.
double Q2(const Interaction *const i)
Definition: KineUtils.cxx:1064
int HitNucPdg(void) const
Definition: Target.cxx:304
const genie::HadronTensorModelI * fHadronTensorModel
std::string string
Definition: nybbler.cc:12
const int kPdgClusterNP
Definition: PDGCodes.h:215
This class is responsible to compute a scaling factor for the XSec.
Definition: XSecScaleI.h:25
double XSec(const Interaction *i, KinePhaseSpace_t k) const
Compute the cross section for the input interaction.
int Pdg(void) const
Definition: Target.h:71
int IonPdgCodeToA(int pdgc)
Definition: PDGUtils.cxx:60
static FermiMomentumTablePool * Instance(void)
const XSecIntegratorI * fXSecIntegrator
GSL numerical integrator.
bool IsChargedLepton(int pdgc)
Definition: PDGUtils.cxx:98
Abstract interface for an object that computes the elements ( , , etc.) and structure functions ( ...
A table of Fermi momentum constants.
double PairRatio(const Interaction *i) const
virtual double qMagMin() const =0
enum genie::HadronTensorType HadronTensorType_t
enum genie::EKinePhaseSpace KinePhaseSpace_t
virtual const HadronTensorI * GetTensor(int tensor_pdg, HadronTensorType_t type) const =0
virtual const Registry & GetConfig(void) const
Definition: Algorithm.cxx:246
static const double kMinQ2Limit
Definition: Controls.h:41
double Qvalue(int targetpdg, int nupdg)
Definition: MECUtils.cxx:164
Summary information for an interaction.
Definition: Interaction.h:56
Singleton class to load & serve tables of Fermi momentum constants.
double Integral(const Interaction *i) const
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE...
Definition: Messenger.h:96
virtual double q0Min() const =0
const FermiMomentumTable * GetTable(string name)
virtual double GetScaling(const Interaction &) const =0
static Config * config
Definition: config.cpp:1054
static string AsString(KinePhaseSpace_t kps)
A class encapsulating an enumeration of interaction types (EM, Weak-CC, Weak-NC) and scattering types...
Definition: ProcessInfo.h:46
bool IsAntiNeutrino(int pdgc)
Definition: PDGUtils.cxx:115
const Kinematics & Kine(void) const
Definition: Interaction.h:71
virtual void Configure(const Registry &config)
Definition: Algorithm.cxx:62
int ProbePdg(void) const
Definition: InitialState.h:64
bool Getq0q3FromTlCostl(double Tl, double costl, double Enu, double ml, double &q0, double &q3)
Definition: MECUtils.cxx:121
void LoadConfig(void)
Load algorithm configuration.
double GetKV(KineVar_t kv) const
Definition: Kinematics.cxx:323
#define pWARN
Definition: Messenger.h:60
void Configure(const Registry &config)
virtual double dSigma_dT_dCosTheta_rosenbluth(const Interaction *interaction, double Q_value) const =0
TParticlePDG * FSPrimLepton(void) const
final state primary lepton
bool IsMEC(void) const
bool IsEM(void) const
double Qvalue(const Interaction &interaction) const
Kinematical utilities.
virtual const AlgId & Id(void) const
Get algorithm ID.
Definition: Algorithm.h:97
A registry. Provides the container for algorithm configuration parameters.
Definition: Registry.h:65
const QvalueShifter * fQvalueShifter
virtual double Integrate(const XSecAlgorithmI *model, const Interaction *interaction) const =0
const int kPdgTgtC12
Definition: PDGCodes.h:202
double fXSecScale
External scaling factor for this cross section.
bool ValidProcess(const Interaction *i) const
Can this cross section algorithm handle the input process?
const InitialState & InitState(void) const
Definition: Interaction.h:69
const ProcessInfo & ProcInfo(void) const
Definition: Interaction.h:70
virtual double qMagMax() const =0
Creates hadron tensor objects for use in cross section calculations.
int IonPdgCodeToZ(int pdgc)
Definition: PDGUtils.cxx:52
const int kPdgProton
Definition: PDGCodes.h:81
double FindClosestKF(int target_pdgc, int nucleon_pdgc) const
bool GetParamDef(const RgKey &name, T &p, const T &def) const
bool GetParam(const RgKey &name, T &p, bool is_top_call=true) const
const Target & Tgt(void) const
Definition: InitialState.h:66
const XSecScaleI * fMECScaleAlg
double ProbeE(RefFrame_t rf) const
Most commonly used PDG codes. A set of utility functions to handle PDG codes is provided in PDGUtils...
const UInt_t kISkipProcessChk
if set, skip process validity checks
Definition: Interaction.h:47
virtual double q0Max() const =0
#define pDEBUG
Definition: Messenger.h:63
const Algorithm * SubAlg(const RgKey &registry_key) const
Definition: Algorithm.cxx:345