GENIEGenerator
Loading...
Searching...
No Matches
EmpiricalMECPXSec2015.cxx
Go to the documentation of this file.
1//____________________________________________________________________________
2/*
3 Copyright (c) 2003-2025, The GENIE Collaboration
4 For the full text of the license visit http://copyright.genie-mc.org
5
6 Costas Andreopoulos <c.andreopoulos \at cern.ch>
7 University of Liverpool
8
9 Steve Dytman <dytman+ \at pitt.edu>
10 Pittsburgh University
11*/
12//____________________________________________________________________________
13
14#include <TMath.h>
15
19#include "Framework/Conventions/GBuild.h"
28
29using namespace genie;
30using namespace genie::constants;
31using namespace genie::controls;
32
33//____________________________________________________________________________
35XSecAlgorithmI("genie::EmpiricalMECPXSec2015")
36{
37
38}
39//____________________________________________________________________________
41XSecAlgorithmI("genie::EmpiricalMECPXSec2015", config)
42{
43
44}
45//____________________________________________________________________________
50//____________________________________________________________________________
52 const Interaction * interaction, KinePhaseSpace_t kps) const
53{
54
55 // If we've been asked for the kPSTlctl phase space, get W and Q^2 from those
56 // variables. You actually need the lepton phi set in order to do the
57 // conversion (see the "important note" in src/Framework/Utils/KineUtils.cxx
58 // about the kPSTlctl --> kPSWQ2fE Jacobian) when Fermi motion is properly
59 // taken into account. For now, I neglect Fermi motion as a stopgap solution.
60 // - S. Gardiner, 29 July 2020
61 if ( kps == kPSTlctl ) {
62
63 // {Tl, ctl} --> {W, Q2}
64
65 // Probe properties (mass, energy, momentum)
66 const InitialState& init_state = interaction->InitState();
67 double mv = init_state.Probe()->Mass();
68 double Ev = init_state.ProbeE( kRfLab );
69 double pv = std::sqrt( std::max(0., Ev*Ev - mv*mv) );
70
71 // Invariant mass of the initial hit nucleon
72 const TLorentzVector& hit_nuc_P4 = init_state.Tgt().HitNucP4();
73 double M = hit_nuc_P4.M();
74
75 // Outgoing lepton mass
76 double ml = interaction->FSPrimLepton()->Mass();
77
78 // Lab-frame lepton kinetic energy and scattering cosine
79 double Tl = interaction->Kine().GetKV( kKVTl );
80 double ctl = interaction->Kine().GetKV( kKVctl );
81
82 // Q^2 from Tl and ctl
83 double El = Tl + ml;
84 double pl = std::sqrt( Tl*Tl + 2.*ml*Tl );
85 double Q2 = -mv*mv - ml*ml + 2.*Ev*El - 2.*pv*pl*ctl;
86
87 // Energy transfer
88 double omega = Ev - El;
89
90 double W = std::sqrt( std::max(0., M*M - Q2 + 2.*omega*M) );
91
92 interaction->KinePtr()->SetW( W );
93 interaction->KinePtr()->SetQ2( Q2 );
94 }
95
96
97// meson exchange current contribution depends a lot on QE model.
98// This is an empirical model in development, not used in default event generation.
99
100// if(! this -> ValidProcess (interaction) ) return 0.;
101// if(! this -> ValidKinematics (interaction) ) return 0.;
102 bool iscc = interaction->ProcInfo().IsWeakCC();
103 bool isnc = interaction->ProcInfo().IsWeakNC();
104 bool isem = interaction->ProcInfo().IsEM();
105
106 const Kinematics & kinematics = interaction -> Kine();
107 double W = kinematics.W();
108 double Q2 = kinematics.Q2();
109 //LOG("MEC", pINFO) << "W, Q2 trial= " << W << " " << Q2 ;
110
111 //
112 // Do a check whether W,Q2 is allowed. Return 0 otherwise.
113 //
114 double Ev = interaction->InitState().ProbeE(kRfHitNucRest); // kRfLab
115 int nucleon_cluster_pdg = interaction->InitState().Tgt().HitNucPdg();
116 double M2n = PDGLibrary::Instance()->Find(nucleon_cluster_pdg)-> Mass(); // nucleon cluster mass
117 double M2n2 = M2n*M2n;
118 double ml = interaction->FSPrimLepton()->Mass();
120
121 //LOG("MEC", pINFO) << "Ev, ml, M2n = " << Ev << " " << ml << " " << M2n;
122 //LOG("MEC", pINFO) << "Wlim= " << Wlim.min << " " <<Wlim.max ;
123 if(W < Wlim.min || W > Wlim.max)
124 {double xsec = 0.;
125 return xsec;
126 }
127 //use proper Q2 limit from Controls.h
129
130 //LOG("MEC", pINFO) << "Q2lim= " << Q2lim.min << " " <<Q2lim.max ;
131 if(Q2 < Q2lim.min || Q2 > Q2lim.max)
132 {double xsec = 0.;
133 return xsec;
134 }
135
136 //get x and y
137 double x = 0.;
138 double y = 0.;
139 genie::utils::kinematics::WQ2toXY(Ev,M2n,W,Q2,x,y);
140 // LOG("MEC", pINFO) << "x = " << x << ", y = " << y;
141 // double Tmu = (1.-y)*Ev; // UNUSED - comment to quiet compiler warnings
142
143 // Calculate d^2xsec/dWdQ2 - first form factor which is common to both
144 double Wdep = TMath::Gaus(W, fMass, fWidth);
145 double Q2dep = Q2*TMath::Power((1+Q2/fMq2d),-8.);
146 // double nudep = TMath::Power(Tmu,2.5);
147 // LOG("MEC", pINFO) << "Tmu = " << Tmu << ", nudep = " << nudep;
148 double FF2 = Wdep * Q2dep;// * nudep;
149 //LOG("MEC", pINFO) << "form factor = " << FF2 << ", Q2 = " << Q2 << ", W = " << W;
150
151// using formulas in Bodek and Budd for (e,e') inclusive cross section
152 double xsec = 1.;
153 if(isem) {
154 // Calculate scattering angle
155 //
156 // Q^2 = 4 * E^2 * sin^2 (theta/2) / ( 1 + 2 * (E/M) * sin^2(theta/2) ) =>
157 // sin^2 (theta/2) = MQ^2 / (4ME^2 - 2EQ^2)
158
159 double E = Ev;
160 double E2 = E*E;
161 double sin2_halftheta = M2n*Q2 / (4*M2n*E2 - 2*E*Q2);
162 // double sin4_halftheta = TMath::Power(sin2_halftheta, 2.);
163 double cos2_halftheta = 1.-sin2_halftheta;
164 // double cos_halftheta = TMath::Sqrt(cos2_halftheta);
165 double tan2_halftheta = sin2_halftheta/cos2_halftheta;
166 double Q4 = Q2*Q2;
167
168 // Calculate tau and the virtual photon polarization (epsilon)
169 double tau = Q2/(4*M2n2);
170 // double epsilon = 1. / (1. + 2.*(tau/x))*tan2_halftheta); //different than RosenbluthPXSec.cxx
171
172 // Calculate the scattered lepton energy
173 double Ep = E / (1. + 2.*(E/M2n)*sin2_halftheta);
174 double Ep2 = Ep*Ep;
175
176 //calculate cross section - d2sig/dOmega dE for purely transverse process
177 xsec = 4*kAem2*Ep2*cos2_halftheta/Q4 * FF2 * (tau/(1+tau) +2*tau*tan2_halftheta);
178 }
179 // use BB formula which seems to be same as Llewlyn-Smith
180 // note B term is only difference between nu and antinu, so both same here
181 else if(isnc||iscc){
182 double tau = Q2/(4*M2n2);
183 double tau2 = tau*tau;
184 double smufac = 4*M2n*Ev - Q2 - ml*ml;
185 double A = (ml*ml+Q2)/M2n2 * (tau*(1+tau) - tau2*(1-tau)+4*tau2)/TMath::Power(1+tau,2.) * FF2;
186 double C = tau/4/(1+tau) * FF2;
187 xsec = A + smufac*smufac*C; // CC or NC case - Llewelyn-Smith for transverse vector process.
188 }
189 // Check whether variable tranformation is needed
190 if ( kps!=kPSWQ2fE && xsec != 0. ) {
191 double J = utils::kinematics::Jacobian(interaction,kPSWQ2fE,kps);
192#ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
193 LOG("MEC", pDEBUG)
194 << "Jacobian for transformation to: "
195 << KinePhaseSpace::AsString(kps) << ", J = " << J;
196#endif
197 xsec *= J;
198 }
199
200 return xsec;
201}
202//____________________________________________________________________________
203double EmpiricalMECPXSec2015::Integral(const Interaction * interaction) const
204{
205 // Normally the empirical MEC splines are computed as a fraction of the CCQE
206 // ones. In cases where we want to integrate the differential cross section
207 // directly (e.g., for reweighting via the XSecShape_CCMEC dial), do that
208 // instead.
210 return fXSecIntegrator->Integrate( this, interaction );
211 }
212
213// Calculate the CCMEC cross section as a fraction of the CCQE cross section
214// for the given nuclear target at the given energy.
215// Alternative strategy is to calculate the MEC cross section as the difference
216// of CCQE cross section for two different M_A values (eg ~1.3 GeV and ~1.0 GeV)
217// Include hit-object combinatorial factor? Would yield different A-dependence
218// for MEC and QE.
219//
220
221 bool iscc = interaction->ProcInfo().IsWeakCC();
222 bool isnc = interaction->ProcInfo().IsWeakNC();
223 bool isem = interaction->ProcInfo().IsEM();
224
225 int nupdg = interaction->InitState().ProbePdg();
226 int tgtpdg = interaction->InitState().Tgt().Pdg();
227 double E = interaction->InitState().ProbeE(kRfLab);
228 int nucleon_cluster_pdg = interaction->InitState().Tgt().HitNucPdg();
229 double Z=interaction->InitState().Tgt().Z();
230 double A=interaction->InitState().Tgt().A();
231 double N=A-Z;
232
233 if(iscc) {
234
235 int nucpdg = 0;
236 // neutrino CC: calculate the CCQE cross section resetting the
237 // hit nucleon cluster to neutron
238 if(pdg::IsNeutrino(nupdg)) {
239 nucpdg = kPdgNeutron;
240 }
241 // anti-neutrino CC: calculate the CCQE cross section resetting the
242 // hit nucleon cluster to proton
243 else
244 if(pdg::IsAntiNeutrino(nupdg)) {
245 nucpdg = kPdgProton;
246 }
247 else {
248 exit(1);
249 }
250
251 // Create a tmp QE process
252 Interaction * in = Interaction::QELCC(tgtpdg,nucpdg,nupdg,E);
253
254 // Calculate cross section for the QE process
255 double xsec = fXSecAlgCCQE->Integral(in);
256
257 // Add A dependence which is not known from theory
258 double fFracADep = 1.;
259 if(A>=12) fFracADep = TMath::Power((N/6.),fMECAPower-1.);
260
261 // Use tunable fraction
262 // FFracCCQE is fraction of QE going to MEC
263 // fFracCCQE_cluster is fraction of MEC going to each NN pair
264 // double fFracCCQE = fFracCCQElo;
265
266 double fFracCCQE_cluster=0.;
267 if(pdg::IsNeutrino(nupdg) && nucleon_cluster_pdg==2000000201) fFracCCQE_cluster= fFracPN_CC; //n+p
268 if(pdg::IsNeutrino(nupdg) && nucleon_cluster_pdg==2000000200) fFracCCQE_cluster= 1.0-fFracPN_CC; //n+n
269 if(pdg::IsAntiNeutrino(nupdg) && nucleon_cluster_pdg==2000000201) fFracCCQE_cluster= fFracPN_CC; //n+p
270 if(pdg::IsAntiNeutrino(nupdg) && nucleon_cluster_pdg==2000000202) fFracCCQE_cluster= 1.0-fFracPN_CC; //p+p
271
272
273 xsec *= fFracCCQE*fFracCCQE_cluster*fFracADep;
274
275 // Use gross combinatorial factor (number of 2-nucleon targets over number
276 // of 1-nucleon targets) : (A-1)/2
277 // double combfact = (in->InitState().Tgt().A()-1)/2.;
278 // xsec *= combfact;
279
280 delete in;
281 return xsec;
282 }
283
284 else if(isnc) {
285 int nucpdg = kPdgProton;
286 // Create a tmp QE process
287 Interaction * inp = Interaction::QELNC(tgtpdg,nucpdg,nupdg,E);
288 nucpdg = kPdgNeutron;
289 // Create a tmp QE process
290 Interaction * inn = Interaction::QELNC(tgtpdg,nucpdg,nupdg,E);
291
292 // Calculate cross section for the QE process - avg of p and n - best for isoscalar nuclei
293 double xsec = (Z*fXSecAlgNCQE->Integral(inp) + N*fXSecAlgNCQE->Integral(inn))/A;
294
295 // Add A dependence which is not known from theory
296 double fFracADep = 1.;
297 if(A>=12) fFracADep = TMath::Power((A/12.),fMECAPower-1.);
298
299 // Use tunable fraction
300 // FFracNCQE is fraction of QE going to MEC
301 // fFracNCQE_cluster is fraction of MEC going to each NN pair
302 double fFracNCQE_cluster=0.;
303 if(nucleon_cluster_pdg==2000000200) fFracNCQE_cluster= 0.5*(1-fFracPN_NC); //n+n
304 if(nucleon_cluster_pdg==2000000201) fFracNCQE_cluster= fFracPN_NC; //n+p
305 if(nucleon_cluster_pdg==2000000202) fFracNCQE_cluster= 0.5*(1-fFracPN_NC); //p+p
306 xsec *= fFracNCQE*fFracNCQE_cluster*fFracADep;
307 delete inn;
308 delete inp;
309 return xsec;
310 }
311
312 else if(isem) {
313 int nucpdg = kPdgProton;
314 // Create a tmp QE process
315 Interaction * inp = Interaction::QELEM(tgtpdg,nucpdg,nupdg,E);
316 nucpdg = kPdgNeutron;
317 // Create a tmp QE process
318 Interaction * inn = Interaction::QELEM(tgtpdg,nucpdg,nupdg,E);
319
320 // Calculate cross section for the QE process - avg of p and n - best for isoscalar nuclei
321 double xsec = (Z*fXSecAlgEMQE->Integral(inp) + N*fXSecAlgEMQE->Integral(inn))/A;
322
323 // Add A dependence which is not known from theory, data wants high A suppression
324 double fFracADep = 1.;
325 if(A>=12) fFracADep = TMath::Power((A/12.),fMECAPower-1.);
326
327 // Use tunable fraction
328 // FFracEMQE is fraction of QE going to MEC
329 // fFracEMQE_cluster is fraction of MEC going to each NN pair
330 double fFracEMQE_cluster=0.;
331 if(nucleon_cluster_pdg==2000000200) fFracEMQE_cluster= 0.5*(1-fFracPN_EM); //n+n
332 if(nucleon_cluster_pdg==2000000201) fFracEMQE_cluster= fFracPN_EM; //n+p
333 if(nucleon_cluster_pdg==2000000202) fFracEMQE_cluster= 0.5*(1-fFracPN_EM); //p+p
334 xsec *= fFracEMQE*fFracEMQE_cluster*fFracADep;
335 delete inn;
336 delete inp;
337 return xsec;
338 }
339
340 return 0;
341}
342//____________________________________________________________________________
344{
345 if(interaction->TestBit(kISkipProcessChk)) return true;
346
347 const ProcessInfo & proc_info = interaction->ProcInfo();
348 if(!proc_info.IsMEC()) return false;
349
350 return true;
351}
352//____________________________________________________________________________
354{
355 Algorithm::Configure(config);
356 this->LoadConfig();
357}
358//____________________________________________________________________________
360{
361 Algorithm::Configure(config);
362
363 Registry* algos = AlgConfigPool::Instance() -> GlobalParameterList() ;
364 string global_key_head = "XSecModel@genie::EventGenerator/" ;
365 string local_key_head = "XSecModel-" ;
366
367 Registry r( "EmpiricalMECPXSec2015_specific", false ) ;
368 r.Set( local_key_head + "QEL-NC", algos -> GetAlg( global_key_head + "QEL-NC") ) ;
369 r.Set( local_key_head + "QEL-CC", algos -> GetAlg( global_key_head + "QEL-CC") ) ;
370 r.Set( local_key_head + "QEL-EM", algos -> GetAlg( global_key_head + "QEL-EM") ) ;
371
373
374 this->LoadConfig();
375}
376//____________________________________________________________________________
378{
379 fXSecAlgCCQE = 0;
380 fXSecAlgNCQE = 0;
381 fXSecAlgEMQE = 0;
382
383 GetParam( "EmpiricalMEC-Mq2d", fMq2d ) ;
384 GetParam( "EmpiricalMEC-Mass", fMass ) ;
385 GetParam( "EmpiricalMEC-Width", fWidth ) ;
386 GetParam( "EmpiricalMEC-APower", fMECAPower ) ;
387
388 GetParam( "EmpiricalMEC-FracPN_NC", fFracPN_NC ) ;
389 GetParam( "EmpiricalMEC-FracPN_CC", fFracPN_CC ) ;
390 GetParam( "EmpiricalMEC-FracPN_EM", fFracPN_EM ) ;
391
392 GetParam( "EmpiricalMEC-FracCCQE", fFracCCQE ) ;
393 GetParam( "EmpiricalMEC-FracNCQE", fFracNCQE ) ;
394 GetParam( "EmpiricalMEC-FracEMQE", fFracEMQE ) ;
395
396 string key_head = "XSecModel-" ;
397
399 dynamic_cast<const XSecAlgorithmI *> ( this -> SubAlg( key_head + "QEL-NC" ) ) ;
400 assert(fXSecAlgNCQE);
401
403 dynamic_cast<const XSecAlgorithmI *> ( this -> SubAlg( key_head + "QEL-CC" ) ) ;
404 assert(fXSecAlgCCQE);
405
407 dynamic_cast<const XSecAlgorithmI *> ( this -> SubAlg( key_head + "QEL-EM" ) ) ;
408 assert(fXSecAlgEMQE);
409
410 // Get the "fast" configuration of MECXSec. This will be used when integrating
411 // the total cross section for reweighting purposes.
413 fXSecIntegrator = dynamic_cast<const XSecIntegratorI*>( algf->AdoptAlgorithm(
414 "genie::MECXSec", "Fast") );
415 assert( fXSecIntegrator );
416
418 GetParamDef( "IntegrateForReweighting", fIntegrateForReweighting, false );
419}
420//____________________________________________________________________________
#define pDEBUG
Definition Messenger.h:63
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE,...
Definition Messenger.h:96
Most commonly used PDG codes. A set of utility functions to handle PDG codes is provided in PDGUtils.
static AlgConfigPool * Instance()
The GENIE Algorithm Factory.
Definition AlgFactory.h:39
static AlgFactory * Instance()
Algorithm * AdoptAlgorithm(const AlgId &algid) const
bool GetParam(const RgKey &name, T &p, bool is_top_call=true) const
virtual void Configure(const Registry &config)
Definition Algorithm.cxx:62
bool GetParamDef(const RgKey &name, T &p, const T &def) const
const Algorithm * SubAlg(const RgKey &registry_key) const
const XSecAlgorithmI * fXSecAlgEMQE
cross section algorithm for EMQE
double fFracPN_NC
toy model param: fraction of nucleon pairs that are pn, not nn or pp
double fFracEMQE
empirical model param: MEC cross section is taken to be this fraction of Rosenbluth xs
const XSecAlgorithmI * fXSecAlgNCQE
cross section algorithm for NCQE
double fWidth
toy model param: width of W distribution (GeV)
const XSecAlgorithmI * fXSecAlgCCQE
cross section algorithm for CCQE
double fFracPN_CC
toy model param: fraction of nucleon pairs that are pn, not nn or pp
double XSec(const Interaction *i, KinePhaseSpace_t k) const
Compute the cross section for the input interaction.
double fMass
toy model param: peak of W distribution (GeV)
const XSecIntegratorI * fXSecIntegrator
Integrator used for reweighting.
double fMq2d
toy model param: ‘mass’ in dipole (Q2 - dependence) form factor (GeV)
double fFracCCQE
empirical model param: MEC cross section is taken to be this fraction of CCQE cross section
double Integral(const Interaction *i) const
double fFracNCQE
empirical model param: MEC cross section is taken to be this fraction of NCQE cross section
void Configure(const Registry &config)
double fMECAPower
power of A relative to carbon
bool ValidProcess(const Interaction *i) const
Can this cross section algorithm handle the input process?
double fFracPN_EM
toy model param: fraction of nucleon pairs that are pn, not nn or pp
Initial State information.
const Target & Tgt(void) const
TParticlePDG * Probe(void) const
int ProbePdg(void) const
double ProbeE(RefFrame_t rf) const
Summary information for an interaction.
Definition Interaction.h:56
const Kinematics & Kine(void) const
Definition Interaction.h:71
static Interaction * QELCC(int tgt, int nuc, int probe, double E=0)
static Interaction * QELEM(int tgt, int nuc, int probe, double E=0)
const ProcessInfo & ProcInfo(void) const
Definition Interaction.h:70
static Interaction * QELNC(int tgt, int nuc, int probe, double E=0)
TParticlePDG * FSPrimLepton(void) const
final state primary lepton
const InitialState & InitState(void) const
Definition Interaction.h:69
Kinematics * KinePtr(void) const
Definition Interaction.h:76
static string AsString(KinePhaseSpace_t kps)
Generated/set kinematical variables for an event.
Definition Kinematics.h:39
void SetQ2(double Q2, bool selected=false)
double Q2(bool selected=false) const
double GetKV(KineVar_t kv) const
double W(bool selected=false) const
void SetW(double W, bool selected=false)
static PDGLibrary * Instance(void)
TParticlePDG * Find(int pdgc, bool must_exist=true)
A class encapsulating an enumeration of interaction types (EM, Weak-CC, Weak-NC) and scattering types...
Definition ProcessInfo.h:46
bool IsWeakNC(void) const
bool IsWeakCC(void) const
bool IsEM(void) const
bool IsMEC(void) const
A simple [min,max] interval for doubles.
Definition Range1.h:43
A registry. Provides the container for algorithm configuration parameters.
Definition Registry.h:65
void Set(RgIMapPair entry)
Definition Registry.cxx:267
int HitNucPdg(void) const
Definition Target.cxx:304
const TLorentzVector & HitNucP4(void) const
Definition Target.h:91
int Z(void) const
Definition Target.h:68
int A(void) const
Definition Target.h:70
int Pdg(void) const
Definition Target.h:71
Cross Section Integrator Interface.
Basic constants.
Misc GENIE control constants.
static const double kMinQ2Limit
Definition Controls.h:41
bool IsNeutrino(int pdgc)
Definition PDGUtils.cxx:110
bool IsAntiNeutrino(int pdgc)
Definition PDGUtils.cxx:118
Range1D_t InelWLim(double El, double ml, double M)
Range1D_t InelQ2Lim_W(double El, double ml, double M, double W)
void WQ2toXY(double Ev, double M, double W, double Q2, double &x, double &y)
Range1D_t InelWLim(double Ev, double M, double ml)
double Jacobian(const Interaction *const i, KinePhaseSpace_t f, KinePhaseSpace_t t)
Range1D_t InelQ2Lim_W(double Ev, double M, double ml, double W, double Q2min_cut=controls::kMinQ2Limit)
THE MAIN GENIE PROJECT NAMESPACE
Definition AlgCmp.h:25
const int kPdgProton
Definition PDGCodes.h:81
const int kPdgNeutron
Definition PDGCodes.h:83
@ kKVTl
Definition KineVar.h:38
@ kKVctl
Definition KineVar.h:39
enum genie::EKinePhaseSpace KinePhaseSpace_t
@ kRfHitNucRest
Definition RefFrame.h:30
@ kRfLab
Definition RefFrame.h:26
const UInt_t kISkipProcessChk
if set, skip process validity checks
Definition Interaction.h:47