GENIEGenerator
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SmithMonizUtils.cxx
Go to the documentation of this file.
1 //____________________________________________________________________________
2 /*
3  Copyright (c) 2003-2024, The GENIE Collaboration
4  For the full text of the license visit http://copyright.genie-mc.org
5 
6  Igor Kakorin <kakorin@jinr.ru>
7  Joint Institute for Nuclear Research
8 
9  adapted from fortran code provided by:
10 
11  Konstantin Kuzmin <kkuzmin@theor.jinr.ru>
12  Joint Institute for Nuclear Research
13 
14  Vladimir Lyubushkin
15  Joint Institute for Nuclear Research
16 
17  Vadim Naumov <vnaumov@theor.jinr.ru>
18  Joint Institute for Nuclear Research
19 
20  based on code of:
21  Costas Andreopoulos <c.andreopoulos \at cern.ch>
22  University of Liverpool
23 */
24 //____________________________________________________________________________
25 #include <TMath.h>
26 #include <Math/IFunction.h>
27 #include <Math/RootFinder.h>
28 
29 #include "Framework/Conventions/GBuild.h"
38 #include "Framework/Utils/Range1.h"
40 
41 using namespace genie;
42 using namespace genie::constants;
43 using std::ostringstream;
44 
45 //____________________________________________________________________________
47 Algorithm("genie::SmithMonizUtils")
48 {
49 
50 }
51 //____________________________________________________________________________
53 Algorithm("genie::SmithMonizUtils", config)
54 {
55 
56 }
57 //____________________________________________________________________________
59 {
60 
61 }
62 //____________________________________________________________________________
64 {
65  Algorithm::Configure(config);
66  this->LoadConfig();
67 }
68 //____________________________________________________________________________
69 void SmithMonizUtils::Configure(string config)
70 {
71  Algorithm::Configure(config);
72  this->LoadConfig();
73 }
74 //____________________________________________________________________________
76 {
77 
78 
79  GetParam( "FermiMomentumTable", fKFTable);
80  GetParam( "RFG-UseParametrization", fUseParametrization);
81 
82 
83  // load removal energy for specific nuclei from either the algorithm's
84  // configuration file or the UserPhysicsOptions file.
85  // if none is used use Wapstra's semi-empirical formula.
86  const std::string keyStart = "RFG-NucRemovalE@Pdg=";
87 
88  RgIMap entries = GetConfig().GetItemMap();
89 
90  for(RgIMap::const_iterator it = entries.begin(); it != entries.end(); ++it)
91  {
92  const std::string& key = it->first;
93  int pdg = 0;
94  int Z = 0;
95  if (0 == key.compare(0, keyStart.size(), keyStart.c_str()))
96  {
97  pdg = atoi(key.c_str() + keyStart.size());
98  Z = pdg::IonPdgCodeToZ(pdg);
99  }
100  if (0 != pdg && 0 != Z)
101  {
102  ostringstream key_ss ;
103  key_ss << keyStart << pdg;
104  RgKey rgkey = key_ss.str();
105  double eb;
106  GetParam( rgkey, eb ) ;
107  eb = TMath::Max(eb, 0.);
108  fNucRmvE.insert(map<int,double>::value_type(Z,eb));
109  }
110  }
111 
112 
113 }
114 //____________________________________________________________________________
115 // Set the variables necessary for further calculations
117 {
118 
119  fInteraction = interaction;
120  // get kinematics & init-state parameters
121  const InitialState & init_state = interaction -> InitState();
122  const Target & target = init_state.Tgt();
123  PDGLibrary * pdglib = PDGLibrary::Instance();
124 
125  // neutrino energy (GeV)
126  E_nu = interaction->InitState().ProbeE(kRfLab);
127 
128  assert(target.HitNucIsSet());
129  // get lepton&nuclear masses (init & final state nucleus)
130 
131  // mass of final charged lepton (GeV)
132  m_lep = interaction->FSPrimLepton()->Mass();
133  mm_lep = TMath::Power(m_lep, 2);
134  int nucl_pdg_ini = target.HitNucPdg();
135  m_ini = target.HitNucMass();
136  mm_ini = TMath::Power(m_ini, 2);
137  int nucl_pdg_fin = genie::pdg::SwitchProtonNeutron(nucl_pdg_ini);
138  TParticlePDG * nucl_fin = pdglib->Find( nucl_pdg_fin );
139  // mass of final hadron or hadron system (GeV)
140  m_fin = nucl_fin -> Mass();
141  mm_fin = TMath::Power(m_fin, 2);
142  // mass of target nucleus (GeV)
143  m_tar = target.Mass();
144  mm_tar = TMath::Power(m_tar, 2);
145 
146  // RFG is not applied for A<4
147  if (target.A()<4)
148  {
149  E_BIN = P_Fermi = m_rnu = mm_rnu = 0;
150  return;
151  }
152 
153  bool is_p = pdg::IsProton(nucl_pdg_ini);
154  int Zi = target.Z();
155  int Ai = target.A();
156  int Zf = (is_p) ? Zi-1 : Zi;
157  int Af = Ai-1;
158  TParticlePDG * nucl_f = pdglib->Find( pdg::IonPdgCode(Af, Zf) );
159  if(!nucl_f)
160  {
161  LOG("SmithMoniz", pFATAL)
162  << "Unknwown nuclear target! No target with code: "
163  << pdg::IonPdgCode(Af, Zf) << " in PDGLibrary!";
164  exit(1);
165  }
166  // mass of residual nucleus (GeV)
167  m_rnu = nucl_f -> Mass();
168  mm_rnu = TMath::Power(m_rnu, 2);
169 
170  int Z = target.Z();
171  int A = target.A();
172  int N = A-Z;
173 
174 
175  // maximum value of Fermi momentum of target nucleon (GeV)
176  if (A < 6 || !fUseParametrization)
177  {
178  // look up the Fermi momentum for this Target
180  const FermiMomentumTable * kft = kftp->GetTable(fKFTable);
181  P_Fermi = kft->FindClosestKF(pdg::IonPdgCode(A, Z), nucl_pdg_ini);
182  }
183  else
184  {
185  // define the Fermi momentum for this Target
186  //
188  // correct the Fermi momentum for the struck nucleon
189  if(is_p) P_Fermi *= TMath::Power( 2.*Z/A, 1./3);
190  else
191  P_Fermi *= TMath::Power( 2.*N/A, 1./3);
192  }
193 
194  // neutrino binding energy (GeV)
195  if (target.A() < 6 || !fUseParametrization)
196  {
197  map<int,double>::const_iterator it = fNucRmvE.find(Z);
198  if(it != fNucRmvE.end()) E_BIN = it->second;
200  }
201  else
203 
204 
205 
206 
207 }
208 //____________________________________________________________________________
209 // Get the neutrino energy threshold
211 {
212 
214 
215  // maximum of function call
216  const int MFC = 10000;
217  const double EPSABS = 0.;
218  const double EPSREL = 1.0e-08;
219 
220  // Energy threshold of scattering on nucleus (Eq. (1) of Ref. 3)
221  double E_min = ((m_lep + m_rnu + m_fin)*(m_lep + m_rnu + m_fin) - mm_tar)/2/m_tar;
222 
223  // Energy threshold of scattering on bound nucleon (Eq. (2) of Ref. 3)
224  double E_min2 = ((m_lep + m_fin)*(m_lep + m_fin)-mm_ini-E_BIN*E_BIN+2*E_BIN*TMath::Sqrt(mm_ini+P_Fermi*P_Fermi))/2/(TMath::Sqrt(mm_ini+P_Fermi*P_Fermi)-E_BIN+P_Fermi);
225 
226  E_min = TMath::Max(E_min, E_min2);
227 
228  // if nu_1>nu_max at E_min then we try to find energy in range (E_min, 50.) where nu_1=nu_max and put E_min equal to it.
229  // nu_1 -- minimal energy transfer for bound nucleon (see Eqs. (11) of Ref. 3),
230  // nu_max -- maximal energy transfer on nucleus (see Eq. (9) of Ref.3)
231  if (QEL_EnuMin_SM(E_min) > 0)
232  {
233  // C++ analog of fortran function Enu_rf= DZEROX(E_min,Enu_2,EPS,MFC,QEL_EnuMin_SM,1)
234  ROOT::Math::RootFinder rfgb(ROOT::Math::RootFinder::kGSL_BRENT);
235  //convergence is reached using tolerance = 2 *( epsrel * abs(x) + epsabs)
236  if ( rfgb.Solve(QEL_EnuMin_SM_, E_min, 50., MFC, EPSABS, EPSREL) )
237  {
238  E_min = rfgb.Root();
239  }
240  }
241  E_min = TMath::Max(E_min, 0.);
242  return E_min;
243 
244 }
245 //____________________________________________________________________________
246 // The auxiliary function for determining energy threshold
247 double SmithMonizUtils::QEL_EnuMin_SM(double Enu) const
248 {
249  // return the minimum of nu_1-nu_max as function of Q2 in range ( Q2_lim1(Enu), Q2_lim2(Enu) )
250  const double EPS = 1.0e-06;
251  const double Delta= 1.0e-14;
252  const double Precision = std::numeric_limits<double>::epsilon();
253  double s = 2*Enu*m_tar+mm_tar;
254  double W2 = (m_rnu+m_fin)*(m_rnu+m_fin);
255  // neutrino energy in CMS (see Eq. (4) of Ref.3)
256  double E_nu_CM = (s-mm_tar)/2/TMath::Sqrt(s);
257  // final lepton energy and momentum at W2_min (see Eqs. (5) and (6) of Ref.3)
258  double E_l_CM = (s+mm_lep-W2)/2/TMath::Sqrt(s);
259  double P_l_CM = E_l_CM>m_lep?TMath::Sqrt(E_l_CM*E_l_CM-mm_lep):Precision;
260  // minimal and maximal allowed Q2 for scattering on nucleus (see Eqs. (3) of Ref.3)
261  double Q2_lim1 = 2*E_nu_CM*(E_l_CM-P_l_CM)-mm_lep;
262  double Q2_lim2 = 2*E_nu_CM*(E_l_CM+P_l_CM)-mm_lep;
263  // C++ analog of fortran function DMINFC(Q2lim1_SM,Q2_lim1,Q2_lim2,EPS,Delta,Q2_0,F_MIN,LLM)
265  double Q2_0,F_MIN;
266  bool LLM;
267  // find minimum of nu_1-nu_max as function of Q2 in range (Q2_lim1,Q2_lim2)
268  DMINFC(Q2lim1_SM_,Q2_lim1,Q2_lim2,EPS,Delta,Q2_0,F_MIN,LLM);
269  return F_MIN;
270 }
271 //____________________________________________________________________________
272 // The auxiliary function for determining Q2-range
273 double SmithMonizUtils::Q2lim1_SM(double Q2, double Enu) const
274 {
275  // maximal energy transfer (see Eq. (9) of Ref.3)
276  double nu_max = Enu*Q2/(Q2+mm_lep)-(Q2+mm_lep)/4/Enu;
277 
278  double E = sqrt(P_Fermi*P_Fermi+mm_ini);
279  double b = (E-E_BIN)*(E-E_BIN)-P_Fermi*P_Fermi;
280  double a = 0.5*(Q2+mm_fin-b);
281  // minimal energy transfer for bound nucleon (see Eqs. (11) of Ref. 3),
282  double nu_1 = (a*(E-E_BIN)-P_Fermi*TMath::Sqrt(a*a+Q2*b))/b;
283  return nu_1-nu_max;
284 
285 }
286 //____________________________________________________________________________
287 // The auxiliary function for determining Q2-range
288 double SmithMonizUtils::Q2lim2_SM(double Q2) const
289 {
290  // minimal energy transfer for scattering on nucleus (see Eq. (7) of Ref.3)
291  double nu_min = ((m_rnu+m_fin)*(m_rnu+m_fin)+Q2-mm_tar)/(2*m_tar);
292 
293  double E = sqrt(P_Fermi*P_Fermi+mm_ini);
294  double b = (E-E_BIN)*(E-E_BIN)-P_Fermi*P_Fermi;
295  double a = (Q2+mm_fin-b)*0.5;
296  // maximal energy transfer for bound nucleon (see Eqs. (11) of Ref. 3)
297  double nu_2 = (a*(E-E_BIN)+P_Fermi*TMath::Sqrt(a*a+Q2*b))/b;
298  return nu_min-nu_2;
299 
300 }
301 //____________________________________________________________________________
302 // Return allowed Q2-range
304 {
305 
306  // here we find Q2_min and Q2_max such that
307  // 0. Q2_min>=0
308  // 1. nu_1(Q2_min)<=nu_max(Q2_min)
309  // 2. nu_1(Q2_max)<=nu_max(Q2_max)
310  // 3. nu_min(Q2_min)<=nu_2(Q2_min)
311  // 4. Q2_min>=the value of minimal Q2 defined for scattering on nucleus
312  // 5. Q2_max<=the value of maximal Q2 defined for scattering on nucleus (see Eqs. (3) of Ref.3)
313  // nu_1 -- minimal energy transfer for bound nucleon (see Eqs. (11) of Ref. 3),
314  // nu_max -- maximal energy transfer on nucleus (see Eq. (9) of Ref.3),
315  // nu_2 -- maximal energy transfer for bound nucleon (see Eqs. (11) of Ref. 3),
316  // nu_min -- minimal energy transfer on nucleus (see Eq. (7) of Ref.3)
317 
318  // maximum of function call
319  const int MFC = 1000;
320  const double EPS = 1.0e-08;
321  const double Delta= 1.0e-14;
322  const double EPSABS = 0;
323  const double EPSREL = 1.0e-08;
324  const double Precision = std::numeric_limits<double>::epsilon();
325  // if the nucleus mass is less than 4 then this is a special case
326  if (E_BIN == 0 && P_Fermi == 0)
327  {
328  double s = 2*E_nu*m_ini+mm_ini;
329  // minimal W2 for scattering on nucleus (see Eq. (6) of Ref.3)
330  double W2 = mm_fin;
331  // neutrino energy in CMS (see Eq. (4) of Ref.3)
332  double E_nu_CM = (s-mm_ini)/2/TMath::Sqrt(s);
333  // final lepton energy and momentum at W2_min (see Eqs. (5) of Ref.3)
334  double E_l_CM = (s+mm_lep-W2)/2/TMath::Sqrt(s);
335  double P_l_CM = E_l_CM>m_lep?TMath::Sqrt(E_l_CM*E_l_CM-mm_lep):Precision;
336  // minimal and maximal allowed Q2 for scattering on nucleus (see Eqs. (3) of Ref.3)
337  double Q2_min = 2*E_nu_CM*(E_l_CM-P_l_CM)-mm_lep;
338  double Q2_max = 2*E_nu_CM*(E_l_CM+P_l_CM)-mm_lep;
339  Q2_min= TMath::Max(Q2_min,0.0);
340  Range1D_t R(Q2_min,Q2_max);
341  return R;
342  }
343  double s = 2*E_nu*m_tar+mm_tar;
344  // minimal W2 for scattering on nucleus (see Eq. (6) of Ref.3)
345  double W2 = (m_rnu+m_fin)*(m_rnu+m_fin);
346  // neutrino energy in CMS (see Eq. (4) of Ref.3)
347  double E_nu_CM = (s-mm_tar)/2/TMath::Sqrt(s);
348  // final lepton energy and momentum at W2_min (see Eqs. (5) of Ref.3)
349  double E_l_CM = (s+mm_lep-W2)/2/TMath::Sqrt(s);
350  double P_l_CM = E_l_CM>m_lep?TMath::Sqrt(E_l_CM*E_l_CM-mm_lep):Precision;
351  // minimal and maximal allowed Q2 for scattering on nucleus (see Eqs. (3) of Ref.3)
352  double Q2_min = 2*E_nu_CM*(E_l_CM-P_l_CM)-mm_lep;
353  double Q2_max = 2*E_nu_CM*(E_l_CM+P_l_CM)-mm_lep;
354  double F_MIN, Q2_0;
355  bool LLM;
356  // C++ analog of fortran function DMINFC(Q2lim1_SM,Q2_min,Q2_max,EPS,Delta,Q2_0,F_MIN,LLM)
358  // if minimum of nu_1-nu_max>0 then exit with error, because it's impossible
359  DMINFC(Q2lim1_SM_,Q2_min,Q2_max,EPS,Delta,Q2_0,F_MIN,LLM);
360  if (F_MIN>0)
361  {
362  LOG("SmithMoniz", pFATAL)
363  << "No overlapped area for energy " << E_nu << "\n" <<
364  "Q2_min=" << Q2_min << " Q2_max=" << Q2_max << "\n" <<
365  "Q2_0=" << Q2_0 << " F_MIN=" << F_MIN;
366  exit(1);
367  }
368  // at Q2_0 here we have: nu_1(Q2_0)-nu_max(Q2_0)<0
369  // if nu_1(Q2_min)-nu_max(Q2_min)>0 we find corrected Q2_min_cor>Q2_min where nu_1(Q2_min_cor)-nu_max(Q2_min_cor)=0
370  // (it is always possible because of above conditions)
371  if (Q2lim1_SM(Q2_min, E_nu)>0)
372  {
373  //C++ analog of fortran function Q2_RF=DZEROX(Q2_min,Q2_0,EPS,MFC,Q2lim1_SM,1)
374  ROOT::Math::RootFinder rfgb(ROOT::Math::RootFinder::kGSL_BRENT);
375  // convergence is reached using tolerance = 2 *( epsrel * abs(x) + epsabs)
376  if (rfgb.Solve(Q2lim1_SM_, Q2_min, Q2_0, MFC, EPSABS, EPSREL))
377  {
378  Q2_min= rfgb.Root();
379  }
380  }
381  // if nu_1(Q2_max)-nu_max(Q2_max)>0 we find Q2_max_cor<Q2_max where nu_1(Q2_max_cor)-nu_max(Q2_max_cor)=0
382  // (it is always possible because of above conditions)
383  if(Q2lim1_SM(Q2_max, E_nu)>0)
384  {
385  // C++ analog of fortran function Q2_RF=DZEROX(Q2_0,Q2_max,Eps,MFC,Q2lim1_SM,1)
386  ROOT::Math::RootFinder rfgb(ROOT::Math::RootFinder::kGSL_BRENT);
387  //convergence is reached using tolerance = 2 *( epsrel * abs(x) + epsabs)
388  if (rfgb.Solve(Q2lim1_SM_, Q2_0, Q2_max, MFC, EPSABS, EPSREL))
389  {
390  Q2_max= rfgb.Root();
391  }
392  }
394  // if nu_min(Q2_min)-nu_2(Q2_min)>0 and nu_min(Q2_max)-nu_2(Q2_max)>0 then set Q2_min=Q2_max (it makes xsec equal to zero).
395  if (Q2lim2_SM(Q2_min)>0)
396  {
397  if(Q2lim2_SM(Q2_max)>0)
398  {
399  LOG("SmithMoniz", pWARN) << "The RFG model is not applicable! The cross section is set zero!";
400  Q2_min = Q2_max;
401  }
402  // here we have nu_min(Q2_min)-nu_2(Q2_min)>0 and nu_min(Q2_max)-nu_2(Q2_max)<0 or vice versa
403  // so we always can find Q2_min_cor where nu_min(Q2_min_cor)-nu_2(Q2_min_cor)=0
404  else
405  {
406  // C++ analog of fortran function Q2_RF = DZEROX(Q2_min,Q2_max,Eps,MFC,Q2lim2_SM,1)
407  ROOT::Math::RootFinder rfgb(ROOT::Math::RootFinder::kGSL_BRENT);
408  // convergence is reached using tolerance = 2 *( epsrel * abs(x) + epsabs)
409  if (rfgb.Solve(Q2lim2_SM_, Q2_min,Q2_max, MFC, EPSABS, EPSREL))
410  {
411  Q2_min= rfgb.Root();
412  }
413  }
414  }
415  Q2_min = TMath::Max(Q2_min,0.0);
416 
417  Range1D_t R(Q2_min,Q2_max);
418  return R;
419 
420 }
421 //____________________________________________________________________________
422 // Return allowed v-range for given Q2
424 {
425 
426  // minimal energy transfer for scattering on nucleus (see Eq. (7) of Ref.3)
427  double nu_min= ((m_rnu+m_fin)*(m_rnu+m_fin)+Q2-mm_tar)/2/m_tar;
428 
429  // if the target is nucleon then nu_min=nu_max=(m_fin^2+Q^2-m_ini^2)/(2*m_ini)
430  if (E_BIN == 0 && P_Fermi == 0)
431  return Range1D_t(nu_min, nu_min);
432 
433  // maximal energy transfer (see Eq. (9) of Ref.3)
434  double nu_max = E_nu*Q2/(Q2+mm_lep)-(Q2+mm_lep)/4/E_nu;
435 
436  // now we find limits for bound nucleon
437  double E = TMath::Sqrt(P_Fermi*P_Fermi+mm_ini);
438  double b = (E-E_BIN)*(E-E_BIN)-P_Fermi*P_Fermi;
439  double a = (Q2+mm_fin-b)*0.5;
440  double tmp1 = a*(E-E_BIN);
441  double tmp2 = P_Fermi*TMath::Sqrt(a*a+Q2*b);
442  // minimal and maximal energy transfer for bound nucleon (see Eqs. (11) of Ref. 3)
443  double nu_1 = (tmp1-tmp2)/b;
444  double nu_2 = (tmp1+tmp2)/b;
445  // for minimal energy transfer we take maximum of corresponding values on nucleus and bound nucleon
446  nu_min= TMath::Max(nu_min,nu_1);
447  // for maximal energy transfer we take minimum of corresponding values on nucleus and bound nucleon
448  nu_max= TMath::Min(nu_max,nu_2);
449 
450  if (nu_min<=nu_max)
451  return Range1D_t(nu_min,nu_max);
452  else
453  // to avoid machine precision errors
454  return Range1D_t(0.5*(nu_min+nu_max),0.5*(nu_min+nu_max));
455 
456 }
457 //____________________________________________________________________________
458 // Return minimum of low edge of v-range for given neutrino energy
459 double SmithMonizUtils::vQES_SM_min(double Q2_min, double Q2_max) const
460 {
461  // maximum of function call
462  const double EPS = 1.0e-08;
463  const double Delta= 1.0e-14;
464 
465  if (E_BIN == 0 && P_Fermi == 0)
466  return vQES_SM_lim(Q2_min).min;
467 
468  double F_MIN, Q2_0;
469  bool LLM;
470  // C++ analog of fortran function DMINFC(Q2lim1_SM,Q2_min,Q2_max,EPS,Delta,Q2_0,F_MIN,LLM)
472  DMINFC(vlim1_SM_,Q2_min,Q2_max,EPS,Delta,Q2_0,F_MIN,LLM);
473 
474  return F_MIN;
475 
476 }
477 //____________________________________________________________________________
478 // Return maximum of low edge of v-range for given neutrino energy
479 double SmithMonizUtils::vQES_SM_max(double Q2_min, double Q2_max) const
480 {
481  // maximum of function call
482  const double EPS = 1.0e-08;
483  const double Delta= 1.0e-14;
484 
485  if (E_BIN == 0 && P_Fermi == 0)
486  return vQES_SM_lim(Q2_max).min;
487 
488  double F_MIN, Q2_0;
489  bool LLM;
490  // C++ analog of fortran function DMINFC(Q2lim1_SM,Q2_min,Q2_max,EPS,Delta,Q2_0,F_MIN,LLM)
492  DMINFC(vlim2_SM_,Q2_min,Q2_max,EPS,Delta,Q2_0,F_MIN,LLM);
493 
494  return -F_MIN;
495 
496 }
497 //____________________________________________________________________________
498 // The auxiliary function for determining minimum of low edge of v-range
499 double SmithMonizUtils::vlim1_SM(double Q2) const
500 {
501  // minimal energy transfer for scattering on nucleus (see Eq. (7) of Ref.3)
502  double nu_min = ((m_rnu+m_fin)*(m_rnu+m_fin)+Q2-mm_tar)/(2*m_tar);
503 
504  double E = sqrt(P_Fermi*P_Fermi+mm_ini);
505  double b = (E-E_BIN)*(E-E_BIN)-P_Fermi*P_Fermi;
506  double a = (Q2+mm_fin-b)*0.5;
507  // minimal energy transfer for bound nucleon (see Eqs. (11) of Ref. 3)
508  double nu_1 = (a*(E-E_BIN)-P_Fermi*TMath::Sqrt(a*a+Q2*b))/b;
509  nu_min= TMath::Max(nu_min,nu_1);
510  return nu_min;
511 }
512 //____________________________________________________________________________
513 // The auxiliary function for determining maximum of up edge of v-range
514 double SmithMonizUtils::vlim2_SM(double Q2) const
515 {
516  // maximal energy transfer (see Eq. (9) of Ref.3)
517  double nu_max = E_nu*Q2/(Q2+mm_lep)-(Q2+mm_lep)/4/E_nu;
518 
519  double E = sqrt(P_Fermi*P_Fermi+mm_ini);
520  double b = (E-E_BIN)*(E-E_BIN)-P_Fermi*P_Fermi;
521  double a = 0.5*(Q2+mm_fin-b);
522  // maximal energy transfer for bound nucleon (see Eqs. (11) of Ref. 3)
523  double nu_2 = (a*(E-E_BIN)+P_Fermi*TMath::Sqrt(a*a+Q2*b))/b;
524  nu_max= TMath::Min(nu_max,nu_2);
525  return -nu_max;
526 }
527 //____________________________________________________________________________
528 // Return allowed Fermi momentum range for given Q2 and v
530 {
531  double qv = TMath::Sqrt(nu*nu+Q2);
532  double c_f = (nu-E_BIN)/qv;
533  double d_f = (E_BIN*E_BIN-2*nu*E_BIN-Q2+mm_ini-mm_fin)/(2*qv*m_ini);
534  // minimal energy of initial nucleon (see Eq. (13) of Ref.3)
535  double Ef_min= TMath::Max(m_ini*(c_f*d_f+TMath::Sqrt(1.0-c_f*c_f+d_f*d_f))/(1.0-c_f*c_f), TMath::Sqrt(P_Fermi*P_Fermi+mm_ini)-nu);
536  double kF_min= P_Fermi!=0?TMath::Sqrt(TMath::Max(Ef_min*Ef_min-mm_ini,0.0)):0.;
537  double kF_max= P_Fermi;
538  Range1D_t R;
539  if (kF_min<=kF_max)
540  R = Range1D_t(kF_min,kF_max);
541  else
542  R = Range1D_t(0.5*(kF_min+kF_max),0.5*(kF_min+kF_max));
543  return R;
544 
545 }
546 //____________________________________________________________________________
547 // C++ implementation of DMINC function from CERN library
548 void SmithMonizUtils::DMINFC(Functor1D &F, double A,double B, double EPS, double DELTA, double &X, double &Y, bool &LLM) const
549 {
550  const double W5 = TMath::Sqrt(5);
551  const double HV = (3-W5)/2;
552  const double HW = (W5-1)/2;
553  const double R1 = 1.0;
554  const double HF = R1/2;
555 
556  int N = -1;
557  if(A!=B) N = TMath::Nint(2.08*TMath::Log(TMath::Abs((A-B)/EPS)));
558  double C = A;
559  double D = B;
560  if(A>B)
561  {
562  C = B;
563  D = A;
564  }
565  bool LLT = true;
566  bool LGE = true;
567  double V, FV, W, FW, H;
568  while(true)
569  {
570  H = D-C;
571  if(N<0)
572  {
573  X = HF*(C+D);
574  Y = F(X);
575  LLM = TMath::Abs(X-A)>DELTA && TMath::Abs(X-B)>DELTA;
576  return;
577  }
578  if(LLT)
579  {
580  V = C+HV*H;
581  FV = F(V);
582  }
583  if(LGE)
584  {
585  W = C+HW*H;
586  FW = F(W);
587  }
588  if(FV<FW)
589  {
590  LLT = true;
591  LGE = false;
592  D = W;
593  W = V;
594  FW = FV;
595  }
596  else
597  {
598  LLT = false;
599  LGE = true;
600  C = V;
601  V = W;
602  FV = FW;
603  }
604  N = N-1;
605  }
606 }
607 //____________________________________________________________________________
608 // Density of Fermi gas, for case T_Fermi=0 is a step functio, which is blurred at T_Fermi!=0
609 double SmithMonizUtils::rho(double P_Fermi, double T_Fermi, double p)
610 {
611 
612  if (T_Fermi==0)
613  {
614  //Pure Fermi gaz with T_Fermi=0
615  if(p<=P_Fermi)
616  return 1.0;
617  else
618  return 0.0;
619  }
620  else
621  {
622  //Fermi-Dirac distribution
623  return 1.0/(1.0 + TMath::Exp(-(P_Fermi-p)/T_Fermi));
624  }
625 
626 
627 }
628 //____________________________________________________________________________
630 {
631  return E_BIN;
632 }
633 //____________________________________________________________________________
635 {
636  return P_Fermi;
637 }
638 //____________________________________________________________________________
639 double SmithMonizUtils::GetTheta_k(double v, double qv) const
640 {
641  return TMath::ACos((v + (mm_lep-v*v+qv*qv)/2/E_nu)/qv);
642 }
643 //____________________________________________________________________________
644 double SmithMonizUtils::GetTheta_p(double pv, double v, double qv, double &E_p) const
645 {
646  E_p = TMath::Sqrt(mm_ini+pv*pv)-E_BIN;
647  if (pv != 0)
648  return TMath::ACos(((v-E_BIN)*(2*E_p+v+E_BIN)-qv*qv+mm_ini-mm_fin)/(2*pv*qv));
649  else
650  return 0;
651 }
652 //____________________________________________________________________________
654 {
655  double vol = 0.0;
656  if (ps == kPSQ2fE)
657  {
658  Range1D_t rQ2 = Q2QES_SM_lim();
659  vol = rQ2.max - rQ2.min;
660  return vol;
661  }
662  else if (ps == kPSQ2vpfE)
663  {
664  const int kNQ2 = 101;
665  const int kNv = 101;
666  Range1D_t rQ2 = Q2QES_SM_lim();
667  double dQ2 = (rQ2.max-rQ2.min)/(kNQ2-1);
668  for(int iq2=0; iq2<kNQ2-1; iq2++)
669  {
670  double Q2 = rQ2.min + iq2*dQ2;
671  Range1D_t rv = vQES_SM_lim(Q2);
672  double dv = (rv.max-rv.min)/(kNv-1);
673  for(int iv=0; iv<kNv-1; iv++)
674  {
675  double v = rv.min + iv*dv;
676  Range1D_t rkF = kFQES_SM_lim(Q2,v);
677  double dkF = (rkF.max-rkF.min);
678  vol += (dQ2*dv*dkF);
679  }
680  }
681  return vol;
682  }
683  else
684  return 0;
685 }
void SetInteraction(const Interaction *i)
Range1D_t Q2QES_SM_lim(void) const
double vQES_SM_max(double Q2min, double Q2max) const
double mm_lep
Squared mass of final charged lepton (GeV)
double m_ini
Mass of initial hadron or hadron system (GeV)
double Q2(const Interaction *const i)
Definition: KineUtils.cxx:1077
double E_BIN
Binding energy (GeV)
int HitNucPdg(void) const
Definition: Target.cxx:304
double E_nu_thr_SM(void) const
int A(void) const
Definition: Target.h:70
A simple [min,max] interval for doubles.
Definition: Range1.h:42
double HitNucMass(void) const
Definition: Target.cxx:233
double m_lep
Mass of final charged lepton (GeV)
#define pFATAL
Definition: Messenger.h:56
double mm_fin
Squared mass of final hadron or hadron system (GeV)
static constexpr double s
Definition: Units.h:95
static FermiMomentumTablePool * Instance(void)
int SwitchProtonNeutron(int pdgc)
Definition: PDGUtils.cxx:356
double E_nu
Neutrino energy (GeV)
map< int, double > fNucRmvE
Algorithm abstract base class.
Definition: Algorithm.h:54
double mm_ini
Sqared mass of initial hadron or hadron system (GeV)
double Mass(Resonance_t res)
resonance mass (GeV)
A table of Fermi momentum constants.
double GetTheta_k(double v, double qv) const
enum genie::EKinePhaseSpace KinePhaseSpace_t
double Mass(void) const
Definition: Target.cxx:224
Range1D_t vQES_SM_lim(double Q2) const
virtual const Registry & GetConfig(void) const
Definition: Algorithm.cxx:246
double GetBindingEnergy(void) const
const double epsilon
static constexpr double b
Definition: Units.h:78
double W(const Interaction *const i)
Definition: KineUtils.cxx:1101
double mm_rnu
Squared mass of residual nucleus (GeV)
Summary information for an interaction.
Definition: Interaction.h:56
const Interaction * fInteraction
Range1D_t kFQES_SM_lim(double nu, double Q2) const
double BindEnergyPerNucleon(const Target &target)
bool IsProton(int pdgc)
Definition: PDGUtils.cxx:336
Singleton class to load &amp; 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
const RgIMap & GetItemMap(void) const
Definition: Registry.h:161
static constexpr double A
Definition: Units.h:74
const FermiMomentumTable * GetTable(string name)
double Q2lim2_SM(double Q2) const
const double a
double P_Fermi
Maximum value of Fermi momentum of target nucleon (GeV)
double BindEnergyPerNucleonParametrization(const Target &target)
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
double m_rnu
Mass of residual nucleus (GeV)
int Z(void) const
Definition: Target.h:68
double Q2lim1_SM(double Q2, double Enu) const
double m_tar
Mass of target nucleus (GeV)
static constexpr double ps
Definition: Units.h:99
void DMINFC(Functor1D &F, double A, double B, double EPS, double DELTA, double &X, double &Y, bool &LLM) const
double vlim2_SM(double Q2) const
double QEL_EnuMin_SM(double E_nu) const
#define pWARN
Definition: Messenger.h:60
double vQES_SM_min(double Q2min, double Q2max) const
TParticlePDG * FSPrimLepton(void) const
final state primary lepton
double FermiMomentumForIsoscalarNucleonParametrization(const Target &target)
double max
Definition: Range1.h:53
static PDGLibrary * Instance(void)
Definition: PDGLibrary.cxx:68
static double rho(double P_Fermi, double T_Fermi, double p)
Singleton class to load &amp; serve a TDatabasePDG.
Definition: PDGLibrary.h:35
bool HitNucIsSet(void) const
Definition: Target.cxx:283
double PhaseSpaceVolume(KinePhaseSpace_t ps) const
string RgKey
A registry. Provides the container for algorithm configuration parameters.
Definition: Registry.h:65
int IonPdgCode(int A, int Z)
Definition: PDGUtils.cxx:71
const InitialState & InitState(void) const
Definition: Interaction.h:69
double min
Definition: Range1.h:52
int IonPdgCodeToZ(int pdgc)
Definition: PDGUtils.cxx:55
double GetTheta_p(double pv, double v, double qv, double &E_p) const
TParticlePDG * Find(int pdgc, bool must_exist=true)
Definition: PDGLibrary.cxx:86
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 mm_tar
Squared mass of target nucleus (GeV)
void Configure(const Registry &config)
double ProbeE(RefFrame_t rf) const
double m_fin
Mass of final hadron or hadron system (GeV)
double vlim1_SM(double Q2) const
double GetFermiMomentum(void) const
Initial State information.
Definition: InitialState.h:48
map< RgKey, RegistryItemI * > RgIMap
Definition: Registry.h:45