GENIEGenerator
Loading...
Searching...
No Matches
LocalFGM.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
7 Author: Joe Johnston, University of Pittsburgh (Advisor Steven Dytman)
8
9 For the class documentation see the corresponding header file.
10
11*/
12//____________________________________________________________________________
13
14#include <sstream>
15#include <cstdlib>
16#include <TMath.h>
17
19#include "Framework/Conventions/GBuild.h"
29
30using std::ostringstream;
31using namespace genie;
32using namespace genie::constants;
33using namespace genie::utils;
34
35//____________________________________________________________________________
37NuclearModelI("genie::LocalFGM")
38{
39
40}
41//____________________________________________________________________________
43NuclearModelI("genie::LocalFGM", config)
44{
45
46}
47//____________________________________________________________________________
52//____________________________________________________________________________
54 double hitNucleonRadius) const
55{
56 assert(target.HitNucIsSet());
57
58 fCurrRemovalEnergy = -99999.0;
59 fCurrMomentum.SetXYZ(0,0,0);
60
61 //-- set fermi momentum vector
62 //
63 TH1D * prob = this->ProbDistro(target,hitNucleonRadius);
64 if(!prob) {
65 LOG("LocalFGM", pNOTICE)
66 << "Null nucleon momentum probability distribution";
67 exit(1);
68 }
69
71
72 double costheta = -1. + 2. * rnd->RndGen().Rndm();
73 double sintheta = TMath::Sqrt(1.-costheta*costheta);
74 double fi = 2 * kPi * rnd->RndGen().Rndm();
75 double cosfi = TMath::Cos(fi);
76 double sinfi = TMath::Sin(fi);
77
78 double px;
79 double py;
80 double pz;
81
82 int Z = target.Z();
83 map<int,double>::const_iterator it = fNucRmvE.find(Z);
84
85 double p;
86
87 bool doThrow = true;
88 while(doThrow){
89 p = prob->GetRandom();
90
91 LOG("LocalFGM", pINFO) << "|p,nucleon| = " << p;
92
93 px = p*sintheta*cosfi;
94 py = p*sintheta*sinfi;
95 pz = p*costheta;
96
97 fCurrMomentum.SetXYZ(px,py,pz);
98
99 if (fMomDepErmv) {
100 // hit nucleon mass
101 double nucl_mass = target.HitNucMass();
102 // get the local Fermi momentum
103 double KF = LocalFermiMomentum( target, target.HitNucPdg(), hitNucleonRadius);
104
105 //initial nucleon kinetic energy at the Fermi surface
106 double T_F = TMath::Sqrt(TMath::Power(nucl_mass,2)+TMath::Power(KF,2)) - nucl_mass;
107
108 //the minimum removal energy to keep nucleons bound is equal to
109 //the nucleon kinetic energy at the Fermi surface
110 double localEb = T_F;
111
112 //initial state nucleon kinetic energy (already present and contributing to its escape from the nucleus)
113 double T_nucl = TMath::Sqrt(TMath::Power(fCurrMomentum.Mag(),2)+TMath::Power(nucl_mass,2))- nucl_mass;
114
115 //set the Qvalue (separation energy) to the RFG removal energy in the CommonParams file
116 double q_val_offset;
117 if(it != fNucRmvE.end()) q_val_offset = it->second;
118 else q_val_offset = nuclear::BindEnergyPerNucleon(target);
119
120 //set the removal energy to be the sum of the removal energy at the Fermi surface
121 //and the Q value offset, minus the nucleon kinetic energy
122 fCurrRemovalEnergy = localEb + q_val_offset - T_nucl;
123
124
125 }
126 else {
127 //else, use already existing treatment, i.e. set removal energy to RFG value from table or use
128 //Wapstra's semi-empirical formula.
129 if(it != fNucRmvE.end()) fCurrRemovalEnergy = it->second;
131 }
132
133 // we keep the event unless otherwise specified
134 doThrow = false;
135
136 if (fCurrRemovalEnergy < 0)
137 {
139 {
140 LOG("LocalFGM", pDEBUG)
141 << " ^-- sampled nucleon resulted in negative LFG removal"
142 << " energy and was rejected. Resampling ...";
143 doThrow = true;
144 }
145 else if ( fUseMBDist )
146 {
147 // Spectral function fits to electron scattering nuclear data typically
148 // use Maxwell-Boltzmann removal energies. The approach here was
149 // inspired by conversations with Artur Ankowski. However, if the
150 // binding energy is too large, the off-shell nucleon's mass can wind
151 // up negative, which is completely unphysical and causes NaNs when
152 // trying to boost into its reference frame (in, e.g.,
153 // QELEventGenerator). We thus have to truncate the MB distribution
154 // below where SF models typically max out in Emiss. This max binding
155 // energy comes from insisting that the mass (which is computed from
156 // the on-shell masses of the struck nucleus and nucleon, and the Fermi
157 // momentum) be positive.
158 const double maxBindE = std::sqrt( target.Mass()*target.Mass()
159 - 2*target.Mass()*p ) - ( target.Mass() - target.HitNucMass() );
160 LOG("LocalFGM", pDEBUG) << " using max removalE = " << maxBindE;
161 fCurrRemovalEnergy = MaxwellBoltzmannRemovalE( target, 0, maxBindE );
162
163 LOG("LocalFGM", pDEBUG) << " ^-- note: sampled nucleon resulted"
164 << " in negative LFG removal energy, so its removal energy was"
165 << " resampled from an SRC-like Maxwell-Boltzmann distribution:"
166 << " Ermv = " << fCurrRemovalEnergy;
167 }
168 }
169 } // while (doThrow)
170
171 delete prob;
172
173 return true;
174}
175//____________________________________________________________________________
176double LocalFGM::Prob(double p, double w, const Target & target,
177 double hitNucleonRadius) const
178{
179 if(w<0) {
180 TH1D * prob = this->ProbDistro(target, hitNucleonRadius);
181 int bin = prob->FindBin(p);
182 double y = prob->GetBinContent(bin);
183 double dx = prob->GetBinWidth(bin);
184 double pr = y*dx;
185 delete prob;
186 return pr;
187 }
188 return 1;
189}
190//____________________________________________________________________________
191// *** The TH1D object must be deleted after it is used ***
192TH1D * LocalFGM::ProbDistro(const Target & target, double r) const
193{
194 LOG("LocalFGM", pNOTICE)
195 << "Computing P = f(p_nucleon) for: " << target.AsString()
196 << ", Nucleon Radius = " << r;
197 LOG("LocalFGM", pNOTICE)
198 << ", P(max) = " << fPMax;
199
200 assert(target.HitNucIsSet());
201
202 //-- get information for the nuclear target
203 int nucleon_pdgc = target.HitNucPdg();
204 assert(pdg::IsProton(nucleon_pdgc) || pdg::IsNeutron(nucleon_pdgc));
205
206 // bool is_p = pdg::IsProton(nucleon_pdgc);
207 // double numNuc = (is_p) ? (double)target.Z():(double)target.N();
208
209 // Calculate Fermi Momentum using Local FG equations
210 double KF = LocalFermiMomentum( target, nucleon_pdgc, r ) ;
211
212 LOG("LocalFGM",pNOTICE) << "KF = " << KF;
213
214 //double a = 2.0;
215 //double C = 4. * kPi * TMath::Power(KF,3) / 3.;
216
217 // Do not include nucleon correlation tail
218 //double R = 1. / (1.- KF/4.);
219//#ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
220 //LOG("LocalFGM", pDEBUG) << "a = " << a;
221 //LOG("LocalFGM", pDEBUG) << "C = " << C;
222 //LOG("LocalFGM", pDEBUG) << "R = " << R;
223//#endif
224
225 //-- create the probability distribution
226
227 int npbins = (int) (1000*fPMax);
228 TH1D * prob = new TH1D("", "", npbins, 0, fPMax);
229 prob->SetDirectory(0);
230
231 double dp = fPMax / (npbins-1);
232// double iC = (C>0) ? 1./C : 0.; // unused variables
233// double kfa_pi_2 = TMath::Power(KF*a/kPi,2); // unused variables
234
235 for(int i = 0; i < npbins; i++) {
236 double p = i * dp;
237 double p2 = TMath::Power(p,2);
238
239 // use expression with fSRC_Fraction to allow the possibility of
240 // using the Correlated Fermi Gas Model with a high momentum tail
241
242 // calculate |phi(p)|^2
243 double phi2 = 0;
244 if (p <= KF){
245 phi2 = (1./(4*kPi)) * (3/TMath::Power(KF,3.)) * ( 1 - fSRC_Fraction );
246 }else if( p > KF && p < fPCutOff ){
247 phi2 = (1./(4*kPi)) * ( fSRC_Fraction / (1./KF - 1./fPCutOff) ) / TMath::Power(p,4.);
248 }
249
250 // calculate probability density : dProbability/dp
251 double dP_dp = 4*kPi * p2 * phi2;
252#ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
253 LOG("LocalFGM", pDEBUG) << "p = " << p << ", dP/dp = " << dP_dp;
254#endif
255 prob->Fill(p, dP_dp);
256 }
257
258 double normfactor = prob->Integral("width");
259
260 //-- normalize the probability distribution
261 if (normfactor > 0) prob->Scale(1/normfactor);
262
263 return prob;
264}
265
266//____________________________________________________________________________
267double LocalFGM::MaxwellBoltzmannRemovalE(const Target&, double Ermv_min, double Ermv_max) const
268{
269 // the target is currently unused,
270 // but the fSRC_Ermv_C and fSRC_Ermv_sigma could (should?)
271 // in principle be a function of nucleus
272
273 const double normFactor = 4 / sqrt(M_PI) / fSRC_Ermv_sigma;
274
276
277 // rejection sample --- draw until success
278 double x;
279 while (true)
280 {
281 x = rnd->RndGen().Uniform( Ermv_min, Ermv_max );
282
283 const double arg = (x - fSRC_Ermv_C + fSRC_Ermv_sigma) / fSRC_Ermv_sigma;
284 const double arg2 = arg * arg;
285
286 const double MB = normFactor * arg2 * exp(-arg2);
287
288 if (MB >= rnd->RndGen().Uniform())
289 break;
290 }
291
292 return x;
293}
294
295//____________________________________________________________________________
296double LocalFGM::LocalFermiMomentum( const Target & t, int nucleon_pdg, double radius ) const {
297
298 assert(pdg::IsProton(nucleon_pdg) || pdg::IsNeutron(nucleon_pdg)) ;
299
300 bool is_p = pdg::IsProton(nucleon_pdg);
301 double numNuc = (double) ( (is_p) ? t.Z() : t.N() );
302
303 // double hbarc = kLightSpeed*kPlankConstant/genie::units::fermi;
304
305 double kF = TMath::Power( 3*kPi2*numNuc*genie::utils::nuclear::Density( radius, t.A() ),
306 1.0/3.0 )
308
309 return kF ;
310}
311//____________________________________________________________________________
313{
315 this->LoadConfig();
316}
317//____________________________________________________________________________
318void LocalFGM::Configure(string param_set)
319{
320 Algorithm::Configure(param_set);
321 this->LoadConfig();
322}
323//____________________________________________________________________________
325{
326
328
329 this->GetParamDef("LFG-MomentumMax", fPMax, 1.0);
330 assert(fPMax > 0);
331
332 this->GetParamDef("SRC-Fraction", fSRC_Fraction, 0.0);
333
334 // Default value from work by A. Ankowski (private communication to J.
335 // Wolcott, Nov. 27 2024)
336 this->GetParamDef("SRC-Ermv-C", fSRC_Ermv_C, 0.120);
337
338 // Default value from work by A. Ankowski (private communication to J.
339 // Wolcott, Nov. 27 2024)
340 this->GetParamDef("SRC-Ermv-sigma", fSRC_Ermv_sigma, 0.100);
341
342 this->GetParam("LFG-MomentumCutOff", fPCutOff);
343 this->GetParam("LFG-MomentumDependentErmv", fMomDepErmv);
344 this->GetParam("LFG-ForcePositiveErmv", fForcePositiveErmv);
345 this->GetParamDef( "LFG-UseMBDistForNegativeErmv", fUseMBDist, false );
346
347 if (fPCutOff > fPMax) {
348 LOG("LocalFGM", pFATAL) << "Momentum CutOff greater than Momentum Max";
349 exit(78);
350 }
351
352 if (fSRC_Fraction > 0 && fSRC_Ermv_sigma <= 0)
353 {
354 LOG("LocalFGM", pFATAL) << "Configured SRC Maxwell-Boltzmann sigma (" << fSRC_Ermv_sigma << ") invalid: must be nonnegative";
355 exit(78);
356 }
357
358 // Load removal energy for specific nuclei from either the algorithm's
359 // configuration file or the UserPhysicsOptions file.
360 // If none is used use Wapstra's semi-empirical formula.
361 //
362
363 for(int Z=1; Z<140; Z++) {
364 for(int A=Z; A<3*Z; A++) {
365 ostringstream key ;
366 int pdgc = pdg::IonPdgCode(A,Z);
367 key << "RFG-NucRemovalE@Pdg=" << pdgc;
368 RgKey rgkey = key.str();
369 double eb ;
370 if ( GetParam( rgkey, eb, false ) ) {
371 eb = TMath::Max(eb, 0.);
372 LOG("LocalFGM", pINFO) << "Nucleus: " << pdgc << " -> using Eb = " << eb << " GeV";
373 fNucRmvE.insert(map<int,double>::value_type(Z,eb));
374 }
375 }
376 }
377}
378//____________________________________________________________________________
#define pNOTICE
Definition Messenger.h:61
#define pINFO
Definition Messenger.h:62
#define pFATAL
Definition Messenger.h:56
#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.
string RgKey
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
bool fForcePositiveErmv
Definition LocalFGM.h:84
double fSRC_Ermv_sigma
Definition LocalFGM.h:97
double fPCutOff
Definition LocalFGM.h:89
virtual double LocalFermiMomentum(const Target &t, int nucleon_pdg, double radius) const
Definition LocalFGM.cxx:296
virtual ~LocalFGM()
Definition LocalFGM.cxx:48
double fSRC_Fraction
Definition LocalFGM.h:88
double fSRC_Ermv_C
Definition LocalFGM.h:93
double Prob(double p, double w, const Target &t, double hitNucleonRadius) const
Definition LocalFGM.cxx:176
map< int, double > fNucRmvE
Definition LocalFGM.h:80
double MaxwellBoltzmannRemovalE(const Target &t, double Ermv_min, double Ermv_max) const
Definition LocalFGM.cxx:267
TH1D * ProbDistro(const Target &t, double r) const
Definition LocalFGM.cxx:192
void LoadConfig(void)
Definition LocalFGM.cxx:324
bool GenerateNucleon(const Target &t, double hitNucleonRadius) const
Definition LocalFGM.cxx:53
void Configure(const Registry &config)
Definition LocalFGM.cxx:312
virtual void LoadConfig()
A singleton holding random number generator classes. All random number generation in GENIE should tak...
Definition RandomGen.h:29
static RandomGen * Instance()
Access instance.
Definition RandomGen.cxx:74
TRandom3 & RndGen(void) const
rnd number generator for generic usage
Definition RandomGen.h:80
A registry. Provides the container for algorithm configuration parameters.
Definition Registry.h:65
A Neutrino Interaction Target. Is a transparent encapsulation of quite different physical systems suc...
Definition Target.h:40
string AsString(void) const
Definition Target.cxx:383
int HitNucPdg(void) const
Definition Target.cxx:304
int N(void) const
Definition Target.h:69
int Z(void) const
Definition Target.h:68
int A(void) const
Definition Target.h:70
double Mass(void) const
Definition Target.cxx:224
double HitNucMass(void) const
Definition Target.cxx:233
bool HitNucIsSet(void) const
Definition Target.cxx:283
Basic constants.
int IonPdgCode(int A, int Z)
Definition PDGUtils.cxx:71
bool IsProton(int pdgc)
Definition PDGUtils.cxx:336
bool IsNeutron(int pdgc)
Definition PDGUtils.cxx:341
static constexpr double fermi
Definition Units.h:55
Simple functions for loading and reading nucleus dependent keys from config files.
double Density(double r, int A, double ring=0.)
double BindEnergyPerNucleon(const Target &target)
Root of GENIE utility namespaces.
THE MAIN GENIE PROJECT NAMESPACE
Definition AlgCmp.h:25