SuSAv2QELPXSec.cxx
Go to the documentation of this file.
1 //_________________________________________________________________________
2 /*
3  Copyright (c) 2003-2019, 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 
25 
26 using namespace genie;
27 
28 //_________________________________________________________________________
29 SuSAv2QELPXSec::SuSAv2QELPXSec() : XSecAlgorithmI("genie::SuSAv2QELPXSec")
30 {
31 }
32 //_________________________________________________________________________
34  : XSecAlgorithmI("genie::SuSAv2QELPXSec", config)
35 {
36 }
37 //_________________________________________________________________________
39 {
40 }
41 //_________________________________________________________________________
43  KinePhaseSpace_t kps) const
44 {
45  if ( !this->ValidProcess(interaction) ) return 0.;
46 
47  // Get the hadron tensor for the selected nuclide. Check the probe PDG code
48  // to know whether to use the tensor for CC neutrino scattering or for
49  // electron scattering
50  int target_pdg = interaction->InitState().Tgt().Pdg();
51  int probe_pdg = interaction->InitState().ProbePdg();
52  int tensor_pdg = target_pdg;
53  int A_request = pdg::IonPdgCodeToA(target_pdg);
54  bool need_to_scale = false;
55 
56  HadronTensorType_t tensor_type = kHT_Undefined;
57  if ( pdg::IsNeutrino(probe_pdg) || pdg::IsAntiNeutrino(probe_pdg) ) {
58  tensor_type = kHT_QE_Full;
59  }
60  else {
61  // If the probe is not a neutrino, assume that it's an electron
62  tensor_type = kHT_QE_EM;
63  }
64 
65  double Eb_tgt=0;
66  double Eb_ten=0;
67 
68  if ( A_request <= 4 ) {
69  // Use carbon tensor for very light nuclei. This is not ideal . . .
70  tensor_pdg = kPdgTgtC12;
71  Eb_tgt=fEbHe; Eb_ten=fEbC;
72  }
73  else if (A_request < 9) {
74  tensor_pdg = kPdgTgtC12;
75  Eb_tgt=fEbLi; Eb_ten=fEbC;
76  }
77  else if (A_request >= 9 && A_request < 15) {
78  tensor_pdg = kPdgTgtC12;
79  Eb_tgt=fEbC; Eb_ten=fEbC;
80  }
81  else if(A_request >= 15 && A_request < 22) {
82  tensor_pdg = kPdgTgtC12;
83  Eb_tgt=fEbO; Eb_ten=fEbC;
84  }
85  else if(A_request >= 22 && A_request < 40) {
86  tensor_pdg = kPdgTgtC12;
87  Eb_tgt=fEbMg; Eb_ten=fEbC;
88  }
89  else if(A_request >= 40 && A_request < 56) {
90  tensor_pdg = kPdgTgtC12;
91  Eb_tgt=fEbAr; Eb_ten=fEbC;
92  }
93  else if(A_request >= 56 && A_request < 119) {
94  tensor_pdg = kPdgTgtC12;
95  Eb_tgt=fEbFe; Eb_ten=fEbC;
96  }
97  else if(A_request >= 119 && A_request < 206) {
98  tensor_pdg = kPdgTgtC12;
99  Eb_tgt=fEbSn; Eb_ten=fEbC;
100  }
101  else if(A_request >= 206) {
102  tensor_pdg = kPdgTgtC12;
103  Eb_tgt=fEbPb; Eb_ten=fEbC;
104  }
105 
106  if (tensor_pdg != target_pdg) need_to_scale = true;
107 
108  // The SuSAv2-1p1h hadron tensors are defined using the same conventions
109  // as the Valencia MEC (and SuSAv2-MEC) model, so we can use the same sort of tensor
110  // object to describe them.
111  const LabFrameHadronTensorI* tensor
112  = dynamic_cast<const LabFrameHadronTensorI*>( fHadronTensorModel->GetTensor(tensor_pdg,
113  tensor_type) );
114 
115  // If retrieving the tensor failed, complain and return zero
116  if ( !tensor ) {
117  LOG("SuSAv2QE", pWARN) << "Failed to load a hadronic tensor for the"
118  " nuclide " << tensor_pdg;
119  return 0.;
120  }
121 
122  // Check that the input kinematical point is within the range
123  // in which hadron tensors are known (for chosen target)
124  double Ev = interaction->InitState().ProbeE(kRfLab);
125  double Tl = interaction->Kine().GetKV(kKVTl);
126  double costl = interaction->Kine().GetKV(kKVctl);
127  double ml = interaction->FSPrimLepton()->Mass();
128  double Q0 = 0.;
129  double Q3 = 0.;
130 
131  // SD: The Q-Value essentially corrects q0 to account for nuclear
132  // binding energy in the Valencia model but this effect is already
133  // in Guille's tensors so I'll set it to 0.
134  // However, if I want to scale I need to account for the altered
135  // binding energy. To first order I can use the Delta_Q_value for this
136  double Delta_Q_value = Eb_tgt-Eb_ten;
137 
138  // Apply Qvalue relative shift if needed:
139  if( fQvalueShifter ) {
140  // We have the option to add an additional shift on top of the binding energy correction
141  // The QvalueShifter, is a relative shift to the Q_value.
142  // The Q_value was already taken into account in the hadron tensor. Here we recalculate it
143  // to get the right absolute shift.
144  double tensor_Q_value = genie::utils::mec::Qvalue(tensor_pdg,probe_pdg);
145  double total_Q_value = tensor_Q_value + Delta_Q_value ;
146  double Q_value_shift = total_Q_value * fQvalueShifter -> Shift( interaction->InitState().Tgt() ) ;
147  Delta_Q_value += Q_value_shift ;
148  }
149 
150  genie::utils::mec::Getq0q3FromTlCostl(Tl, costl, Ev, ml, Q0, Q3);
151 
152  double Q0min = tensor->q0Min();
153  double Q0max = tensor->q0Max();
154  double Q3min = tensor->qMagMin();
155  double Q3max = tensor->qMagMax();
156  if (Q0-Delta_Q_value < Q0min || Q0-Delta_Q_value > Q0max || Q3 < Q3min || Q3 > Q3max) {
157  return 0.0;
158  }
159 
160  // *** Enforce the global Q^2 cut (important for EM scattering) ***
161  // Choose the appropriate minimum Q^2 value based on the interaction
162  // mode (this is important for EM interactions since the differential
163  // cross section blows up as Q^2 --> 0)
164  double Q2min = genie::controls::kMinQ2Limit; // CC/NC limit
165  if ( interaction->ProcInfo().IsEM() ) Q2min = genie::utils::kinematics
166  ::electromagnetic::kMinQ2Limit; // EM limit
167 
168  // Neglect shift due to binding energy. The cut is on the actual
169  // value of Q^2, not the effective one to use in the tensor contraction.
170  double Q2 = Q3*Q3 - Q0*Q0;
171  if ( Q2 < Q2min ) return 0.;
172 
173  // Compute the cross section using the hadron tensor
174  double xsec = tensor->dSigma_dT_dCosTheta_rosenbluth(interaction, Delta_Q_value);
175  LOG("SuSAv2QE", pDEBUG) << "XSec in cm2 / neutron is " << xsec/(units::cm2);
176 
177  // Currently the SuSAv2 QE hadron tensors are given per active nucleon, but
178  // the calculation above assumes they are per atom. Need to adjust for this.
179  const ProcessInfo& proc_info = interaction->ProcInfo();
180 
181  // Neutron, proton, and mass numbers of the target
182  const Target& tgt = interaction->InitState().Tgt();
183  if ( proc_info.IsWeakCC() ) {
184  if ( pdg::IsNeutrino(probe_pdg) ) xsec *= tgt.N();
185  else if ( pdg::IsAntiNeutrino(probe_pdg) ) xsec *= tgt.Z();
186  else {
187  // We should never get here if ValidProcess() is working correctly
188  LOG("SuSAv2QE", pERROR) << "Unrecognized probe " << probe_pdg
189  << " encountered for a WeakCC process";
190  xsec = 0.;
191  }
192  }
193  else if ( proc_info.IsEM() || proc_info.IsWeakNC() ) {
194  // For EM processes, scale by the number of nucleons of the same type
195  // as the struck one. This ensures the correct ratio of initial-state
196  // p vs. n when making splines. The nuclear cross section is obtained
197  // by scaling by A/2 for an isoscalar target, so we can get the right
198  // behavior for all targets by scaling by Z/2 or N/2 as appropriate.
199  // Do the same for NC. TODO: double-check that this is the right
200  // thing to do when we SuSAv2 NC hadronic tensors are added to GENIE.
201  int hit_nuc_pdg = tgt.HitNucPdg();
202  if ( pdg::IsProton(hit_nuc_pdg) ) xsec *= tgt.Z() / 2.;
203  else if ( pdg::IsNeutron(hit_nuc_pdg) ) xsec *= tgt.N() / 2.;
204  // We should never get here if ValidProcess() is working correctly
205  else return 0.;
206  }
207  else {
208  // We should never get here if ValidProcess() is working correctly
209  LOG("SuSAv2QE", pERROR) << "Unrecognized process " << proc_info.AsString()
210  << " encountered in SuSAv2QELPXSec::XSec()";
211  xsec = 0.;
212  }
213 
214  LOG("SuSAv2QE", pDEBUG) << "XSec in cm2 / atom is " << xsec / units::cm2;
215 
216  // This scaling should be okay-ish for the total xsec, but it misses
217  // the energy shift. To get this we should really just build releveant
218  // hadron tensors but there may be some ways to approximate it.
219  // For more details see Guille's thesis: https://idus.us.es/xmlui/handle/11441/74826
220  if ( need_to_scale ) {
222  const FermiMomentumTable * kft = kftp->GetTable(fKFTable);
223  double KF_tgt = kft->FindClosestKF(target_pdg, kPdgProton);
224  double KF_ten = kft->FindClosestKF(tensor_pdg, kPdgProton);
225  LOG("SuSAv2QE", pDEBUG) << "KF_tgt = " << KF_tgt;
226  LOG("SuSAv2QE", pDEBUG) << "KF_ten = " << KF_ten;
227  double scaleFact = (KF_ten/KF_tgt); // A-scaling already applied in section above
228  xsec *= scaleFact;
229  }
230 
231  // Apply given overall scaling factor
232  xsec *= fXSecScale;
233 
234  if ( kps != kPSTlctl ) {
235  LOG("SuSAv2QE", pWARN)
236  << "Doesn't support transformation from "
237  << KinePhaseSpace::AsString(kPSTlctl) << " to "
238  << KinePhaseSpace::AsString(kps);
239  xsec = 0.;
240  }
241 
242  return xsec;
243 }
244 //_________________________________________________________________________
246 {
247  double xsec = fXSecIntegrator->Integrate(this, interaction);
248  return xsec;
249 }
250 //_________________________________________________________________________
252 {
253  if ( interaction->TestBit(kISkipProcessChk) ) return true;
254 
255  const InitialState & init_state = interaction->InitState();
256  const ProcessInfo & proc_info = interaction->ProcInfo();
257 
258  if ( !proc_info.IsQuasiElastic() ) return false;
259 
260  // The SuSAv2 calculation is only appropriate for complex nuclear targets,
261  // not free nucleons.
262  if ( !init_state.Tgt().IsNucleus() ) return false;
263 
264  int nuc = init_state.Tgt().HitNucPdg();
265  int nu = init_state.ProbePdg();
266 
267  bool isP = pdg::IsProton(nuc);
268  bool isN = pdg::IsNeutron(nuc);
269  bool isnu = pdg::IsNeutrino(nu);
270  bool isnub = pdg::IsAntiNeutrino(nu);
271  bool is_chgl = pdg::IsChargedLepton(nu);
272 
273  bool prcok = ( proc_info.IsWeakCC() && ((isP && isnub) || (isN && isnu)) )
274  || ( proc_info.IsEM() && is_chgl && (isP || isN) );
275  if ( !prcok ) return false;
276 
277  return true;
278 }
279 //_________________________________________________________________________
281 {
282  Algorithm::Configure(config);
283  this->LoadConfig();
284 }
285 //____________________________________________________________________________
287 {
288  Algorithm::Configure(config);
289  this->LoadConfig();
290 }
291 //_________________________________________________________________________
293 {
294  bool good_config = true ;
295 
296  // Cross section scaling factor
297  GetParam( "QEL-CC-XSecScale", fXSecScale ) ;
298 
299  fHadronTensorModel = dynamic_cast< const SuSAv2QELHadronTensorModel* >(
300  this->SubAlg("HadronTensorAlg") );
301  assert( fHadronTensorModel );
302 
303  // Load XSec Integrator
304  fXSecIntegrator = dynamic_cast<const XSecIntegratorI *>(
305  this->SubAlg("XSec-Integrator") );
306  assert( fXSecIntegrator );
307 
308  // Fermi momentum tables for scaling
309  this->GetParam( "FermiMomentumTable", fKFTable);
310 
311  // Binding energy lookups for scaling
312  this->GetParam( "RFG-NucRemovalE@Pdg=1000020040", fEbHe );
313  this->GetParam( "RFG-NucRemovalE@Pdg=1000030060", fEbLi );
314  this->GetParam( "RFG-NucRemovalE@Pdg=1000060120", fEbC );
315  this->GetParam( "RFG-NucRemovalE@Pdg=1000080160", fEbO );
316  this->GetParam( "RFG-NucRemovalE@Pdg=1000120240", fEbMg );
317  this->GetParam( "RFG-NucRemovalE@Pdg=1000180400", fEbAr );
318  this->GetParam( "RFG-NucRemovalE@Pdg=1000200400", fEbCa );
319  this->GetParam( "RFG-NucRemovalE@Pdg=1000260560", fEbFe );
320  this->GetParam( "RFG-NucRemovalE@Pdg=1000280580", fEbNi );
321  this->GetParam( "RFG-NucRemovalE@Pdg=1000501190", fEbSn );
322  this->GetParam( "RFG-NucRemovalE@Pdg=1000791970", fEbAu );
323  this->GetParam( "RFG-NucRemovalE@Pdg=1000822080", fEbPb );
324 
325  // Read optional QvalueShifter:
326  // Read optional QvalueShifter:
327  fQvalueShifter = nullptr;
328  if( GetConfig().Exists("QvalueShifterAlg") ) {
329 
330  fQvalueShifter = dynamic_cast<const QvalueShifter *> ( this->SubAlg("QvalueShifterAlg") );
331 
332  if( !fQvalueShifter ) {
333 
334  good_config = false ;
335 
336  LOG("SuSAv2QE", pERROR) << "The required QvalueShifterAlg is not valid. AlgID is : "
337  << SubAlg("QvalueShifterAlg")->Id() ;
338  }
339  } // if there is a requested QvalueShifteralgo
340  if( ! good_config ) {
341  LOG("SuSAv2QE", pERROR) << "Configuration has failed.";
342  exit(78) ;
343  }
344 
345 
346 }
Cross Section Calculation Interface.
void LoadConfig(void)
Load algorithm configuration.
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
std::string string
Definition: nybbler.cc:12
bool IsQuasiElastic(void) const
Definition: ProcessInfo.cxx:69
const XSecIntegratorI * fXSecIntegrator
GSL numerical integrator.
const QvalueShifter * fQvalueShifter
bool IsNucleus(void) const
Definition: Target.cxx:272
int Pdg(void) const
Definition: Target.h:71
int IonPdgCodeToA(int pdgc)
Definition: PDGUtils.cxx:60
static FermiMomentumTablePool * Instance(void)
bool IsChargedLepton(int pdgc)
Definition: PDGUtils.cxx:98
Creates hadron tensor objects for calculations of quasielastic cross sections using the SuSAv2 approa...
Abstract interface for an object that computes the elements ( , , etc.) and structure functions ( ...
A table of Fermi momentum constants.
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
double XSec(const Interaction *i, KinePhaseSpace_t k) const
Compute the cross section for the input interaction.
virtual const Registry & GetConfig(void) const
Definition: Algorithm.cxx:246
static const double kMinQ2Limit
Definition: Controls.h:41
bool IsNeutron(int pdgc)
Definition: PDGUtils.cxx:338
double Qvalue(int targetpdg, int nupdg)
Definition: MECUtils.cxx:164
Summary information for an interaction.
Definition: Interaction.h:56
bool IsProton(int pdgc)
Definition: PDGUtils.cxx:333
bool IsWeakNC(void) const
Singleton class to load & serve tables of Fermi momentum constants.
#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)
static constexpr double cm2
Definition: Units.h:69
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
A Neutrino Interaction Target. Is a transparent encapsulation of quite different physical systems suc...
Definition: Target.h:40
virtual void Configure(const Registry &config)
Definition: Algorithm.cxx:62
int ProbePdg(void) const
Definition: InitialState.h:64
string AsString(void) const
bool Getq0q3FromTlCostl(double Tl, double costl, double Enu, double ml, double &q0, double &q3)
Definition: MECUtils.cxx:121
int Z(void) const
Definition: Target.h:68
double GetKV(KineVar_t kv) const
Definition: Kinematics.cxx:323
const HadronTensorModelI * fHadronTensorModel
double fXSecScale
External scaling factor for this cross section.
#define pWARN
Definition: Messenger.h:60
virtual double dSigma_dT_dCosTheta_rosenbluth(const Interaction *interaction, double Q_value) const =0
TParticlePDG * FSPrimLepton(void) const
final state primary lepton
bool IsEM(void) const
bool ValidProcess(const Interaction *i) const
Can this cross section algorithm handle the input process?
Kinematical utilities.
virtual const AlgId & Id(void) const
Get algorithm ID.
Definition: Algorithm.h:97
int N(void) const
Definition: Target.h:69
A registry. Provides the container for algorithm configuration parameters.
Definition: Registry.h:65
virtual double Integrate(const XSecAlgorithmI *model, const Interaction *interaction) const =0
const int kPdgTgtC12
Definition: PDGCodes.h:202
const InitialState & InitState(void) const
Definition: Interaction.h:69
const ProcessInfo & ProcInfo(void) const
Definition: Interaction.h:70
virtual double qMagMax() const =0
const int kPdgProton
Definition: PDGCodes.h:81
void Configure(const Registry &config)
double FindClosestKF(int target_pdgc, int nucleon_pdgc) const
bool GetParam(const RgKey &name, T &p, bool is_top_call=true) const
const Target & Tgt(void) const
Definition: InitialState.h:66
double Integral(const Interaction *i) const
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
Initial State information.
Definition: InitialState.h:48
#define pDEBUG
Definition: Messenger.h:63
const Algorithm * SubAlg(const RgKey &registry_key) const
Definition: Algorithm.cxx:345