diff --git a/config/HybridXSecAlgorithm.xml b/config/HybridXSecAlgorithm.xml
index e14294658..9147f9198 100644
--- a/config/HybridXSecAlgorithm.xml
+++ b/config/HybridXSecAlgorithm.xml
@@ -269,6 +269,246 @@ XSecAlg@Interaction=XX alg Yes Algorithm to use to handle interactio
genie::RosenbluthPXSec/Default
+
+
+ genie::SmithMonizQELCCPXSec/Dipole
+
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+
+
+ genie::SmithMonizQELCCPXSec/ZExp
+
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+
+
+ genie::SmithMonizQELCCPXSec/RunningMA
+
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+
+
+ genie::SmithMonizQELCCPXSec/RunningMA
+
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+
+
+ genie::NievesQELCCPXSec/IsoscalarDipole
+
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+
+
+ genie::NievesQELCCPXSec/IsoscalarDipoleNoRPA
+
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+
+
+ genie::NievesQELCCPXSec/IsoscalarDipoleNoCoulomb
+
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+
+
+ genie::NievesQELCCPXSec/IsoscalarDipoleNoPauli
+
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarDipole
+
+
+
+ genie::NievesQELCCPXSec/IsoscalarIsoscalarZExp
+
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarZExp
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarZExp
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarZExp
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarZExp
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarZExp
+
+ genie::LwlynSmithQELCCPXSec/IsoscalarZExp
+
+
+
+ genie::NievesQELCCPXSec/Dipole
+
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+
+
+ genie::NievesQELCCPXSec/DipoleNoRPA
+
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+
+
+ genie::NievesQELCCPXSec/DipoleNoCoulomb
+
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+
+
+ genie::NievesQELCCPXSec/DipoleNoPauli
+
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+ genie::LwlynSmithQELCCPXSec/Dipole
+
+
+
+ genie::NievesQELCCPXSec/ZExp
+
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+ genie::LwlynSmithQELCCPXSec/ZExp
+
+
+
diff --git a/config/LwlynSmithIsoFFCC.xml b/config/LwlynSmithIsoFFCC.xml
new file mode 100644
index 000000000..e9e943262
--- /dev/null
+++ b/config/LwlynSmithIsoFFCC.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+ WeakInt,MagnMoments,StrongInt,ElasticFF
+
+
+
+
+
+ genie::DipoleAxialFormFactorModel/Default
+
+
+
+ genie::ZExpAxialFormFactorModel/Default
+
+
+
+ genie::MArunAxialFormFactorModel/Default
+
+
+
+ genie::GalsterELFormFactorsModel/MK
+ genie::DipoleAxialFormFactorModel/MK
+ true
+
+
+
+ genie::GalsterELFormFactorsModel/MK
+ genie::DipoleAxialFormFactorModel/MK
+ false
+
+
+
+
+
diff --git a/config/LwlynSmithQELCCPXSec.xml b/config/LwlynSmithQELCCPXSec.xml
index 9dfa64588..6b0dc0f45 100644
--- a/config/LwlynSmithQELCCPXSec.xml
+++ b/config/LwlynSmithQELCCPXSec.xml
@@ -14,6 +14,8 @@ XSec-Integrator alg No
CabibboAngle double No Cabibbo angle CommonParam[CKM]
QEL-CC-XSecScale double yes XSec Scaling factor for CC 1.
QEL-NC-XSecScale double yes XSec Scaling factor for NC 1.
+PreciseLeptonPol bool Yes Do precise calculation of No
+ lepton polarization
.....................................................................................................
Parameters needed when Integrating with this model to generate splines:
@@ -40,12 +42,16 @@ IntegralNuclearInfluenceCutoffEnergy double No
genie::PauliBlocker/Default
true
-
+ true
genie::LwlynSmithFFCC/Dipole
+
+
+ genie::LwlynSmithIsoFFCC/Dipole
+
@@ -56,12 +62,15 @@ IntegralNuclearInfluenceCutoffEnergy double No
genie::LwlynSmithFFCC/ZExp
-
+
+
+
+ genie::LwlynSmithIsoFFCC/ZExp
+
genie::LwlynSmithFFCC/RunningMA
-
diff --git a/config/MKFFCC.xml b/config/MKFFCC.xml
deleted file mode 100644
index 4f19876c4..000000000
--- a/config/MKFFCC.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
- WeakInt,MagnMoments,StrongInt,ElasticFF
- genie::GalsterELFormFactorsModel/MK
- genie::DipoleAxialFormFactorModel/MK
-
-
-
-
-
-
diff --git a/config/MKFFEM.xml b/config/MKFFEM.xml
deleted file mode 100644
index 03bdf7a45..000000000
--- a/config/MKFFEM.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
- ElasticFF
-
- genie::GalsterELFormFactorsModel/MK
-
-
-
-
-
-
diff --git a/config/MKSPPPXSec2020.xml b/config/MKSPPPXSec2020.xml
index e029549c9..e89597151 100644
--- a/config/MKSPPPXSec2020.xml
+++ b/config/MKSPPPXSec2020.xml
@@ -59,8 +59,8 @@ XSec-Integrator alg No
0.840
0.882856
- genie::MKFFCC/Default
- genie::MKFFEM/Default
+ genie::LwlynSmithIsoFFCC/MK-CC
+ genie::LwlynSmithIsoFFCC/MK-EM
genie::RSHelicityAmplModelCC/Default
diff --git a/config/Messenger.xml b/config/Messenger.xml
index 1cfd3ce03..d23d5badf 100644
--- a/config/Messenger.xml
+++ b/config/Messenger.xml
@@ -154,6 +154,7 @@
NOTICE
INFO
NOTICE
+ NOTICE
WARN
NOTICE
WARN
diff --git a/config/Messenger_inuke_verbose.xml b/config/Messenger_inuke_verbose.xml
index e53bb4f35..bb37d6487 100644
--- a/config/Messenger_inuke_verbose.xml
+++ b/config/Messenger_inuke_verbose.xml
@@ -130,6 +130,7 @@
NOTICE
INFO
NOTICE
+ NOTICE
NOTICE
NOTICE
NOTICE
diff --git a/config/Messenger_laconic.xml b/config/Messenger_laconic.xml
index 1cfaf6590..e54b8878c 100644
--- a/config/Messenger_laconic.xml
+++ b/config/Messenger_laconic.xml
@@ -148,6 +148,7 @@
WARN
WARN
WARN
+ WARN
WARN
WARN
WARN
diff --git a/config/Messenger_rambling.xml b/config/Messenger_rambling.xml
index e591abc5e..64024fca5 100644
--- a/config/Messenger_rambling.xml
+++ b/config/Messenger_rambling.xml
@@ -147,6 +147,7 @@
NOTICE
INFO
NOTICE
+ NOTICE
NOTICE
NOTICE
NOTICE
diff --git a/config/Messenger_whisper.xml b/config/Messenger_whisper.xml
index c8d945a86..f10c5fbc9 100644
--- a/config/Messenger_whisper.xml
+++ b/config/Messenger_whisper.xml
@@ -146,6 +146,7 @@
FATAL
FATAL
FATAL
+ FATAL
FATAL
FATAL
FATAL
diff --git a/config/NievesQELCCPXSec.xml b/config/NievesQELCCPXSec.xml
index 2f41146ef..6e552502a 100644
--- a/config/NievesQELCCPXSec.xml
+++ b/config/NievesQELCCPXSec.xml
@@ -6,16 +6,17 @@
Configuration for the Nieves QEL CCP xsec algorithm.
Configurable Parameters:
-.....................................................................................................
-Name Type Optional Comment Default
-.....................................................................................................
-FormFactorsAlg alg No QEL form factors algorithm
-XSec-Integrator alg No
-CabibboAngle double No Cabibbo angle CommonParam[CKM]
-RPA bool Yes Turn RPA effects on or off true
-Coulomb bool Yes Turn coulomb effects on or off true
-QEL-CC-XSecScale double Yes Scaling factor for CC GPL value
-QEL-NC-XSecScale double Yes Scaling factor for NC GPL value
+...................................................................................................................
+Name Type Optional Comment Default
+...................................................................................................................
+FormFactorsAlg alg No QEL form factors algorithm
+XSec-Integrator alg No
+CabibboAngle double No Cabibbo angle CommonParam[CKM]
+RPA bool Yes Turn RPA effects on or off true
+Coulomb bool Yes Turn coulomb effects on or off true
+QEL-CC-XSecScale double Yes Scaling factor for CC GPL value
+PreciseLeptonPol bool Yes Do precise calculation of lepton polarization No
+LindhardFunction string Yes Which Lindhard functions to use? OriginalByNieves
.....................................................................................................
Parameters needed when Integrating with this model to generate splines:
@@ -35,22 +36,23 @@ RmaxMode string Yes Method to use to comput
CKM,FermiGas,NUCL
1.000
- 1.000
genie::NewQELXSec/Default
genie::NuclearModelMap/Default
UseNuclearModel
10.0
- true
+ true
true
- false
genie::PauliBlocker/Default
true
VertexGenerator
+
+ true
+ OriginalByNieves
+
+
+ adaptive
+ 1e-4
+ 7500
+ 1000000
+
+ adaptive
+ 1e-4
+ 1000000
+
+
+
+
+
+
+
diff --git a/config/NievesSimoVacasMECPXSec2016.xml b/config/NievesSimoVacasMECPXSec2016.xml
index 7bd6ed289..6128336d4 100644
--- a/config/NievesSimoVacasMECPXSec2016.xml
+++ b/config/NievesSimoVacasMECPXSec2016.xml
@@ -14,6 +14,8 @@ MEC-CC-XSecScale double Yes XSec Scaling factor GPL v
MECScaleAlg alg Yes XSecScale algorithm used The cross section is not scaled
to scale the cross section
QvalueShifterAlg algo yes Possible Qshift algo none
+PreciseLeptonPol bool Yes Do precise calculation of No
+ lepton polarization
-->
genie::MECXSec/Default
@@ -22,6 +24,9 @@ QvalueShifterAlg algo yes Possible Qshift algo none
1.000
1.000
+
+ true
+
diff --git a/config/PaisQELLambdaPXSec.xml b/config/PaisQELLambdaPXSec.xml
index 590af97be..82bddf1e4 100644
--- a/config/PaisQELLambdaPXSec.xml
+++ b/config/PaisQELLambdaPXSec.xml
@@ -9,6 +9,8 @@ Algorithm Configurable Parameters:
......................................................................................................
Name Type Optional Comment Default
......................................................................................................
+PreciseLeptonPol bool Yes Do precise calculation of No
+ lepton polarization
XSec-Integrator alg No xsection integration algorithm
-->
@@ -18,6 +20,7 @@ XSec-Integrator alg No xsection integration algorithm
genie::LwlynSmithFFDeltaS/Default
genie::QELXSec/Default
+ true
diff --git a/config/SmithMonizQELCCPXSec.xml b/config/SmithMonizQELCCPXSec.xml
index 2348c88db..f2cecb992 100644
--- a/config/SmithMonizQELCCPXSec.xml
+++ b/config/SmithMonizQELCCPXSec.xml
@@ -12,6 +12,8 @@ Name Type Optional Comment Default
FormFactorsAlg alg No QEL form factors algorithm
XSec-Integrator alg No Integrator
CKM-Vud double No Vud element of CKM-matrix CommonParam[CKM]
+PreciseLeptonPol bool Yes Do precise calculation of No
+ lepton polarization
QEL-CC-XSecScale double yes XSec Scaling factor 1.
-->
@@ -23,6 +25,7 @@ QEL-CC-XSecScale double yes XSec Scaling factor 1.
1.000
genie::LwlynSmithFFCC/Default
genie::SmithMonizQELCCXSec/Default
+ true
diff --git a/config/SmithMonizQELCCXSec.xml b/config/SmithMonizQELCCXSec.xml
index 2d794afa3..e6b9d55fd 100644
--- a/config/SmithMonizQELCCXSec.xml
+++ b/config/SmithMonizQELCCXSec.xml
@@ -11,24 +11,26 @@ Name Type Optional Comment
gsl-integration-type string Yes name of GSL 1D numerical integrator gauss
gsl-max-size-of-subintervals int Yes GSL maximum number of sub-intervals 40000
for 1D integrator
-gsl-relative-tolerance double Yes GSL max evaluations for 1D integrator 1e-3
+gsl-relative-tolerance double Yes GSL max evaluations for 1D integrator 1e-5
gsl-rule int Yes GSL Gauss-Kronrod integration rule 3
(only for GSL 1D adaptive type)
gsl-integration-type-2D string Yes name of GSL 2D numerical integrator adaptive
-gsl-max-eval int Yes required relative tolerance (error) 1000000000
- for 2D integrator
-gsl-relative-tolerance-2D double Yes GSL max evaluations for 2D integrator 1e-7
+gsl-max-eval int Yes GSL max evaluations for 2D integrator 100000
+gsl-min-eval int Yes GSL min evaluations for 2D integrator 7500
+gsl-relative-tolerance-2D double Yes required relative tolerance (error)
+ for 2D integrator 1e-5
.....................................................................................................
-->
gauss
40000
- 1e-3
+ 1e-5
3
adaptive
- 1000000000
- 1e-7
+ 100000
+ 7500
+ 1e-5
diff --git a/config/SuSAv2MECPXSec.xml b/config/SuSAv2MECPXSec.xml
index 83763ca0a..b5a907b9d 100644
--- a/config/SuSAv2MECPXSec.xml
+++ b/config/SuSAv2MECPXSec.xml
@@ -14,6 +14,8 @@ CKM-Vud double No Vud element of CKM matrix
FermiMomentumTable string No Table of Fermi momentum (kF) constants CommonParam[FermiGas]
MECScaleAlg alg Yes XSecScale algorithm used The cross section is unscaled
to scale the cross section
+PreciseLeptonPol bool Yes Do precise calculation of No
+ lepton polarization
QvalueShifterAlg algo yes Qvalue shifter algo none
-->
@@ -24,6 +26,7 @@ QvalueShifterAlg algo yes Qvalue shifter algo
1.000
1.000
FermiGas
+ true
diff --git a/config/SuSAv2QELPXSec.xml b/config/SuSAv2QELPXSec.xml
index 1e9c80218..9ac2d809a 100644
--- a/config/SuSAv2QELPXSec.xml
+++ b/config/SuSAv2QELPXSec.xml
@@ -13,6 +13,8 @@ XSec-Integrator alg No
QEL-CC-XSecScale double yes XSec Scaling factor for CC 1.
QEL-NC-XSecScale double yes XSec Scaling factor for NC 1.
QEL-EM-XSecScale double yes XSec Scaling factor for EM 1.
+PreciseLeptonPol bool Yes Do precise calculation of No
+ lepton polarization
FermiMomentumTable string No Table of Fermi momentum (kF) constants CommonParam[FermiGas]
QvalueShifterAlg alg yes QValue shifter algo none
.....................................................................................................
@@ -44,6 +46,8 @@ Name Type Optional Comment
genie::MECXSec/Default
+ true
+
QELXSec.xml
NewQELXSec.xml
+ NievesQELCCXSec.xml
SmithMonizQELCCXSec.xml
DISXSec.xml
COHDNuXSec.xml
@@ -217,7 +217,7 @@
ReinSehgalRESXSec.xml
ReinSehgalSPPXSec.xml
MKSPPPXSec2020.xml
- SPPXSec.xml
+ SPPXSec.xml
H3AMNuGammaPXSec.xml
EmpiricalMECPXSec2015.xml
NievesSimoVacasMECPXSec2016.xml
diff --git a/src/Framework/Conventions/KinePhaseSpace.h b/src/Framework/Conventions/KinePhaseSpace.h
index a51c72add..6d7a0813b 100644
--- a/src/Framework/Conventions/KinePhaseSpace.h
+++ b/src/Framework/Conventions/KinePhaseSpace.h
@@ -75,7 +75,9 @@ typedef enum EKinePhaseSpace {
kPSn1n2n3fE,
kPSWQ2ctpphipfE,
kPSWQ2ctpfE,
- kPSQ2vpfE
+ kPSQ2vpfE,
+ kPSyphi0fEx // Phase space dimension to set lepton polarization properly
+ // for cases when an output of XSecModel depends on phase space dim.
} KinePhaseSpace_t;
class KinePhaseSpace
@@ -137,6 +139,7 @@ class KinePhaseSpace
case(kPSn1n2n3fE) : return "<{n1,n2,n3}|E>"; break;
case(kPSWQ2ctpphipfE): return "<{W, Q2, cost(theta_pion), phi_pion}|E>"; break;
case(kPSWQ2ctpfE) : return "<{W, Q2, cost(theta_pion)}|E>"; break;
+ case(kPSyphi0fEx) : return "<{y, phi0}|E,x>"; break;
}
return "** Undefined kinematic phase space **";
}
diff --git a/src/Framework/EventGen/HybridXSecAlgorithm.cxx b/src/Framework/EventGen/HybridXSecAlgorithm.cxx
index e8bd161cf..65dd30f46 100644
--- a/src/Framework/EventGen/HybridXSecAlgorithm.cxx
+++ b/src/Framework/EventGen/HybridXSecAlgorithm.cxx
@@ -10,6 +10,7 @@
#include "Framework/EventGen/HybridXSecAlgorithm.h"
#include "Framework/Messenger/Messenger.h"
+#include "Framework/ParticleData/PDGCodes.h"
using namespace genie;
@@ -80,17 +81,16 @@ double HybridXSecAlgorithm::XSec(const Interaction* interaction,
const XSecAlgorithmI* alg_to_use = this->ChooseXSecAlg( *interaction );
if ( !alg_to_use ) return 0.;
- // Ad hoc solution of problem with inappropriate kinematic phase space
- // reported by Julia so she can continue working.
- // (The reason of problem: it is intended for LlewelynSmith,
- // BUT also used by Rosenbluth)
- // A more thoughtful solutions could be
- // 1. Specify in the configuration file the phase space appropriate
- // for each algorithm
- // 2. Implement in RosenbluthPXSec the analog of method
- // LwlynSmithQELCCPXSec::FullDifferentialXSec - Igor Kakorin
- if (alg_to_use == fDefaultXSecAlg) return alg_to_use->XSec( interaction, kps );
- return alg_to_use->XSec( interaction, kPSQ2fE );
+ // Special case, when the process is EM scattering on free nucleon.
+ // In this case genie::RosenbluthPXSec is used to calculate cross-section.
+ // However, input kps is equal to either kPSTlctl for SuSAv2
+ // or kPSQELEvGen for LwlynSmithQELCCPXSec (2d phase spaces),
+ // while RosenbluthPXSec uses kPSQ2fE (1d phase space)
+ // and there is no way to transform 1d to 2d phase space.
+ if ( alg_to_use->Id().Name() == "genie::RosenbluthPXSec")
+ return alg_to_use->XSec( interaction, kPSQ2fE );
+ return alg_to_use->XSec( interaction, kps );
+
}
//_________________________________________________________________________
double HybridXSecAlgorithm::Integral(const Interaction* interaction) const
@@ -138,3 +138,13 @@ void HybridXSecAlgorithm::LoadConfig(void)
assert( fDefaultXSecAlg );
}
}
+//____________________________________________________________________________
+const TVector3 & HybridXSecAlgorithm::FinalLeptonPolarization (const Interaction* interaction) const
+{
+ const XSecAlgorithmI* alg_to_use = this->ChooseXSecAlg( *interaction );
+
+ if ( !alg_to_use ) return XSecAlgorithmI::FinalLeptonPolarization(interaction);
+
+ return alg_to_use->FinalLeptonPolarization( interaction );
+}
+//____________________________________________________________________________
diff --git a/src/Framework/EventGen/HybridXSecAlgorithm.h b/src/Framework/EventGen/HybridXSecAlgorithm.h
index 10d5a97a9..40624d0c8 100644
--- a/src/Framework/EventGen/HybridXSecAlgorithm.h
+++ b/src/Framework/EventGen/HybridXSecAlgorithm.h
@@ -44,6 +44,7 @@ class HybridXSecAlgorithm : public XSecAlgorithmI {
double XSec(const Interaction* i, KinePhaseSpace_t k) const;
double Integral(const Interaction* i) const;
bool ValidProcess(const Interaction* i) const;
+ const TVector3 & FinalLeptonPolarization (const Interaction* i) const;
// override the Algorithm::Configure methods to load configuration
// data to private data members
@@ -59,7 +60,7 @@ class HybridXSecAlgorithm : public XSecAlgorithmI {
/// using the map. If no suitable algorithm was found, return a
/// null pointer.
const XSecAlgorithmI* ChooseXSecAlg(const Interaction& interaction) const;
-
+
/// Map specifying the managed cross section algorithms. Keys are strings
/// generated with Interaction::AsString() (identical to those used for
/// splines). Values are pointers to the corresponding cross section
diff --git a/src/Framework/EventGen/XSecAlgorithmI.cxx b/src/Framework/EventGen/XSecAlgorithmI.cxx
index 6e370be0d..7d168ecc6 100644
--- a/src/Framework/EventGen/XSecAlgorithmI.cxx
+++ b/src/Framework/EventGen/XSecAlgorithmI.cxx
@@ -10,6 +10,7 @@
#include "Framework/EventGen/XSecAlgorithmI.h"
#include "Framework/Messenger/Messenger.h"
+#include "Framework/ParticleData/PDGUtils.h"
using namespace genie;
@@ -17,19 +18,22 @@ using namespace genie;
XSecAlgorithmI::XSecAlgorithmI() :
Algorithm()
{
-
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ fIsPreciseLeptonPolarization = false;
}
//___________________________________________________________________________
XSecAlgorithmI::XSecAlgorithmI(string name) :
Algorithm(name)
{
-
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ fIsPreciseLeptonPolarization = false;
}
//___________________________________________________________________________
XSecAlgorithmI::XSecAlgorithmI(string name, string config) :
Algorithm(name, config)
{
-
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ fIsPreciseLeptonPolarization = false;
}
//___________________________________________________________________________
XSecAlgorithmI::~XSecAlgorithmI()
@@ -57,3 +61,23 @@ bool XSecAlgorithmI::ValidKinematics(const Interaction* interaction) const
return true;
}
//___________________________________________________________________________
+const TVector3 & XSecAlgorithmI::FinalLeptonPolarization (const Interaction* i) const
+{
+ if ( i->ProcInfo().IsEM() )
+ {
+ LOG("XSecBase", pWARN) << "For EM processes doesn't work yet. Set it to zero.";
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+ int pdg = i->FSPrimLeptonPdg();
+ if ( pdg::IsNeutrino(pdg) || pdg::IsElectron(pdg) || pdg::IsMuon(pdg) || pdg::IsTau(pdg) )
+ {
+ fFinalLeptonPolarization = TVector3(0, 0, -1);
+ }
+ else
+ {
+ fFinalLeptonPolarization = TVector3(0, 0, 1);
+ }
+ return fFinalLeptonPolarization;
+}
+//___________________________________________________________________________
diff --git a/src/Framework/EventGen/XSecAlgorithmI.h b/src/Framework/EventGen/XSecAlgorithmI.h
index 2674ce60f..43eaccf09 100644
--- a/src/Framework/EventGen/XSecAlgorithmI.h
+++ b/src/Framework/EventGen/XSecAlgorithmI.h
@@ -18,6 +18,8 @@
#ifndef _XSEC_ALGORITHM_I_H_
#define _XSEC_ALGORITHM_I_H_
+#include "TVector3.h"
+
#include "Framework/Algorithm/Algorithm.h"
#include "Framework/Conventions/KinePhaseSpace.h"
#include "Framework/Interaction/Interaction.h"
@@ -31,6 +33,8 @@ class XSecAlgorithmI : public Algorithm {
//! Compute the cross section for the input interaction
virtual double XSec (const Interaction* i, KinePhaseSpace_t k=kPSfE) const = 0;
+
+ virtual const TVector3 & FinalLeptonPolarization (const Interaction* i) const;
//! Integrate the model over the kinematic phase space available to the
//! input interaction (kinematical cuts can be included)
@@ -46,6 +50,9 @@ class XSecAlgorithmI : public Algorithm {
XSecAlgorithmI();
XSecAlgorithmI(string name);
XSecAlgorithmI(string name, string config);
+
+ mutable TVector3 fFinalLeptonPolarization;
+ bool fIsPreciseLeptonPolarization;
};
} // genie namespace
diff --git a/src/Framework/GHEP/GHepParticle.cxx b/src/Framework/GHEP/GHepParticle.cxx
index a34d0e9f0..0a36264dc 100644
--- a/src/Framework/GHEP/GHepParticle.cxx
+++ b/src/Framework/GHEP/GHepParticle.cxx
@@ -68,10 +68,8 @@ fLastDaughter(daughter2)
fP4 = new TLorentzVector(p);
fX4 = new TLorentzVector(v);
-
+ fPolarization = TVector3(0, 0, 0);
fRescatterCode = -1;
- fPolzTheta = -999;
- fPolzPhi = -999;
fIsBound = false;
fRemovalEnergy = 0.;
}
@@ -92,10 +90,8 @@ fLastDaughter(daughter2)
fP4 = new TLorentzVector(px,py,pz,En);
fX4 = new TLorentzVector(x,y,z,t);
-
+ fPolarization = TVector3(0, 0, 0);
fRescatterCode = -1;
- fPolzTheta = -999;
- fPolzPhi = -999;
fIsBound = false;
fRemovalEnergy = 0.;
}
@@ -119,8 +115,7 @@ fFirstDaughter(-1),
fLastDaughter(-1),
fP4(0),
fX4(0),
-fPolzTheta(-999.),
-fPolzPhi(-999.),
+fPolarization( TVector3(0, 0, 0) ),
fRemovalEnergy(0),
fIsBound(false)
{
@@ -305,59 +300,6 @@ bool GHepParticle::IsOffMassShell(void) const
return (! this->IsOnMassShell());
}
//___________________________________________________________________________
-bool GHepParticle::PolzIsSet(void) const
-{
-// checks whether the polarization angles have been set
-
- return (fPolzTheta > -999 && fPolzPhi > -999);
-}
-//___________________________________________________________________________
-void GHepParticle::GetPolarization(TVector3 & polz)
-{
-// gets the polarization vector
-
- if(! this->PolzIsSet() ) {
- polz.SetXYZ(0.,0.,0.);
- return;
- }
- polz.SetX( TMath::Sin(fPolzTheta) * TMath::Cos(fPolzPhi) );
- polz.SetY( TMath::Sin(fPolzTheta) * TMath::Sin(fPolzPhi) );
- polz.SetZ( TMath::Cos(fPolzTheta) );
-}
-//___________________________________________________________________________
-void GHepParticle::SetPolarization(double theta, double phi)
-{
-// sets the polarization angles
-
- if(theta>=0 && theta<=kPi && phi>=0 && phi<2*kPi)
- {
- fPolzTheta = theta;
- fPolzPhi = phi;
-
- } else {
- LOG("GHepParticle", pERROR)
- << "Invalid polarization angles (polar = " << theta
- << ", azimuthal = " << phi << ")";
- }
-}
-//___________________________________________________________________________
-void GHepParticle::SetPolarization(const TVector3 & polz)
-{
-// sets the polarization angles
-
- double p = polz.Mag();
- if(! (p>0) ) {
- LOG("GHepParticle", pERROR)
- << "Input polarization vector has non-positive norm! Ignoring it";
- return;
- }
-
- double theta = TMath::ACos(polz.z()/p);
- double phi = kPi + TMath::ATan2(-polz.y(), -polz.x());
-
- this->SetPolarization(theta,phi);
-}
-//___________________________________________________________________________
void GHepParticle::SetBound(bool bound)
{
// only set it for p or n
@@ -394,8 +336,7 @@ void GHepParticle::Init(void)
fLastMother = -1;
fFirstDaughter = -1;
fLastDaughter = -1;
- fPolzTheta = -999;
- fPolzPhi = -999;
+ fPolarization = TVector3(0, 0, 0);
fIsBound = false;
fRemovalEnergy = 0.;
fP4 = new TLorentzVector(0,0,0,0);
@@ -525,8 +466,7 @@ void GHepParticle::Copy(const GHepParticle & particle)
this->SetMomentum (*particle.P4());
this->SetPosition (*particle.X4());
- this->fPolzTheta = particle.fPolzTheta;
- this->fPolzPhi = particle.fPolzPhi;
+ this->fPolarization = particle.fPolarization;
this->fIsBound = particle.fIsBound;
this->fRemovalEnergy = particle.fRemovalEnergy;
diff --git a/src/Framework/GHEP/GHepParticle.h b/src/Framework/GHEP/GHepParticle.h
index 6d70af7a9..1c0686db3 100644
--- a/src/Framework/GHEP/GHepParticle.h
+++ b/src/Framework/GHEP/GHepParticle.h
@@ -116,10 +116,10 @@ public :
// Get the polarization. Most likely it is only the f/s primary lepton
// for which this is usefull and might be set during event generation
- double PolzPolarAngle (void) const { return fPolzTheta; }
- double PolzAzimuthAngle (void) const { return fPolzPhi; }
- bool PolzIsSet (void) const;
- void GetPolarization (TVector3 & polz);
+ double PolzPolarAngle (void) const { return fPolarization.Mag()>0?fPolarization.Theta():0; }
+ double PolzAzimuthAngle (void) const { return fPolarization.Mag()>0?fPolarization.Phi():0; }
+ bool PolzIsSet (void) const { return fPolarization.Mag()>0;}
+ void GetPolarization (TVector3 & polz) const {polz = fPolarization;}
// Set pdg code and status codes
void SetPdgCode (int c);
@@ -144,9 +144,7 @@ public :
void SetPy (double py);
void SetPz (double pz);
- // Set the polarization angles
- void SetPolarization(double theta, double phi);
- void SetPolarization(const TVector3 & polz);
+ void SetPolarization(const TVector3 & polz) { fPolarization = polz;}
// Set the bould flag & removal energy (bound flag set automatically
// if a positive removal energy is set)
@@ -180,12 +178,11 @@ public :
int fLastDaughter; ///< last daughter idx
TLorentzVector * fP4; ///< momentum 4-vector (GeV)
TLorentzVector * fX4; ///< position 4-vector (in the target nucleus coordinate system / x,y,z in fm / t from the moment of the primary interaction in ys(yocto second = 10^-24 s)
- double fPolzTheta; ///< polar polarization angle (rad)
- double fPolzPhi; ///< azimuthal polarization angle (rad)
+ TVector3 fPolarization; ///< polarization vector of final lepton
double fRemovalEnergy; ///< removal energy for bound nucleons (GeV)
bool fIsBound; ///< 'is it a bound particle?' flag
-ClassDef(GHepParticle, 2)
+ClassDef(GHepParticle, 3)
};
diff --git a/src/Framework/GHEP/GHepRecord.h b/src/Framework/GHEP/GHepRecord.h
index 03f4013bb..b497e52d1 100644
--- a/src/Framework/GHEP/GHepRecord.h
+++ b/src/Framework/GHEP/GHepRecord.h
@@ -197,7 +197,7 @@ public :
private:
-ClassDef(GHepRecord, 2)
+ClassDef(GHepRecord, 3)
};
diff --git a/src/Framework/Interaction/KPhaseSpace.cxx b/src/Framework/Interaction/KPhaseSpace.cxx
index 50b830202..1cce481eb 100644
--- a/src/Framework/Interaction/KPhaseSpace.cxx
+++ b/src/Framework/Interaction/KPhaseSpace.cxx
@@ -311,6 +311,7 @@ bool KPhaseSpace::IsAboveThreshold(void) const
pi.IsDarkMatterDeepInelastic() ||
pi.IsDiffractive() ||
pi.IsSingleKaon() ||
+ pi.IsSinglePion() ||
pi.IsAMNuGamma())
{
E = init_state.ProbeE(kRfHitNucRest);
diff --git a/src/Framework/Utils/KineUtils.cxx b/src/Framework/Utils/KineUtils.cxx
index 5b5917134..9abbe4d9b 100644
--- a/src/Framework/Utils/KineUtils.cxx
+++ b/src/Framework/Utils/KineUtils.cxx
@@ -154,8 +154,8 @@ double genie::utils::kinematics::Jacobian(
<< KinePhaseSpace::AsString(fromps) << " --> "
<< KinePhaseSpace::AsString(tops);
- double J=0;
- bool forward;
+ double J = 0;
+ bool forward = true;
const Kinematics & kine = i->Kine();
// cover the simple case
@@ -321,14 +321,166 @@ double genie::utils::kinematics::Jacobian(
// (it will be inverted below for the inverse transformation)
J = W / ( 2. * pv * pl * M );
}
+
+ else if ( TransformMatched(fromps,tops, kPSyphi0fEx, kPSQELEvGen, forward) )
+ {
+ TLorentzVector* ki4 = i->InitStatePtr()->GetProbeP4(genie::kRfLab);
+ TLorentzVector* pi4 = i->InitStatePtr()->TgtPtr()->HitNucP4Ptr();
+ TLorentzVector totMom = *ki4 + *pi4;
+ TVector3 beta = totMom.BoostVector();
+ TLorentzVector kf4(i->KinePtr()->FSLeptonP4());
+ kf4.Boost(-beta);
+
+ TVector3 zvec(0., 0., 1.);
+ TVector3 rot = ( zvec.Cross(beta) ).Unit();
+ double angle = beta.Angle( zvec );
+ // Handle the edge case where beta is along z, so the
+ // cross product above vanishes
+ if ( beta.Perp() == 0. && beta.Z() < 0. )
+ {
+ rot = TVector3(0., 1., 0.);
+ angle = genie::constants::kPi;
+ }
+
+ if ( rot.Mag() > 0 )
+ {
+ kf4.Rotate(angle, -rot);
+ }
+
+ double kf4_mag = kf4.Vect().Mag();
+ double theta_star = kf4.Theta();
+ double phi_star = kf4.Phi();
+
+ TLorentzVector kf4_dtheta(kf4_mag*TMath::Cos(phi_star)*TMath::Cos(theta_star), kf4_mag*TMath::Sin(phi_star)*TMath::Cos(theta_star), -kf4_mag*TMath::Sin(theta_star), 0);
+ TLorentzVector kf4_dphi( -kf4_mag*TMath::Sin(phi_star)*TMath::Sin(theta_star), kf4_mag*TMath::Cos(phi_star)*TMath::Sin(theta_star), 0, 0);
+ if ( theta_star <= 0 || theta_star >= genie::constants::kPi)
+ {
+ kf4_dphi = TLorentzVector( -kf4_mag*TMath::Sin(phi_star), kf4_mag*TMath::Cos(phi_star), 0, 0 );
+ }
+ // to LAB frame
+ if ( rot.Mag() > 0 )
+ {
+ kf4_dtheta.Rotate(angle, rot);
+ kf4_dphi.Rotate(angle, rot);
+ }
+ kf4_dtheta.Boost(beta);
+ kf4_dphi.Boost(beta);
+ kf4 = i->KinePtr()->FSLeptonP4();
+
+ double dQ2dtheta = 2*((*ki4)*kf4_dtheta);
+ double dQ2dphi = 2*((*ki4)*kf4_dphi);
+
+ // to hit nucleon rest frame
+ TVector3 beta1 = pi4->BoostVector();
+ kf4_dtheta.Boost(-beta1);
+ kf4_dphi.Boost(-beta1);
+ kf4.Boost(-beta1);
+
+ ki4->Boost(-beta1);
+ TVector3 ki3 = ki4->Vect();
+ TVector3 rot1 = ( ki3.Cross(zvec) ).Unit();
+ double angle1 = zvec.Angle( ki3 );
+ // Handle the edge case where beta is along z, so the
+ // cross product above vanishes
+ if ( ki3.Perp() == 0. && ki3.Z() < 0. )
+ {
+ rot1 = TVector3(0., 1., 0.);
+ angle1 = genie::constants::kPi;
+ }
+ if ( rot1.Mag() > 0 )
+ {
+ kf4_dtheta.Rotate(angle1, rot1);
+ kf4_dphi.Rotate(angle1, rot1);
+ kf4.Rotate(angle1, rot1);
+ }
+ double t = 1/( kf4.Px()*kf4.Px() + kf4.Py()*kf4.Py() );
+ double dphi0dtheta = t*(kf4_dtheta.Py()*kf4.Px() - kf4_dtheta.Px()*kf4.Py());
+ double dphi0dphi = t*(kf4_dphi.Py()*kf4.Px() - kf4_dphi.Px()*kf4.Py());
+
+ double Q2 = i->Kine().GetKV( kKVQ2 );
+ // mass of initial nucleon
+ double Mi = i->InitStatePtr()->TgtPtr()->HitNucMass();
+ // Look up the (on-shell) mass of the final nucleon
+ TDatabasePDG *tb = TDatabasePDG::Instance();
+ double Mf = tb->GetParticle( i->RecoilNucleonPdg() )->Mass();
+ // Mandelstam s for the probe/hit nucleon system
+ double s = TMath::Sq( i->InitState().CMEnergy() );
+ double dydQ2 = (s - Mi*Mi)/TMath::Sq(s - Mf*Mf - Q2);
+ if ( theta_star <= 0 || theta_star >= genie::constants::kPi)
+ J = 1;
+ else
+ J = 1/TMath::Sin(theta_star);
+
+ // It is not entirely correct to divide by 2 pi, but solely to simplify the code it is better to do it here (Igor Kakorin)
+ J = TMath::Abs(J*dydQ2*(dQ2dtheta*dphi0dphi - dQ2dphi*dphi0dtheta)/2/genie::constants::kPi);
+
+ delete ki4;
+ }
+
+ else if ( TransformMatched(fromps,tops, kPSyphi0fEx, kPSQ2fE, forward) )
+ {
+ double Q2 = i->Kine().GetKV( kKVQ2 );
+ // mass of initial nucleon
+ double Mi = i->InitStatePtr()->TgtPtr()->HitNucMass();
+ // Look up the (on-shell) mass of the final nucleon
+ TDatabasePDG *tb = TDatabasePDG::Instance();
+ double Mf = tb->GetParticle( i->RecoilNucleonPdg() )->Mass();
+ // Mandelstam s for the probe/hit nucleon system
+ double s = TMath::Sq( i->InitState().CMEnergy() );
+ double dydQ2 = (s - Mi*Mi)/TMath::Sq(s - Mf*Mf - Q2);
+ J = dydQ2;
+ }
+
+ else if ( TransformMatched(fromps,tops, kPSxyfE, kPSTlctl, forward) )
+ {
+ TLorentzVector* ki4 = i->InitStatePtr()->GetProbeP4();
+ TLorentzVector* pi4 = i->InitStatePtr()->TgtPtr()->HitNucP4Ptr();
+ TLorentzVector kf4(i->KinePtr()->FSLeptonP4());
+ // mass of initial nucleon
+ double M = i->InitStatePtr()->TgtPtr()->HitNucMass();
+
+ TVector3 beta = pi4->BoostVector();
+ kf4.Boost(-beta);
+ double nu = ki4->Energy() - kf4.Energy();
+ double Pf = kf4.Vect().Mag();
+ J = TMath::Abs(Pf/M/nu);
+
+ delete ki4;
+ }
+
+ else if ( TransformMatched(fromps,tops, kPSQ2vfE, kPSxyfE, forward) )
+ {
+ TLorentzVector* ki4 = i->InitStatePtr()->GetProbeP4(genie::kRfLab);
+ TLorentzVector kf4(i->KinePtr()->FSLeptonP4());
+ double Ev = ki4->Energy();
+ double l = kf4.Vect().Mag();
+ J = Jacobian(i, kPSTlctl, kPSxyfE);
+ J = TMath::Abs(J*2*Ev*l);
+
+ delete ki4;
+ }
+
+ else if ( TransformMatched(fromps,tops, kPSxyfE, kPSWQ2fE, forward) )
+ {
+ const InitialState & init_state = i->InitState();
+ double Ev = init_state.ProbeE(kRfHitNucRest);
+ double M = init_state.Tgt().HitNucMass();
+ double M2 = M*M;
+ double W = kine.W();
+ double W2 = W*W;
+ double Q2 = kine.Q2();
+ J = TMath::Abs( W/(Ev*M*(W2 + Q2 - M2)) );
+ }
else {
std::ostringstream msg;
msg << "Can not compute Jacobian for transforming: "
<< KinePhaseSpace::AsString(fromps) << " --> "
<< KinePhaseSpace::AsString(tops);
- SLOG("KineLimits", pFATAL) << "*** " << msg.str();
- throw genie::exceptions::InteractionException(msg.str());
+ SLOG("KineLimits", pNOTICE) << msg.str()
+ << ". Set Jacbian equal to zero!";
+ //SLOG("KineLimits", pFATAL) << "*** " << msg.str();
+ //throw genie::exceptions::InteractionException(msg.str());
//exit(1);
}
diff --git a/src/Framework/Utils/Range1.cxx b/src/Framework/Utils/Range1.cxx
index 10911c954..b6fe7ebf0 100644
--- a/src/Framework/Utils/Range1.cxx
+++ b/src/Framework/Utils/Range1.cxx
@@ -45,6 +45,13 @@ void Range1F_t::Copy(const Range1F_t & r)
max = r.max;
}
//____________________________________________________________________________
+Range1F_t & Range1F_t::operator=(const Range1F_t &r)
+{
+ min = r.min;
+ max = r.max;
+ return *this;
+}
+//____________________________________________________________________________
Range1D_t::Range1D_t(void) :
min(0.),
max(0.)
@@ -77,6 +84,13 @@ void Range1D_t::Copy(const Range1D_t & r)
max = r.max;
}
//____________________________________________________________________________
+Range1D_t & Range1D_t::operator=(const Range1D_t &r)
+{
+ min = r.min;
+ max = r.max;
+ return *this;
+}
+//____________________________________________________________________________
Range1I_t::Range1I_t(void) :
min(0),
max(0)
@@ -109,3 +123,10 @@ void Range1I_t::Copy(const Range1I_t & r)
max = r.max;
}
//____________________________________________________________________________
+Range1I_t & Range1I_t::operator=(const Range1I_t &r)
+{
+ min = r.min;
+ max = r.max;
+ return *this;
+}
+//____________________________________________________________________________
diff --git a/src/Framework/Utils/Range1.h b/src/Framework/Utils/Range1.h
index 464ed1cbd..ba39369f1 100644
--- a/src/Framework/Utils/Range1.h
+++ b/src/Framework/Utils/Range1.h
@@ -31,6 +31,7 @@ class Range1F_t
Range1F_t (void);
Range1F_t (float _min, float _max);
Range1F_t (const Range1F_t & r);
+ Range1F_t &operator=(const Range1F_t &r);
~Range1F_t (void);
void Copy (const Range1F_t & r);
@@ -45,6 +46,8 @@ class Range1D_t
Range1D_t (void);
Range1D_t (double _min, double _max);
Range1D_t (const Range1D_t & r);
+ Range1D_t &operator=(const Range1D_t &r);
+
~Range1D_t (void);
void Copy (const Range1D_t & r);
@@ -59,6 +62,7 @@ class Range1I_t
Range1I_t (void);
Range1I_t (int _min, int _max);
Range1I_t (const Range1I_t & r);
+ Range1I_t &operator=(const Range1I_t &r);
~Range1I_t (void);
void Copy (const Range1I_t & r);
diff --git a/src/Physics/Common/NormGenerator.cxx b/src/Physics/Common/NormGenerator.cxx
index 1107c298f..f6f9fb081 100644
--- a/src/Physics/Common/NormGenerator.cxx
+++ b/src/Physics/Common/NormGenerator.cxx
@@ -30,8 +30,14 @@ EventRecordVisitorI("genie::NormGenerator")
}
//___________________________________________________________________________
-NormGenerator::NormGenerator(string config):
-EventRecordVisitorI("genie::NormGenerator")
+NormGenerator::NormGenerator(string name):
+EventRecordVisitorI(name)
+{
+
+}
+//___________________________________________________________________________
+NormGenerator::NormGenerator(string name, string config):
+EventRecordVisitorI(name, config)
{
}
@@ -44,8 +50,7 @@ NormGenerator::~NormGenerator()
void NormGenerator::ProcessEventRecord(GHepRecord * evrec) const
{
Interaction * interaction = evrec->Summary();
- const InitialState & init_state = interaction -> InitState();
-
+
// Access cross section algorithm for running thread
RunningThreadInfo * rtinfo = RunningThreadInfo::Instance();
const EventGeneratorI * evg = rtinfo->RunningThread();
diff --git a/src/Physics/Common/NormGenerator.h b/src/Physics/Common/NormGenerator.h
index 49cc5388e..d3b0d63ab 100644
--- a/src/Physics/Common/NormGenerator.h
+++ b/src/Physics/Common/NormGenerator.h
@@ -34,7 +34,8 @@ namespace genie {
public :
NormGenerator();
- NormGenerator(string config);
+ NormGenerator(string name);
+ NormGenerator(string name, string config);
~NormGenerator();
// implement the EventRecordVisitorI interface
diff --git a/src/Physics/Common/PrimaryLeptonUtils.cxx b/src/Physics/Common/PrimaryLeptonUtils.cxx
index 25ad55800..215d297cf 100644
--- a/src/Physics/Common/PrimaryLeptonUtils.cxx
+++ b/src/Physics/Common/PrimaryLeptonUtils.cxx
@@ -8,16 +8,27 @@
*/
//____________________________________________________________________________
+#include "TLorentzVector.h"
#include "TVector3.h"
+#include "TMath.h"
+#include "TMatrixD.h"
+ #include "TDecompSVD.h"
+#include "Framework/Conventions/Constants.h"
#include "Physics/Common/PrimaryLeptonUtils.h"
#include "Framework/GHEP/GHepRecord.h"
#include "Framework/GHEP/GHepParticle.h"
#include "Framework/Messenger/Messenger.h"
#include "Framework/ParticleData/PDGUtils.h"
+#include "Framework/EventGen/EventGeneratorI.h"
+#include "Framework/EventGen/RunningThreadInfo.h"
+#include "Framework/EventGen/XSecAlgorithmI.h"
+#include "Framework/ParticleData/PDGLibrary.h"
using namespace genie;
using namespace genie::utils;
+using namespace genie::constants;
+using namespace std::complex_literals;
//___________________________________________________________________________
void genie::utils::SetPrimaryLeptonPolarization( GHepRecord * ev )
@@ -26,12 +37,6 @@ void genie::utils::SetPrimaryLeptonPolarization( GHepRecord * ev )
// accessible for generators that use a more unified approach (e.g.,
// QELEventGenerator and MECGenerator). -- S. Gardiner
-// Set the final state lepton polarization. A mass-less lepton would be fully
-// polarized. This would be exact for neutrinos and a very good approximation
-// for electrons for the energies this generator is going to be used. This is
-// not the case for muons and, mainly, for taus. I need to refine this later.
-// How? See Kuzmin, Lyubushkin and Naumov, hep-ph/0312107
-
// get the final state primary lepton
GHepParticle * fsl = ev->FinalStatePrimaryLepton();
if ( !fsl ) {
@@ -39,27 +44,255 @@ void genie::utils::SetPrimaryLeptonPolarization( GHepRecord * ev )
<< "Final state lepton not set yet! \n" << *ev;
return;
}
-
- // Get (px,py,pz) @ LAB
- TVector3 plab( fsl->Px(), fsl->Py(), fsl->Pz() );
-
- // In the limit m/E->0: leptons are left-handed and their anti-particles
- // are right-handed
- int pdgc = fsl->Pdg();
- if ( pdg::IsNeutrino(pdgc) || pdg::IsElectron(pdgc) ||
- pdg::IsMuon(pdgc) || pdg::IsTau(pdgc) )
- {
- plab *= -1; // left-handed
- }
-
+ //-- Get the interaction
+ Interaction * interaction = ev->Summary();
+ //-- Access cross section algorithm for running thread
+ RunningThreadInfo * rtinfo = RunningThreadInfo::Instance();
+ const EventGeneratorI * evg = rtinfo->RunningThread();
+ const XSecAlgorithmI * xsec_alg = evg->CrossSectionAlg();
+ fsl->SetPolarization(xsec_alg->FinalLeptonPolarization(interaction));
+
LOG("LeptonicVertex", pINFO)
<< "Setting polarization angles for particle: " << fsl->Name();
- fsl->SetPolarization( plab );
-
if ( fsl->PolzIsSet() ) {
LOG("LeptonicVertex", pINFO)
<< "Polarization (rad): Polar = " << fsl->PolzPolarAngle()
<< ", Azimuthal = " << fsl->PolzAzimuthAngle();
}
+
+}
+//___________________________________________________________________________
+void genie::utils::CalculatePolarizationVectorWithNuclearTensor(
+ TVector3 & polarization,
+ const TLorentzVector & neutrinoMom,
+ const TLorentzVector & leptonMom,
+ bool isLeftPolarized,
+ const HermitianMatrix & NTensor
+)
+{
+ double k[4], l[4], s[4], eskl[4];
+ std::complex jp[4], jm[4];
+ // k_\mu
+ k[0] = neutrinoMom.E();
+ k[1] = -neutrinoMom.Px();
+ k[2] = -neutrinoMom.Py();
+ k[3] = -neutrinoMom.Pz();
+ // l_\mu
+ l[0] = leptonMom.E();
+ l[1] = -leptonMom.Px();
+ l[2] = -leptonMom.Py();
+ l[3] = -leptonMom.Pz();
+
+ double ml = leptonMom.M();
+ // s_\mu
+ s[0] = leptonMom.P()/ml;
+ s[1] = -leptonMom.Vect().Unit().X()*leptonMom.E()/ml;
+ s[2] = -leptonMom.Vect().Unit().Y()*leptonMom.E()/ml;
+ s[3] = -leptonMom.Vect().Unit().Z()*leptonMom.E()/ml;
+
+
+
+ // epsilon_\alpha\beta\gamma\delta s^\beta k^\gamma l^\delta
+ for (int a = 0; a < 4; a++)
+ {
+ eskl[a] = 0;
+ for (int b = 0; b < 4; b++)
+ {
+ if (b == a) continue;
+ for (int g = 0; g < 4; g++)
+ {
+ if (g == b || g == a) continue;
+ for (int d = 0; d < 4; d++)
+ {
+ if (d == g || d == b || d == a) continue;
+ double sb = s[b]*genie::utils::g(b,b);
+ double kg = k[g]*genie::utils::g(g,g);
+ double ld = l[d]*genie::utils::g(d,d);
+ eskl[a] += e(a,b,g,d)*sb*kg*ld;
+ }
+ }
+ }
+ }
+
+ double kl = k[0]*l[0] - k[1]*l[1] - k[2]*l[2] - k[3]*l[3];
+ double ks = k[0]*s[0] - k[1]*s[1] - k[2]*s[2] - k[3]*s[3];
+
+ for (int a = 0; a < 4; a++)
+ {
+ double aux_plus = kl + ml*ks;
+ double aux_minus = kl - ml*ks;
+ if (isLeftPolarized)
+ {
+ jp[a] = aux_plus > 0 ? (l[a]*ks - s[a]*kl - 1i*eskl[a] + ml*k[a])/sqrt(aux_plus) : 0; //jp_\alpha
+ jm[a] = aux_minus > 0 ? (-l[a]*ks + s[a]*kl + 1i*eskl[a] + ml*k[a])/sqrt(aux_minus) : 0; //jm_\alpha
+ }
+ else
+ {
+ jp[a] = aux_minus > 0 ? (l[a]*ks - s[a]*kl + 1i*eskl[a] - ml*k[a])/sqrt(aux_minus) : 0; //jp_\alpha
+ jm[a] = aux_plus > 0 ? (l[a]*ks - s[a]*kl + 1i*eskl[a] + ml*k[a])/sqrt(aux_plus) : 0; //jm_\alpha
+ }
+ }
+
+ std::complex LWpp(0, 0), LWpm(0, 0), LWmp(0, 0), LWmm(0, 0);
+ for(int mu = 0; mu < 4; mu++)
+ {
+ for(int nu = mu;nu < 4; nu++)
+ {
+ LWpp += jp[mu]*std::conj(jp[nu])*NTensor(mu,nu); // Lpp_\mu\nu*W^\mu\nu
+ LWpm += jp[mu]*std::conj(jm[nu])*NTensor(mu,nu); // Lpm_\mu\nu*W^\mu\nu
+ LWmp += jm[mu]*std::conj(jp[nu])*NTensor(mu,nu); // Lmp_\mu\nu*W^\mu\nu
+ LWmm += jm[mu]*std::conj(jm[nu])*NTensor(mu,nu); // Lmm_\mu\nu*W^\mu\nu
+ if (mu != nu)
+ {
+ LWpp += jp[nu]*std::conj(jp[mu])*NTensor(nu,mu); // Lpp_\mu\nu*W^\mu\nu
+ LWpm += jp[nu]*std::conj(jm[mu])*NTensor(nu,mu); // Lpm_\mu\nu*W^\mu\nu
+ LWmp += jm[nu]*std::conj(jp[mu])*NTensor(nu,mu); // Lmp_\mu\nu*W^\mu\nu
+ LWmm += jm[nu]*std::conj(jm[mu])*NTensor(nu,mu); // Lmm_\mu\nu*W^\mu\nu
+ }
+ }
+ }
+
+ std::complex LWppmm = LWpp + LWmm;
+ if (LWppmm.real() == 0 && LWppmm.imag() == 0)
+ {
+ polarization = TVector3(0, 0, 0);
+ return;
+ }
+ std::complex rhopp = LWpp/LWppmm;
+ std::complex rhopm = LWpm/LWppmm;
+ std::complex rhomp = LWmp/LWppmm;
+ std::complex rhomm = LWmm/LWppmm;
+ double PL = std::real(rhopp - rhomm);
+ double PP = std::real(rhopm + rhomp);
+ double PT = std::imag(rhomp - rhopm);
+
+ TVector3 neutrinoMom3 = neutrinoMom.Vect();
+ TVector3 leptonMom3 = leptonMom.Vect();
+ TVector3 Pz = leptonMom3.Unit();
+ TVector3 Px = neutrinoMom3.Cross(leptonMom3).Unit();
+ TVector3 Py = Pz.Cross(Px);
+ polarization = PT*Px + PP*Py + PL*Pz;
+ //std::cout << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n";
+ //std::cout << "PL = " << PL << ", PP = " << PP << ", PT = " << PT << "\n";
+ //std::cout << "UT@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" << std::endl;
+}
+//____________________________________________________________________________
+void genie::utils::CalculatePolarizationVectorWithStructureFunctions(
+ TVector3 & polarization,
+ const TLorentzVector & neutrinoMom,
+ const TLorentzVector & leptonMom,
+ const TLorentzVector & inNucleonMom,
+ const TLorentzVector & q4,
+ bool isLeftPolarized,
+ double W1,
+ double W2,
+ double W3,
+ double W4,
+ double W5,
+ double W6
+)
+{
+ double M2 = inNucleonMom.M2();
+ double p[4], q[4], epq[4][4];
+ p[0] = inNucleonMom.E();
+ p[1] = inNucleonMom.Px();
+ p[2] = inNucleonMom.Py();
+ p[3] = inNucleonMom.Pz();
+
+ q[0] = q4.E();
+ q[1] = q4.Px();
+ q[2] = q4.Py();
+ q[3] = q4.Pz();
+ // epsilon^\alpha\beta\gamma\delta p_\gamma q_\delta
+ for (int a = 0; a < 4; a++)
+ {
+ for (int b = 0; b < 4; b++)
+ {
+ epq[a][b] = 0;
+ if (b == a) continue;
+ for (int g = 0; g < 4; g++)
+ {
+ if (g == b || g == a) continue;
+ for (int d = 0; d < 4; d++)
+ {
+ if (d == g || d == b || d == a) continue;
+ epq[a][b] += e(a,b,g,d)*genie::utils::g(a,a)*genie::utils::g(b,b)*p[g]*q[d];
+ }
+ }
+ }
+ }
+ HermitianMatrix NucleonTensor(4);
+ for(int mu = 0; mu < 4; mu++)
+ {
+ for(int nu = mu; nu < 4; nu++)
+ {
+ double Wreal = -g(mu,nu)*W1 + p[mu]*p[nu]*W2/M2 + q[mu]*q[nu]*W4/M2 + (p[mu]*q[nu] + q[mu]*p[nu])*W5/2/M2;
+ double Wimag = epq[mu][nu]*W3/2/M2 + (q[mu]*p[nu] - p[mu]*q[nu])*W6/2/M2;
+ NucleonTensor.set(mu, nu, Wreal - 1i*Wimag); // W^\mu\nu
+ if (mu != nu) NucleonTensor.set(nu, mu, Wreal + 1i*Wimag);
+ }
+ }
+
+ CalculatePolarizationVectorWithNuclearTensor(
+ polarization,
+ neutrinoMom,
+ leptonMom,
+ isLeftPolarized,
+ NucleonTensor);
+
}
+//____________________________________________________________________________
+void genie::utils::CalculatePolarizationVectorInTargetRestFrame(
+ TVector3 & polarization,
+ const TLorentzVector & neutrinoMomTRF,
+ const TLorentzVector & leptonMomTRF,
+ bool isLeftPolarized,
+ double M,
+ double W1,
+ double W2,
+ double W3,
+ double W4,
+ double W5,
+ double W6
+)
+{
+ double ml = leptonMomTRF.M();
+ double ml2 = ml*ml;
+ double M2 = M*M;
+ double Ev = neutrinoMomTRF.E();
+ double El = leptonMomTRF.E();
+ double Pl = leptonMomTRF.P();
+ double cost = TMath::Cos( neutrinoMomTRF.Angle(leptonMomTRF.Vect()) );
+ double sint = TMath::Sqrt(1 - cost*cost);
+ int sign = isLeftPolarized?-1:1;
+ double auxm = (El - Pl*cost)/2/M;
+ double auxp = (El + Pl*cost)/2/M;
+ double aux1m = (Pl - El*cost)/2/M;
+ double aux1p = (Pl + El*cost)/2/M;
+ double aux1 = ml2/2/M2;
+ double aux2 = (Ev + El)/M;
+ double R = 2*auxm*(W1 + aux1*W4) + auxp*W2 - sign*(aux2*auxm - aux1)*W3 - aux1*W5;
+ if (R == 0)
+ {
+ polarization = TVector3(0, 0, 0);
+ return;
+ }
+ double PL = sign*(2*aux1m*(W1 - aux1*W4) + aux1p*W2 - sign*(aux2*aux1m + aux1*cost)*W3 - aux1*cost*W5)/R;
+ double PP = sign*ml*sint*(2*W1 - W2 -sign*Ev*W3/M - ml2*W4/M2 + El*W5/M)/2/M/R;
+ double PT = - ml*Pl*sint*W6/2/M2/R;
+
+
+ TVector3 neutrinoMomTRF3 = neutrinoMomTRF.Vect();
+ TVector3 leptonMomTRF3 = leptonMomTRF.Vect();
+ TVector3 Pz = leptonMomTRF3.Unit();
+ TVector3 Px = neutrinoMomTRF3.Cross(leptonMomTRF3).Unit();
+ TVector3 Py = Pz.Cross(Px);
+ polarization = PT*Px + PP*Py + PL*Pz;
+ //std::cout << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n";
+ //std::cout << "PL = " << PL << ", PP = " << PP << ", PT = " << PT << ", R = " << R << "\n";
+ //std::cout << "UT@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" << std::endl;
+}
+//____________________________________________________________________________
+
+
diff --git a/src/Physics/Common/PrimaryLeptonUtils.h b/src/Physics/Common/PrimaryLeptonUtils.h
index bd68efcfc..723b1ff33 100644
--- a/src/Physics/Common/PrimaryLeptonUtils.h
+++ b/src/Physics/Common/PrimaryLeptonUtils.h
@@ -20,13 +20,115 @@
#ifndef _PRIMARY_LEPTON_UTILS_H
#define _PRIMARY_LEPTON_UTILS_H
+#include
+#include
+#include
+
+#include "TVector3.h"
+
namespace genie {
class GHepRecord;
namespace utils {
+ class HermitianMatrix;
void SetPrimaryLeptonPolarization( GHepRecord* ev );
+
+ void CalculatePolarizationVectorWithNuclearTensor(
+ TVector3 & polarization,
+ const TLorentzVector & neutrinoMom,
+ const TLorentzVector & leptonMom,
+ bool isLeftPolarized,
+ const HermitianMatrix & NTensor);
+
+ void CalculatePolarizationVectorWithStructureFunctions(
+ TVector3 & polarization,
+ const TLorentzVector & neutrinoMom,
+ const TLorentzVector & leptonMom,
+ const TLorentzVector & inNucleonMom,
+ const TLorentzVector & q4,
+ bool isLeftPolarized,
+ double W1,
+ double W2,
+ double W3,
+ double W4,
+ double W5,
+ double W6);
+
+ void CalculatePolarizationVectorInTargetRestFrame(
+ TVector3 & polarization,
+ const TLorentzVector & neutrinoMomTRF,
+ const TLorentzVector & leptonMomTRF,
+ bool isLeftPolarized,
+ double M,
+ double W1,
+ double W2,
+ double W3,
+ double W4,
+ double W5,
+ double W6);
+
+
+ inline int g(int a, int b) ///< metric g^{ab}=g_{ab}=diag(1,-1,-1,1)
+ {
+ return (a==b)*(2*(a==0) - 1);
+ }
+ inline int e(int a, int b, int c, int d) ///< Levi-Chevita symbol, where e_{0123}=+1
+ {
+ return (b - a)*(c - a)*(d - a)*(c - b)*(d - b)*(d - c)/12;
+ }
+
+
+ class HermitianMatrix
+ {
+ public:
+ // Constructor
+ explicit HermitianMatrix(size_t size) : n(size), data(size * (size + 1) / 2) {}
+
+ // Set an element
+ void set(size_t i, size_t j, const std::complex& value)
+ {
+ if (i >= n || j >= n)
+ {
+ throw std::out_of_range("Indices out of range.");
+ }
+ if (i == j)
+ {
+ data[index(i, j)] = std::real(value);
+ }
+ data[index(i, j)] = (i < j) ? value : std::conj(value);
+ }
+
+ // Get an element
+ std::complex get(size_t i, size_t j) const
+ {
+ if (i >= n || j >= n)
+ {
+ throw std::out_of_range("Indices out of range.");
+ }
+ return (i <= j) ? data[index(i, j)] : std::conj(data[index(j, i)]);
+ }
+
+ // Operator () for accessing elements
+ std::complex operator()(size_t i, size_t j) const
+ {
+ return get(i, j);
+ }
+
+ private:
+ size_t n; // Matrix size
+ std::vector> data; // Vector for storing elements of the upper triangular part
+
+ // Convert (i, j) indices to a single index in the 1D array
+ size_t index(size_t i, size_t j) const
+ {
+ if (i > j) std::swap(i, j); // Use only the upper triangular part
+ return i * n - i * (i + 1) / 2 + j;
+ }
+ };
+
+
} // utils namespace
} // genie namespace
diff --git a/src/Physics/Multinucleon/EventGen/MECGenerator.cxx b/src/Physics/Multinucleon/EventGen/MECGenerator.cxx
index d6d9ca9b9..2488f880a 100644
--- a/src/Physics/Multinucleon/EventGen/MECGenerator.cxx
+++ b/src/Physics/Multinucleon/EventGen/MECGenerator.cxx
@@ -92,6 +92,8 @@ void MECGenerator::ProcessEventRecord(GHepRecord * event) const
// copy of an earlier version of the `DecayNucleonCluster` method here - but, watch
// for this...
this -> DecayNucleonCluster(event);
+ // Set the final-state lepton polarization
+ utils::SetPrimaryLeptonPolarization( event );
} else if (fXSecModel->Id().Name() == "genie::SuSAv2MECPXSec") {
event->Print();
this -> SelectSuSALeptonKinematics(event);
@@ -110,7 +112,7 @@ void MECGenerator::ProcessEventRecord(GHepRecord * event) const
"ProcessEventRecord >> Cannot calculate kinematics for " <<
fXSecModel->Id().Name();
}
-
+
}
//___________________________________________________________________________
@@ -378,6 +380,8 @@ void MECGenerator::AddFinalStateLepton(GHepRecord * event) const
// Boost final state primary lepton to the lab frame
p4l.Boost(beta); // active Lorentz transform
+
+ interaction->KinePtr()->SetFSLeptonP4(p4l);
// Figure out the final-state primary lepton PDG code
int pdgc = interaction->FSPrimLepton()->PdgCode();
@@ -839,6 +843,7 @@ void MECGenerator::SelectNSVLeptonKinematics (GHepRecord * event) const
interaction->KinePtr()->Sety(gy, true);
interaction->KinePtr()->Setx(gx, true);
interaction->KinePtr()->SetW(gW, true);
+ interaction->KinePtr()->ClearRunningValues();
interaction->KinePtr()->SetFSLeptonP4(p4l);
// in later methods
// will also set the four-momentum and W^2 of the hadron system.
@@ -846,9 +851,6 @@ void MECGenerator::SelectNSVLeptonKinematics (GHepRecord * event) const
// -- Lepton
event->AddParticle( pdgc, kIStStableFinalState, momidx, -1, -1, -1, p4l, v4);
- // Set the final-state lepton polarization
- utils::SetPrimaryLeptonPolarization( event );
-
LOG("MEC",pDEBUG) << "~~~ LEPTON DONE ~~~";
}
//___________________________________________________________________________
@@ -1113,12 +1115,15 @@ void MECGenerator::SelectSuSALeptonKinematics(GHepRecord* event) const
interaction->KinePtr()->Sety(gy, true);
interaction->KinePtr()->Setx(gx, true);
interaction->KinePtr()->SetW(gW, true);
+ interaction->KinePtr()->ClearRunningValues();
interaction->KinePtr()->SetFSLeptonP4(p4l);
// in later methods
// will also set the four-momentum and W^2 of the hadron system.
// -- Lepton
event->AddParticle( pdgc, kIStStableFinalState, momidx, -1, -1, -1, p4l, v4 );
+
+ utils::SetPrimaryLeptonPolarization( event );
LOG("MEC", pDEBUG) << "~~~ LEPTON DONE ~~~";
}
@@ -1315,6 +1320,7 @@ void MECGenerator::GenerateNSVInitialHadrons(GHepRecord * event) const
event->AddParticle(p1);
+ interaction->InitStatePtr()->TgtPtr()->SetHitNucP4(p4initial_cluster);
interaction->KinePtr()->SetHadSystP4(p4final_cluster);
}
//___________________________________________________________________________
diff --git a/src/Physics/Multinucleon/XSection/NievesSimoVacasMECPXSec2016.cxx b/src/Physics/Multinucleon/XSection/NievesSimoVacasMECPXSec2016.cxx
index 7c1b2d904..5bfc0b0ba 100644
--- a/src/Physics/Multinucleon/XSection/NievesSimoVacasMECPXSec2016.cxx
+++ b/src/Physics/Multinucleon/XSection/NievesSimoVacasMECPXSec2016.cxx
@@ -21,6 +21,7 @@
#include "Physics/Multinucleon/XSection/NievesSimoVacasMECPXSec2016.h"
#include "Physics/Multinucleon/XSection/MECUtils.h"
#include "Physics/XSectionIntegration/XSecIntegratorI.h"
+#include "Physics/Common/PrimaryLeptonUtils.h"
using namespace genie;
using namespace genie::constants;
@@ -166,10 +167,10 @@ double NievesSimoVacasMECPXSec2016::XSec(
// Check that the input kinematical point is within the range
// in which hadron tensors are known (for chosen target)
- double Ev = interaction->InitState().ProbeE(kRfLab);
- double Tl = interaction->Kine().GetKV(kKVTl);
- double costl = interaction->Kine().GetKV(kKVctl);
- double ml = interaction->FSPrimLepton()->Mass();
+ //double Ev = interaction->InitState().ProbeE(kRfLab);
+ //double Tl = interaction->Kine().GetKV(kKVTl);
+ //double costl = interaction->Kine().GetKV(kKVctl);
+ //double ml = interaction->FSPrimLepton()->Mass();
double Q0 = interaction->Kine().GetKV(kKVQ0);
double Q3 = interaction->Kine().GetKV(kKVQ3);
@@ -323,16 +324,10 @@ double NievesSimoVacasMECPXSec2016::XSec(
if( fMECScaleAlg ) xsec *= fMECScaleAlg->GetScaling( * interaction ) ;
- if ( kps != kPSTlctl && kps != kPSWQ2fE ) {
- LOG("NievesSimoVacasMEC", pWARN)
- << "Doesn't support transformation from "
- << KinePhaseSpace::AsString(kPSTlctl) << " to "
- << KinePhaseSpace::AsString(kps);
- xsec = 0;
- }
- else if ( kps == kPSWQ2fE && xsec != 0. ) {
- double J = utils::kinematics::Jacobian( interaction, kPSTlctl, kps );
- xsec *= J;
+ if ( kps != kPSTlctl ) {
+ // Compute the appropriate Jacobian for transformation to the requested phase space
+ double J = utils::kinematics::Jacobian(interaction, kPSTlctl, kps);
+ xsec *= J;
}
return xsec;
@@ -376,6 +371,9 @@ void NievesSimoVacasMECPXSec2016::LoadConfig(void)
// Cross section scaling factor
GetParam( "MEC-CC-XSecScale", fXSecCCScale ) ;
GetParam( "MEC-NC-XSecScale", fXSecNCScale ) ;
+
+ // Do precise calculation of lepton polarization
+ GetParamDef( "PreciseLeptonPol", fIsPreciseLeptonPolarization, false ) ;
fHadronTensorModel = dynamic_cast ( this->SubAlg("HadronTensorAlg") );
if( !fHadronTensorModel ) {
@@ -415,3 +413,352 @@ void NievesSimoVacasMECPXSec2016::LoadConfig(void)
}
}
+//_________________________________________________________________________
+const TVector3 & NievesSimoVacasMECPXSec2016::FinalLeptonPolarization (const Interaction* interaction) const
+{
+ if (!fIsPreciseLeptonPolarization) return XSecAlgorithmI::FinalLeptonPolarization(interaction);
+
+ const Kinematics& kinematics = interaction -> Kine();
+ const InitialState& init_state = interaction -> InitState();
+ const Target& tgt = init_state.Tgt();
+
+ TLorentzVector * tempNeutrino = init_state.GetProbeP4(kRfLab);
+ TLorentzVector neutrinoMom = *tempNeutrino;
+ delete tempNeutrino;
+ const TLorentzVector leptonMom = kinematics.FSLeptonP4();
+
+ double Ev = neutrinoMom.E();
+ double El = leptonMom.E();
+ double ml = interaction->FSPrimLepton()->Mass();
+ double Tl = El - ml;
+ TVector3 neutrinoMom3 = neutrinoMom.Vect();
+ TVector3 leptonMom3 = leptonMom.Vect();
+ double pv = neutrinoMom3.Mag();
+ double pl = leptonMom3.Mag();
+ double costl = pl*pv != 0 ? neutrinoMom3.Dot(leptonMom3)/pl/pv : 0;
+ double Q0 = 0.;
+ double Q3 = 0.;
+ genie::utils::mec::Getq0q3FromTlCostl(Tl, costl, Ev, ml, Q0, Q3);
+
+ const double M = 1; // the polarization doesn't depend on mass of target in target rest frame
+ // This function returns d2sigma/(dTmu dcos_mu) in GeV^(-3)
+ int target_pdg = tgt.Pdg();
+
+ int A_request = pdg::IonPdgCodeToA(target_pdg);
+ int Z_request = pdg::IonPdgCodeToZ(target_pdg);
+
+ // To generate cross-sections for nuclei other than those with hadron
+ // tensors we need to pull both the full cross-section and
+ // the pn initial state fraction.
+ // Non-isoscalar nuclei are beyond the original published Valencia model
+ // and scale with A according to the number of pp, pn, or nn pairs
+ // the probe is expected to find.
+ // There is some by-hand optimization here, skipping the delta part when
+ // only the total cross-section is requested.
+ // Possible future models without a Delta had tensor would also use that
+ // flag to call this without computing the Delta part.
+
+ // Try to look up a hadron tensor in the pool that is an exact match for
+ // the target nucleus. If an exact match cannot be found, decide upon a
+ // suitable substitute based on the mass number A and proton number Z.
+
+ int tensor_pdg = target_pdg;
+
+ /// \todo Replace these hard-coded replacements with an equivalent XML
+ /// configuration
+ if ( ! fHadronTensorModel->GetTensor(tensor_pdg, genie::kHT_MEC_FullAll) )
+ {
+
+ if ( A_request == 4 && Z_request == 2 )
+ {
+ tensor_pdg = kPdgTgtC12;
+ // This is for helium 4, but use carbon tensor
+ // the use of nuclear density parameterization is suspicious
+ // but some users (MINERvA) need something not nothing.
+ // The pn will be exactly 1/3, but pp and nn will be ~1/4
+ // Because the combinatorics are different.
+ // Could do lithium beryllium boron which you don't need
+ }
+ else if (A_request < 9)
+ {
+ // refuse to do D, T, He3, Li, and some Be, B
+ // actually it would work technically, maybe except D, T
+ MAXLOG("NievesSimoVacasMEC", pWARN, 10)
+ << "Asked to scale to deuterium through boron "
+ << target_pdg << " nope, lets not do that.";
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+ else if (A_request >= 9 && A_request < 15)
+ {
+ tensor_pdg = kPdgTgtC12;
+ //}
+ // could explicitly put in nitrogen for air
+ //else if ( A_request >= 14 && A < 15) { // AND CHANGE <=14 to <14.
+ // tensor_pdg = kPdgTgtN14;
+ }
+ else if (A_request >= 15 && A_request < 22)
+ {
+ tensor_pdg = kPdgTgtO16;
+ }
+ else if (A_request >= 22 && A_request < 33)
+ {
+ // of special interest, this gets Al27 and Si28
+ tensor_pdg = 1000140280;
+ }
+ else if (A_request >= 33 && A_request < 50)
+ {
+ // of special interest, this gets Ar40 and Ti48
+ tensor_pdg = kPdgTgtCa40;
+ }
+ else if (A_request >= 50 && A_request < 90)
+ {
+ // pseudoFe56, also covers many other ferrometals and Ge
+ tensor_pdg = 1000280560;
+ }
+ else if (A_request >= 90 && A_request < 160)
+ {
+ // use Ba112 = PseudoCd. Row5 of Periodic table useless. Ag, Xe?
+ tensor_pdg = 1000561120;
+ }
+ else if (A_request >= 160)
+ {
+ // use Rf208 = pseudoPb
+ tensor_pdg = 1001042080;
+ }
+ else
+ {
+ MAXLOG("NievesSimoVacasMEC", pWARN, 10) << "Can't calculate final lepton polarization. Set it to zero.";
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+ }
+
+ const LabFrameHadronTensorI* tensor
+ = dynamic_cast(
+ fHadronTensorModel->GetTensor(tensor_pdg, genie::kHT_MEC_FullAll) );
+
+ // If retrieving the tensor failed, complain and return zero
+ if ( !tensor )
+ {
+ LOG("NievesSimoVacasMEC", pWARN) << "Failed to load a"
+ " hadronic tensor for the nuclide " << tensor_pdg;
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+
+ // Assume for now that the range of validity for the "FullAll" hadron
+ // tensor is the same as for the partial hadron tensors
+ /// \todo Revisit this assumption, and perhaps implement something
+ /// more robust
+ double Q0min = tensor->q0Min();
+ double Q0max = tensor->q0Max();
+ double Q3min = tensor->qMagMin();
+ double Q3max = tensor->qMagMax();
+ if (Q0 < Q0min || Q0 > Q0max || Q3 < Q3min || Q3 > Q3max)
+ {
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+
+ // Get the Q-value needed to calculate the cross sections using the
+ // hadron tensor.
+ /// \todo Shouldn't we get this from the nuclear model?
+ int nu_pdg = interaction->InitState().ProbePdg();
+ double Q_value = genie::utils::mec::Qvalue(target_pdg, nu_pdg);
+
+ // Apply Qvalue relative shift if needed:
+ if( fQvalueShifter ) Q_value += Q_value * fQvalueShifter -> Shift( interaction->InitState().Tgt() ) ;
+
+ // By default, we will compute the full cross-section. If a resonance is
+ // set, we will calculate the part of the cross-section with an internal
+ // Delta line without a final state pion (usually called PPD for pioness
+ // Delta decay). If a {p,n} hit dinucleon was set we will calculate the
+ // cross-section for that component only (either full or PDD cross-section)
+ bool delta = interaction->ExclTag().KnownResonance();
+ bool pn = (tgt.HitNucPdg() == kPdgClusterNP);
+
+ double W1_all(0), W2_all(0), W3_all(0), W4_all(0), W5_all(0);
+ double W1_pn(0), W2_pn(0), W3_pn(0), W4_pn(0), W5_pn(0);
+ double W1(0), W2(0), W3(0), W4(0), W5(0);
+
+ if ( delta )
+ {
+ const LabFrameHadronTensorI* tensor_delta_all
+ = dynamic_cast(
+ fHadronTensorModel->GetTensor(tensor_pdg, genie::kHT_MEC_DeltaAll) );
+
+ if ( !tensor_delta_all )
+ {
+ LOG("NievesSimoVacasMEC", pWARN) << "Failed to load a \"DeltaAll\""
+ << " hadronic tensor for nuclide " << tensor_pdg;
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+
+ const LabFrameHadronTensorI* tensor_delta_pn
+ = dynamic_cast(
+ fHadronTensorModel->GetTensor(tensor_pdg, genie::kHT_MEC_Deltapn) );
+
+ if ( !tensor_delta_pn )
+ {
+ LOG("NievesSimoVacasMEC", pWARN) << "Failed to load a \"Deltapn\""
+ << " hadronic tensor for nuclide " << tensor_pdg;
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+
+ W1_all = tensor_delta_all->W1(Q0 - Q_value, Q3, M);
+ W2_all = tensor_delta_all->W2(Q0 - Q_value, Q3, M);
+ W3_all = -tensor_delta_all->W3(Q0 - Q_value, Q3, M);
+ W4_all = tensor_delta_all->W4(Q0 - Q_value, Q3, M);
+ W5_all = tensor_delta_all->W5(Q0 - Q_value, Q3, M);
+ W1_pn = tensor_delta_pn->W1(Q0 - Q_value, Q3, M);
+ W2_pn = tensor_delta_pn->W2(Q0 - Q_value, Q3, M);
+ W3_pn = -tensor_delta_pn->W3(Q0 - Q_value, Q3, M);
+ W4_pn = tensor_delta_pn->W4(Q0 - Q_value, Q3, M);
+ W5_pn = tensor_delta_pn->W5(Q0 - Q_value, Q3, M);
+ }
+ else
+ {
+ const LabFrameHadronTensorI* tensor_full_all
+ = dynamic_cast(
+ fHadronTensorModel->GetTensor(tensor_pdg, genie::kHT_MEC_FullAll) );
+
+ if ( !tensor_full_all )
+ {
+ LOG("NievesSimoVacasMEC", pWARN) << "Failed to load a \"FullAll\""
+ << " hadronic tensor for nuclide " << tensor_pdg;
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+
+ const LabFrameHadronTensorI* tensor_full_pn
+ = dynamic_cast(
+ fHadronTensorModel->GetTensor(tensor_pdg, genie::kHT_MEC_Fullpn) );
+
+ if ( !tensor_full_pn )
+ {
+ LOG("NievesSimoVacasMEC", pWARN) << "Failed to load a \"Fullpn\""
+ << " hadronic tensor for nuclide " << tensor_pdg;
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+
+ W1_all = tensor_full_all->W1(Q0 - Q_value, Q3, M);
+ W2_all = tensor_full_all->W2(Q0 - Q_value, Q3, M);
+ W3_all = -tensor_full_all->W3(Q0 - Q_value, Q3, M);
+ W4_all = tensor_full_all->W4(Q0 - Q_value, Q3, M);
+ W5_all = tensor_full_all->W5(Q0 - Q_value, Q3, M);
+ W1_pn = tensor_full_pn->W1(Q0 - Q_value, Q3, M);
+ W2_pn = tensor_full_pn->W2(Q0 - Q_value, Q3, M);
+ W3_pn = -tensor_full_pn->W3(Q0 - Q_value, Q3, M);
+ W4_pn = tensor_full_pn->W4(Q0 - Q_value, Q3, M);
+ W5_pn = tensor_full_pn->W5(Q0 - Q_value, Q3, M);
+ }
+
+ // We need to scale the cross section appropriately if
+ // we are using a hadronic tensor for a nuclide that is different
+ // from the actual target
+ bool need_to_scale = (target_pdg != tensor_pdg);
+
+ // would need to trap and treat He3, T, D special here.
+ if ( need_to_scale )
+ {
+
+ double PP = Z_request;
+ double NN = A_request - PP;
+ double P = pdg::IonPdgCodeToZ(tensor_pdg);
+ double N = pdg::IonPdgCodeToA(tensor_pdg) - P;
+
+ double scale_pn = TMath::Sqrt( (PP*NN)/(P*N) );
+ double scale_pp = TMath::Sqrt( (PP * (PP - 1.)) / (P * (P - 1.)) );
+ double scale_nn = TMath::Sqrt( (NN * (NN - 1.)) / (N * (N - 1.)) );
+
+ LOG("NievesSimoVacasMEC", pDEBUG)
+ << "Scale pn pp nn for (" << target_pdg << ", " << tensor_pdg << ")"
+ << " : " << scale_pn << " " << scale_pp << " " << scale_nn;
+
+ // This is an approximation in at least three senses:
+ // 1. We are scaling from an isoscalar nucleus using p and n counting
+ // 2. We are not using the right qvalue in the had tensor
+ // 3. We are not scaling the Delta faster than the non-Delta.
+ // The guess is that these are good approximations.
+ // A test we could document is to scale from O16 to N14 or C12 using this
+ // algorithm and see how many percent deviation we see from the full
+ // calculation.
+ double temp1_all = W1_all;
+ double temp1_pn = W1_pn * scale_pn;
+ double temp2_all = W2_all;
+ double temp2_pn = W2_pn * scale_pn;
+ double temp3_all = W3_all;
+ double temp3_pn = W3_pn * scale_pn;
+ double temp4_all = W4_all;
+ double temp4_pn = W4_pn * scale_pn;
+ double temp5_all = W5_all;
+ double temp5_pn = W5_pn * scale_pn;
+ if (nu_pdg > 0)
+ {
+ // matter neutrinos
+ temp1_all = W1_pn * scale_pn + (W1_all - W1_pn) * scale_nn;
+ temp2_all = W2_pn * scale_pn + (W2_all - W2_pn) * scale_nn;
+ temp3_all = W3_pn * scale_pn + (W3_all - W3_pn) * scale_nn;
+ temp4_all = W4_pn * scale_pn + (W4_all - W4_pn) * scale_nn;
+ temp5_all = W5_pn * scale_pn + (W5_all - W5_pn) * scale_nn;
+ }
+ else
+ {
+ // antineutrinos
+ temp1_all = W1_pn * scale_pn + (W1_all - W1_pn) * scale_pp;
+ temp2_all = W2_pn * scale_pn + (W2_all - W2_pn) * scale_pp;
+ temp3_all = W3_pn * scale_pn + (W3_all - W3_pn) * scale_pp;
+ temp4_all = W4_pn * scale_pn + (W4_all - W4_pn) * scale_pp;
+ temp5_all = W5_pn * scale_pn + (W5_all - W5_pn) * scale_pp;
+ }
+
+ W1_all = temp1_all;
+ W1_pn = temp1_pn;
+ W2_all = temp2_all;
+ W2_pn = temp2_pn;
+ W3_all = temp3_all;
+ W3_pn = temp3_pn;
+ W4_all = temp4_all;
+ W4_pn = temp4_pn;
+ W5_all = temp5_all;
+ W5_pn = temp5_pn;
+ }
+
+ // Choose the right kind of cross section ("all" or "pn") to return
+ // based on whether a {p, n} dinucleon was hit
+ if (pn)
+ {
+ W1 = W1_pn;
+ W2 = W2_pn;
+ W3 = W3_pn;
+ W4 = W4_pn;
+ W5 = W5_pn;
+ }
+ else
+ {
+ W1 = W1_all;
+ W2 = W2_all;
+ W3 = W3_all;
+ W4 = W4_all;
+ W5 = W5_all;
+ }
+
+ bool is_neutrino = pdg::IsNeutrino(init_state.ProbePdg());
+ genie::utils::CalculatePolarizationVectorInTargetRestFrame(
+ fFinalLeptonPolarization,
+ neutrinoMom,
+ leptonMom,
+ is_neutrino,
+ M, W1,W2,W3,W4,W5,0);
+
+
+// std::cout << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n";
+// std::cout << fFinalLeptonPolarization.Mag() << "\n";
+// std::cout << "NVMEC@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" << std::endl;
+
+ return fFinalLeptonPolarization;
+}
diff --git a/src/Physics/Multinucleon/XSection/NievesSimoVacasMECPXSec2016.h b/src/Physics/Multinucleon/XSection/NievesSimoVacasMECPXSec2016.h
index 273126f14..9228280d3 100644
--- a/src/Physics/Multinucleon/XSection/NievesSimoVacasMECPXSec2016.h
+++ b/src/Physics/Multinucleon/XSection/NievesSimoVacasMECPXSec2016.h
@@ -49,6 +49,7 @@ class NievesSimoVacasMECPXSec2016 : public XSecAlgorithmI {
double XSec (const Interaction * i, KinePhaseSpace_t k) const;
double Integral (const Interaction * i) const;
bool ValidProcess (const Interaction * i) const;
+ const TVector3 & FinalLeptonPolarization (const Interaction* i) const;
// override the Algorithm::Configure methods to load configuration
// data to private data members
diff --git a/src/Physics/Multinucleon/XSection/SuSAv2MECPXSec.cxx b/src/Physics/Multinucleon/XSection/SuSAv2MECPXSec.cxx
index 180a4bf8a..a73c3325f 100644
--- a/src/Physics/Multinucleon/XSection/SuSAv2MECPXSec.cxx
+++ b/src/Physics/Multinucleon/XSection/SuSAv2MECPXSec.cxx
@@ -21,6 +21,7 @@
#include "Physics/XSectionIntegration/XSecIntegratorI.h"
#include "Physics/NuclearState/FermiMomentumTablePool.h"
#include "Physics/NuclearState/FermiMomentumTable.h"
+#include "Physics/Common/PrimaryLeptonUtils.h"
using namespace genie;
@@ -51,7 +52,7 @@ double SuSAv2MECPXSec::XSec(const Interaction* interaction,
int target_pdg = interaction->InitState().Tgt().Pdg();
int probe_pdg = interaction->InitState().ProbePdg();
int A_request = pdg::IonPdgCodeToA(target_pdg);
- int Z_request = pdg::IonPdgCodeToZ(target_pdg);
+// int Z_request = pdg::IonPdgCodeToZ(target_pdg);
bool need_to_scale = false;
HadronTensorType_t tensor_type = kHT_Undefined;
@@ -128,7 +129,7 @@ double SuSAv2MECPXSec::XSec(const Interaction* interaction,
// dinucleon was set we will calculate the cross-section for that
// component only
- bool pn = (interaction->InitState().Tgt().HitNucPdg() == kPdgClusterNP);
+ //bool pn = (interaction->InitState().Tgt().HitNucPdg() == kPdgClusterNP);
// Compute the cross section using the hadron tensor
double xsec = tensor->dSigma_dT_dCosTheta_rosenbluth(interaction, Delta_Q_value);
@@ -160,11 +161,9 @@ double SuSAv2MECPXSec::XSec(const Interaction* interaction,
if( fMECScaleAlg ) xsec *= fMECScaleAlg->GetScaling( * interaction ) ;
if ( kps != kPSTlctl ) {
- LOG("SuSAv2MEC", pWARN)
- << "Doesn't support transformation from "
- << KinePhaseSpace::AsString(kPSTlctl) << " to "
- << KinePhaseSpace::AsString(kps);
- xsec = 0.;
+ // Compute the appropriate Jacobian for transformation to the requested phase space
+ double J = utils::kinematics::Jacobian(interaction, kPSTlctl, kps);
+ xsec *= J;
}
return xsec;
@@ -417,6 +416,9 @@ void SuSAv2MECPXSec::LoadConfig(void)
GetParamDef("MEC-CC-XSecScale", fXSecCCScale, 1.) ;
GetParamDef("MEC-NC-XSecScale", fXSecNCScale, 1.) ;
GetParamDef("MEC-EM-XSecScale", fXSecEMScale, 1.) ;
+
+ // Do precise calculation of lepton polarization
+ GetParamDef( "PreciseLeptonPol", fIsPreciseLeptonPolarization, false ) ;
fHadronTensorModel = dynamic_cast ( this->SubAlg("HadronTensorAlg") );
if( !fHadronTensorModel ) {
@@ -473,3 +475,132 @@ void SuSAv2MECPXSec::LoadConfig(void)
}
}
+//_________________________________________________________________________
+const TVector3 & SuSAv2MECPXSec::FinalLeptonPolarization (const Interaction* interaction) const
+{
+ const ProcessInfo& proc_info = interaction->ProcInfo();
+ if ( proc_info.IsEM() )
+ {
+ LOG("SuSAv2MECPXSec", pWARN) << "For EM processes doesn't work yet. Set it to zero.";
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+ if (!fIsPreciseLeptonPolarization) return XSecAlgorithmI::FinalLeptonPolarization(interaction);
+ // Get the hadron tensor for the selected nuclide. Check the probe PDG code
+ // to know whether to use the tensor for CC neutrino scattering or for
+ // electron scattering
+ const double M = 1; // the polarization doesn't depend on mass of target in target rest frame
+ const Kinematics& kinematics = interaction -> Kine();
+ const InitialState& init_state = interaction -> InitState();
+ int probe_pdg = interaction->InitState().ProbePdg();
+
+ HadronTensorType_t tensor_type = kHT_Undefined;
+ if ( pdg::IsNeutrino(probe_pdg) || pdg::IsAntiNeutrino(probe_pdg) )
+ {
+ tensor_type = kHT_MEC_FullAll;
+ }
+ else
+ {
+ LOG("SuSAv2MECPXSec", pWARN) << "Doesn't work for processes other than weak ones. Set it to zero.";
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+ //else
+ //{
+ //tensor_type = kHT_MEC_EM;
+ //}
+
+ // Currently we only have the relative pair contributions for C12.
+ int tensor_pdg = kPdgTgtC12;
+ // The rescaling factor will be reduced. Therefore there is no need in rescaling.
+// if(tensor_pdg != target_pdg) need_to_scale = true;
+
+ // The SuSAv2-MEC hadron tensors are defined using the same conventions
+ // as the Valencia MEC model, so we can use the same sort of tensor
+ // object to describe them.
+ const LabFrameHadronTensorI* tensor
+ = dynamic_cast( fHadronTensorModel->GetTensor(tensor_pdg,
+ tensor_type) );
+
+ // If retrieving the tensor failed, complain and return zero
+ if ( !tensor )
+ {
+ LOG("SuSAv2MEC", pWARN) << "Can't calculate final lepton polarization. Set it to zero.";
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+
+ TLorentzVector * tempNeutrino = init_state.GetProbeP4(kRfLab);
+ TLorentzVector neutrinoMom = *tempNeutrino;
+ delete tempNeutrino;
+ const TLorentzVector leptonMom = kinematics.FSLeptonP4();
+
+ double Ev = neutrinoMom.E();
+ double El = leptonMom.E();
+ double ml = interaction->FSPrimLepton()->Mass();
+ double Tl = El - ml;
+ TVector3 neutrinoMom3 = neutrinoMom.Vect();
+ TVector3 leptonMom3 = leptonMom.Vect();
+ double pv = neutrinoMom3.Mag();
+ double pl = leptonMom3.Mag();
+ double costl = pl*pv != 0 ? neutrinoMom3.Dot(leptonMom3)/pl/pv : 0;
+ double Q0 = 0;
+ double Q3 = 0;
+
+ // The Q-Value essentially corrects q0 to account for nuclear
+ // binding energy in the Valencia model but this effect is already
+ // in Guille's tensors so its set it to 0.
+ // However, additional corrections may be necessary:
+ double Delta_Q_value = Qvalue( * interaction ) ;
+
+ genie::utils::mec::Getq0q3FromTlCostl(Tl, costl, Ev, ml, Q0, Q3);
+
+ double Q0min = tensor->q0Min();
+ double Q0max = tensor->q0Max();
+ double Q3min = tensor->qMagMin();
+ double Q3max = tensor->qMagMax();
+ if (Q0-Delta_Q_value < Q0min || Q0-Delta_Q_value > Q0max || Q3 < Q3min || Q3 > Q3max)
+ {
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+
+ // *** Enforce the global Q^2 cut (important for EM scattering) ***
+ // Choose the appropriate minimum Q^2 value based on the interaction
+ // mode (this is important for EM interactions since the differential
+ // cross section blows up as Q^2 --> 0)
+ double Q2min = genie::controls::kMinQ2Limit; // CC/NC limit
+ //if ( interaction->ProcInfo().IsEM() )
+ //Q2min = genie::utils::kinematics::electromagnetic::kMinQ2Limit; // EM limit
+
+ // Neglect shift due to binding energy. The cut is on the actual
+ // value of Q^2, not the effective one to use in the tensor contraction.
+ double Q2 = Q3*Q3 - Q0*Q0;
+ if ( Q2 < Q2min )
+ {
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+
+
+ double W1 = tensor->W1(Q0 - Delta_Q_value, Q3, M);
+ double W2 = tensor->W2(Q0 - Delta_Q_value, Q3, M);
+ double W3 =-tensor->W3(Q0 - Delta_Q_value, Q3, M); // note invert sign
+ double W4 = tensor->W4(Q0 - Delta_Q_value, Q3, M);
+ double W5 = tensor->W5(Q0 - Delta_Q_value, Q3, M);
+
+ bool is_neutrino = pdg::IsNeutrino(init_state.ProbePdg());
+ genie::utils::CalculatePolarizationVectorInTargetRestFrame(
+ fFinalLeptonPolarization,
+ neutrinoMom,
+ leptonMom,
+ is_neutrino,
+ M, W1,W2,W3,W4,W5,0);
+
+
+// std::cout << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n";
+// std::cout << fFinalLeptonPolarization.Mag() << "\n";
+// std::cout << "SU@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" << std::endl;
+
+ return fFinalLeptonPolarization;
+}
diff --git a/src/Physics/Multinucleon/XSection/SuSAv2MECPXSec.h b/src/Physics/Multinucleon/XSection/SuSAv2MECPXSec.h
index 9c93967fb..b425b7996 100644
--- a/src/Physics/Multinucleon/XSection/SuSAv2MECPXSec.h
+++ b/src/Physics/Multinucleon/XSection/SuSAv2MECPXSec.h
@@ -49,6 +49,8 @@ class SuSAv2MECPXSec : public XSecAlgorithmI {
double XSec(const Interaction* i, KinePhaseSpace_t k) const;
double Integral(const Interaction* i) const;
bool ValidProcess(const Interaction* i) const;
+ const TVector3 & FinalLeptonPolarization (const Interaction* i) const;
+
// override the Algorithm::Configure methods to load configuration
// data to private data members
diff --git a/src/Physics/NuclearState/NuclearUtils.cxx b/src/Physics/NuclearState/NuclearUtils.cxx
index 7f6c985cc..37ddff5be 100644
--- a/src/Physics/NuclearState/NuclearUtils.cxx
+++ b/src/Physics/NuclearState/NuclearUtils.cxx
@@ -453,9 +453,10 @@ double genie::utils::nuclear::DensityGaus(
ring = TMath::Min(ring, 0.3*a);
double aeval = a + ring;
- double norm = 1./((5.568 + alf*8.353)*TMath::Power(a,3.)); //0.0132;
- double b = TMath::Power(r/aeval, 2.);
- double dens = norm * (1. + alf*b) * TMath::Exp(-b);
+ double a3 = a*a*a;
+ double norm = 1/(5.568 + alf*8.353)/a3; //0.0132;
+ double b = TMath::Sq(r/aeval);
+ double dens = norm*(1 + alf*b)*TMath::Exp(-b);
LOG("Nuclear", pINFO)
<< "r = " << r << ", norm = " << norm << ", dens = " << dens
@@ -480,8 +481,9 @@ double genie::utils::nuclear::DensityWoodsSaxon(
ring = TMath::Min(ring, 0.75*c);
double ceval = c + ring;
- double norm = (3./(4.*kPi*TMath::Power(c,3)))*1./(1.+TMath::Power((kPi*z/c),2));
- double dens = norm / (1 + TMath::Exp((r-ceval)/z));
+ double c3 = c*c*c;
+ double norm = 3/4./kPi/c3/(1 + TMath::Sq(kPi*z/c));
+ double dens = norm/(1 + TMath::Exp((r - ceval)/z));
LOG("Nuclear", pINFO)
<< "r = " << r << ", norm = " << norm
diff --git a/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSM.cxx b/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSM.cxx
index 072f19807..db4ad196a 100644
--- a/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSM.cxx
+++ b/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSM.cxx
@@ -179,7 +179,7 @@ void QELEventGeneratorSM::ProcessEventRecord(GHepRecord * evrec) const
Range1D_t rkF = sm_utils->kFQES_SM_lim(Q2, v);
// rkF.max = Fermi momentum
- kF = rnd->RndKine().Rndm()*sm_utils->GetFermiMomentum();
+ kF = rnd->RndKine().Rndm()*sm_utils->GetInitialFermiMomentum();
if (kF < rkF.min)
{
continue;
@@ -263,6 +263,9 @@ void QELEventGeneratorSM::ProcessEventRecord(GHepRecord * evrec) const
outNucleonMom.Rotate(theta-theta_k, yvec);
outNucleonMom.Rotate(phi, zvec);
+ // One can also rotate the neutrino by an angle psi in Z frame.
+ // The angles of incoing particles will be same,
+ // The angles of outgoing particles will be fi_p - psi
outLeptonMom.Rotate(psi, unit_nudir);
inNucleonMom.Rotate(psi, unit_nudir);
outNucleonMom.Rotate(psi, unit_nudir);
@@ -286,6 +289,8 @@ void QELEventGeneratorSM::ProcessEventRecord(GHepRecord * evrec) const
kinematics::WQ2toXY(E,M,W,Q2,x,y);
// lock selected kinematics & clear running values
+ interaction->KinePtr()->SetFSLeptonP4(outLeptonMom);
+ interaction->KinePtr()->SetHadSystP4(outNucleonMom);
interaction->KinePtr()->SetQ2(Q2, true);
interaction->KinePtr()->SetW (W, true);
interaction->KinePtr()->Setx (x, true);
@@ -468,7 +473,7 @@ double QELEventGeneratorSM::ComputeMaxXSec(const Interaction * interaction) cons
const double logQ2min = TMath::Log(TMath::Max(rQ2.min, eps));
const double logQ2max = TMath::Log(TMath::Min(rQ2.max, fQ2Min));
Kinematics * kinematics = interaction->KinePtr();
- const double pFmax = sm_utils->GetFermiMomentum();
+ const double pFmax = sm_utils->GetInitialFermiMomentum();
// Now scan through kinematical variables Q2,v,kF
for (int Q2_n=0; Q2_n <= N_Q2; Q2_n++)
{
@@ -477,10 +482,11 @@ double QELEventGeneratorSM::ComputeMaxXSec(const Interaction * interaction) cons
kinematics->SetKV(kKVQ2, Q2);
Range1D_t rv = sm_utils->vQES_SM_lim(Q2);
const double logvmin = TMath::Log(TMath::Max(rv.min, eps));
- const double logvmax = TMath::Log(TMath::Max(rv.max, TMath::Max(rv.min, eps)));
+ const double logvmax = TMath::Max(TMath::Log(rv.max), logvmin);
for (int v_n=0; v_n <= N_v; v_n++)
{
// Scan around v
+ // for not heavy nucleus gives nan, but it doesn't matter for latter calculations
double v = TMath::Exp(v_n*(logvmax-logvmin)/N_v + logvmin);
kinematics->SetKV(kKVv, v);
kinematics->SetKV(kKVPn, pFmax);
@@ -552,7 +558,7 @@ double QELEventGeneratorSM::ComputeMaxXSec(const Interaction * interaction, cons
const double logQ2min = TMath::Log(fQ2Min);
const double logQ2max = TMath::Log(rQ2.max);
Kinematics * kinematics = interaction->KinePtr();
- const double pFmax = sm_utils->GetFermiMomentum();
+ const double pFmax = sm_utils->GetInitialFermiMomentum();
// Now scan through kinematical variables Q2,v,kF
for (int Q2_n=0; Q2_n <= N_Q2; Q2_n++)
{
@@ -561,10 +567,11 @@ double QELEventGeneratorSM::ComputeMaxXSec(const Interaction * interaction, cons
kinematics->SetKV(kKVQ2, Q2);
Range1D_t rv = sm_utils->vQES_SM_lim(Q2);
const double logvmin = TMath::Log(TMath::Max(rv.min, eps));
- const double logvmax = TMath::Log(TMath::Max(rv.max, TMath::Max(rv.min, eps)));
+ const double logvmax = TMath::Max(TMath::Log(rv.max), logvmin);
for (int v_n=0; v_n <= N_v; v_n++)
{
// Scan around v
+ // for not heavy nucleus gives nan, but it doesn't matter for latter calculations
double v = TMath::Exp(v_n*(logvmax-logvmin)/N_v + logvmin);
kinematics->SetKV(kKVv, v);
kinematics->SetKV(kKVPn, pFmax);
@@ -659,6 +666,9 @@ d3XSecSM_dQ2dvdkF_E::d3XSecSM_dQ2dvdkF_E(
fInteraction(i),
fpF(pF)
{
+ AlgFactory * algf = AlgFactory::Instance();
+ sm_utils = const_cast(dynamic_cast(algf->GetAlgorithm("genie::SmithMonizUtils","Default")));
+ sm_utils->SetInteraction(fInteraction);
}
d3XSecSM_dQ2dvdkF_E::~d3XSecSM_dQ2dvdkF_E()
{
@@ -672,6 +682,8 @@ double d3XSecSM_dQ2dvdkF_E::DoEval(const double * xin) const
// outputs:
// differential cross section
//
+ Range1D_t rv = sm_utils->vQES_SM_lim(xin[0]);
+ if (xin[1] < rv.min || xin[1] > rv.max) return 0;
fInteraction->KinePtr()->SetKV(kKVQ2, xin[0]);
fInteraction->KinePtr()->SetKV(kKVv, xin[1]);
fInteraction->KinePtr()->SetKV(kKVPn, fpF);
diff --git a/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSM.h b/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSM.h
index 97b23e7ae..d2a3c94f8 100644
--- a/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSM.h
+++ b/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSM.h
@@ -104,6 +104,7 @@ class d3XSecSM_dQ2dvdkF_E: public ROOT::Math::IBaseFunctionMultiDim
const XSecAlgorithmI * fModel;
const Interaction * fInteraction;
const double fpF;
+ mutable SmithMonizUtils * sm_utils;
};
//
// genie::utils::gsl::d1XSecSM_dQ2_E
diff --git a/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSuSA.cxx b/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSuSA.cxx
index 71ac4a97e..28c67119b 100644
--- a/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSuSA.cxx
+++ b/src/Physics/QuasiElastic/EventGen/QELEventGeneratorSuSA.cxx
@@ -31,6 +31,7 @@
#include "Framework/ParticleData/PDGCodes.h"
#include "Physics/QuasiElastic/EventGen/QELEventGeneratorSuSA.h"
#include "Physics/Multinucleon/XSection/MECUtils.h"
+#include "Physics/Common/PrimaryLeptonUtils.h"
#include "Physics/NuclearState/NuclearModelI.h"
#include "Framework/Numerical/MathUtils.h"
@@ -276,10 +277,14 @@ void QELEventGeneratorSuSA::SelectLeptonKinematics (GHepRecord * event) const
interaction->KinePtr()->Sety(gy, true);
interaction->KinePtr()->Setx(gx, true);
interaction->KinePtr()->SetW(gW, true);
+ interaction->KinePtr()->ClearRunningValues();
interaction->KinePtr()->SetFSLeptonP4(p4l);
// -- Lepton
event->AddParticle( pdgc, kIStStableFinalState, momidx, -1, -1, -1, p4l, v4);
+
+ // Set its polarization
+ utils::SetPrimaryLeptonPolarization( event );
LOG("QELEvent",pDEBUG) << "~~~ LEPTON DONE ~~~";
}
diff --git a/src/Physics/QuasiElastic/XSection/LinkDef.h b/src/Physics/QuasiElastic/XSection/LinkDef.h
index 85c97a998..c5e00521c 100644
--- a/src/Physics/QuasiElastic/XSection/LinkDef.h
+++ b/src/Physics/QuasiElastic/XSection/LinkDef.h
@@ -23,8 +23,7 @@
#pragma link C++ class genie::LwlynSmithFFCC;
#pragma link C++ class genie::LwlynSmithFFNC;
#pragma link C++ class genie::LwlynSmithFF;
-#pragma link C++ class genie::MKFFEM;
-#pragma link C++ class genie::MKFFCC;
+#pragma link C++ class genie::LwlynSmithIsoFFCC;
#pragma link C++ class genie::GalsterELFormFactorsModel;
#pragma link C++ class genie::LwlynSmithFFDeltaS;
#pragma link C++ class genie::AxialFormFactorModelI;
@@ -33,6 +32,7 @@
#pragma link C++ class genie::ZExpAxialFormFactorModel;
#pragma link C++ class genie::MArunAxialFormFactorModel;
#pragma link C++ class genie::NievesQELCCPXSec;
+#pragma link C++ class genie::NievesQELCCXSec;
#pragma link C++ class genie::SuSAv2QELPXSec;
#pragma link C++ class genie::SmithMonizQELCCPXSec;
#pragma link C++ class genie::SmithMonizQELCCXSec;
@@ -47,5 +47,6 @@
// Wrappers for GSL/MathMore lib
#pragma link C++ class genie::utils::gsl::d2Xsec_dQ2dv;
+#pragma link C++ class genie::utils::gsl::d3XSec_dElepdCosThetalepdR_E;
#endif
diff --git a/src/Physics/QuasiElastic/XSection/MKFFCC.cxx b/src/Physics/QuasiElastic/XSection/LwlynSmithIsoFFCC.cxx
similarity index 53%
rename from src/Physics/QuasiElastic/XSection/MKFFCC.cxx
rename to src/Physics/QuasiElastic/XSection/LwlynSmithIsoFFCC.cxx
index d637ae2ed..5af4e0c19 100644
--- a/src/Physics/QuasiElastic/XSection/MKFFCC.cxx
+++ b/src/Physics/QuasiElastic/XSection/LwlynSmithIsoFFCC.cxx
@@ -14,7 +14,7 @@ Author: Igor Kakorin , Joint Institute for Nuclear Research
//____________________________________________________________________________
#include "Framework/Conventions/Constants.h"
-#include "Physics/QuasiElastic/XSection/MKFFCC.h"
+#include "Physics/QuasiElastic/XSection/LwlynSmithIsoFFCC.h"
#include "Framework/Messenger/Messenger.h"
#include "Framework/ParticleData/PDGLibrary.h"
#include "Framework/ParticleData/PDGCodes.h"
@@ -23,44 +23,72 @@ using namespace genie;
using namespace genie::constants;
//____________________________________________________________________________
-MKFFCC::MKFFCC() :
-LwlynSmithFF("genie::MKFFCC")
+LwlynSmithIsoFFCC::LwlynSmithIsoFFCC() :
+LwlynSmithFF("genie::LwlynSmithIsoFFCC")
{
}
//____________________________________________________________________________
-MKFFCC::MKFFCC(string config) :
-LwlynSmithFF("genie::MKFFCC", config)
+LwlynSmithIsoFFCC::LwlynSmithIsoFFCC(string config) :
+LwlynSmithFF("genie::LwlynSmithIsoFFCC", config)
{
}
//____________________________________________________________________________
-MKFFCC::~MKFFCC()
+LwlynSmithIsoFFCC::~LwlynSmithIsoFFCC()
{
}
//____________________________________________________________________________
-double MKFFCC::F1V(const Interaction * interaction) const
+double LwlynSmithIsoFFCC::F1V(const Interaction * interaction) const
{
- return LwlynSmithFF::F1V(interaction);
+ if (fIsCC)
+ return LwlynSmithFF::F1V(interaction);
+
+ double F1p = this->F1P(interaction);
+ double F1n = this->F1N(interaction);
+ double _F1V = F1p + F1n;
+ return _F1V;
}
//____________________________________________________________________________
-double MKFFCC::xiF2V(const Interaction * interaction) const
+double LwlynSmithIsoFFCC::xiF2V(const Interaction * interaction) const
{
- return LwlynSmithFF::xiF2V(interaction);
+ if (fIsCC)
+ return LwlynSmithFF::xiF2V(interaction);
+
+ double F2p = this->F2P(interaction);
+ double F2n = this->F2N(interaction);
+ double _xiF2V = F2p + F2n;
+ return _xiF2V;
}
//____________________________________________________________________________
-double MKFFCC::FA(const Interaction * interaction) const
+double LwlynSmithIsoFFCC::FA(const Interaction * interaction) const
{
return LwlynSmithFF::FA(interaction);
}
//____________________________________________________________________________
-double MKFFCC::Fp(const Interaction * interaction) const
+double LwlynSmithIsoFFCC::Fp(const Interaction * interaction) const
{
- return LwlynSmithFF::Fp(interaction);
+ // get momentum transfer
+ const Kinematics & kine = interaction->Kine();
+ double q2 = kine.q2();
+
+ // get struck nucleon mass & set pion mass
+ PDGLibrary * pdglib = PDGLibrary::Instance();
+ double M = (pdglib->Find(kPdgProton)->Mass() + pdglib->Find(kPdgNeutron)->Mass())/2;
+ double M2 = M*M;
+ double Mpi = kPionMass;
+ double Mpi2 = TMath::Power(Mpi, 2);
+
+ // calculate FA
+ double fa = this->FA(interaction);
+
+ // calculate Fp
+ double _Fp = 2. * M2 * fa/(Mpi2-q2);
+ return _Fp;
}
//____________________________________________________________________________
-double MKFFCC::tau(const Interaction * interaction) const
+double LwlynSmithIsoFFCC::tau(const Interaction * interaction) const
{
// computes q^2 / (4 * Misoscalar^2)
@@ -75,6 +103,11 @@ double MKFFCC::tau(const Interaction * interaction) const
//-- calculate q^2 / (4*Mnuc^2)
return q2/(4*M*M);
}
-
+//____________________________________________________________________________
+void LwlynSmithIsoFFCC::LoadConfig(void)
+{
+ LwlynSmithFF::LoadConfig();
+ GetParamDef( "IsCCFormFactors", fIsCC, true);
+}
diff --git a/src/Physics/QuasiElastic/XSection/MKFFCC.h b/src/Physics/QuasiElastic/XSection/LwlynSmithIsoFFCC.h
similarity index 70%
rename from src/Physics/QuasiElastic/XSection/MKFFCC.h
rename to src/Physics/QuasiElastic/XSection/LwlynSmithIsoFFCC.h
index a582c32f9..b8c622859 100644
--- a/src/Physics/QuasiElastic/XSection/MKFFCC.h
+++ b/src/Physics/QuasiElastic/XSection/LwlynSmithIsoFFCC.h
@@ -1,10 +1,11 @@
//____________________________________________________________________________
/*!
-\class genie::MKFFCC
+\class genie::LwlynSmithIsoFFCC
\brief Is a concrete implementation of the QELFormFactorsModelI:
- Form Factors for MK SPP model.
+ Form Factors for Quasi Elastic CC vN scattering according to
+ Llewellyn-Smith model for isoscalar nucleon.
\author Igor Kakorin , Joint Institute for Nuclear Research \n
@@ -20,19 +21,19 @@
*/
//____________________________________________________________________________
-#ifndef _MK_CC_FORM_FACTOR_MODEL_H_
-#define _MK_CC_FORM_FACTOR_MODEL_H_
+#ifndef _LLEWELLYN_SMITH_ISO_CC_FORM_FACTOR_MODEL_H_
+#define _LLEWELLYN_SMITH_ISO_CC_FORM_FACTOR_MODEL_H_
#include "Physics/QuasiElastic/XSection/LwlynSmithFF.h"
namespace genie {
-class MKFFCC : public LwlynSmithFF {
+class LwlynSmithIsoFFCC : public LwlynSmithFF {
public:
- MKFFCC();
- MKFFCC(string config);
- virtual ~MKFFCC();
+ LwlynSmithIsoFFCC();
+ LwlynSmithIsoFFCC(string config);
+ virtual ~LwlynSmithIsoFFCC();
// QELFormFactorModelI interface implementation
double F1V (const Interaction * interaction) const;
@@ -41,6 +42,10 @@ class MKFFCC : public LwlynSmithFF {
double Fp (const Interaction * interaction) const;
double tau (const Interaction * interaction) const;
+protected:
+ virtual void LoadConfig (void);
+ bool fIsCC;
+
};
diff --git a/src/Physics/QuasiElastic/XSection/LwlynSmithQELCCPXSec.cxx b/src/Physics/QuasiElastic/XSection/LwlynSmithQELCCPXSec.cxx
index 5d743afbc..360fc37a8 100644
--- a/src/Physics/QuasiElastic/XSection/LwlynSmithQELCCPXSec.cxx
+++ b/src/Physics/QuasiElastic/XSection/LwlynSmithQELCCPXSec.cxx
@@ -32,6 +32,7 @@
#include "Framework/Utils/KineUtils.h"
#include "Physics/NuclearState/NuclearUtils.h"
#include "Physics/QuasiElastic/XSection/QELUtils.h"
+#include "Physics/Common/PrimaryLeptonUtils.h"
using namespace genie;
using namespace genie::constants;
@@ -209,7 +210,7 @@ double LwlynSmithQELCCPXSec::FullDifferentialXSec(const Interaction* interactio
double mNi = init_state.Tgt().HitNucMass();
// Hadronic matrix element for CC neutrino interactions should really use
- // the "nucleon mass," i.e., the mean of the proton and neutrino masses.
+ // the "nucleon mass," i.e., the mean of the proton and neutron masses.
// This expression would also work for NC and EM scattering (since the
// initial and final on-shell nucleon masses would be the same)
double mNucleon = ( mNi + interaction->RecoilNucleon()->Mass() ) / 2.;
@@ -260,8 +261,8 @@ double LwlynSmithQELCCPXSec::FullDifferentialXSec(const Interaction* interactio
double tau = Q2tilde / (4 * std::pow(mNucleon, 2));
double h1 = FA*FA*(1 + tau) + tau*(F1V + xiF2V)*(F1V + xiF2V);
double h2 = FA*FA + F1V*F1V + tau*xiF2V*xiF2V;
- double h3 = 2.0 * FA * (F1V + xiF2V);
- double h4 = 0.25 * xiF2V*xiF2V *(1-tau) + 0.5*F1V*xiF2V + FA*Fp - tau*Fp*Fp;
+ double h3 = 2.0 * FA * (F1V + xiF2V); // toghether with sign of FA ("-") will give correct total sign
+ double h4 = (0.25 * xiF2V*xiF2V *(1-tau) + 0.5*F1V*xiF2V + FA*Fp - tau*Fp*Fp);
bool is_neutrino = pdg::IsNeutrino(init_state.ProbePdg());
int sign = (is_neutrino) ? -1 : 1;
@@ -427,6 +428,9 @@ void LwlynSmithQELCCPXSec::LoadConfig(void)
// Cross section scaling factor
GetParam( "QEL-CC-XSecScale", fXSecCCScale ) ;
GetParam( "QEL-NC-XSecScale", fXSecNCScale ) ;
+
+ // Do precise calculation of lepton polarization
+ GetParamDef( "PreciseLeptonPol", fIsPreciseLeptonPolarization, false ) ;
double thc ;
GetParam( "CabibboAngle", thc ) ;
@@ -474,3 +478,161 @@ void LwlynSmithQELCCPXSec::LoadConfig(void)
// Decide whether or not it should be used in FullDifferentialXSec
GetParamDef( "DoPauliBlocking", fDoPauliBlocking, true );
}
+//____________________________________________________________________________
+const TVector3 & LwlynSmithQELCCPXSec::FinalLeptonPolarization (const Interaction* interaction) const
+{
+ if (!fIsPreciseLeptonPolarization) return XSecAlgorithmI::FinalLeptonPolarization(interaction);
+ const QELFormFactorsModelI* qel_ff_mod = dynamic_cast (this->SubAlg("FormFactorsAlg"));
+ const AlgId & qel_ff_mod_id = qel_ff_mod->Id();
+ std::string qel_ff_mod_name = qel_ff_mod_id.Name();
+ bool isosymmetry = true;
+ if (qel_ff_mod_name == "genie::LwlynSmithFFCC") isosymmetry = false;
+ if (qel_ff_mod_name == "genie::LwlynSmithIsoFFCC") isosymmetry = true;
+
+ // First we need access to all of the particles in the interaction
+ // The particles were stored in the lab frame
+ const Kinematics& kinematics = interaction -> Kine();
+ const InitialState& init_state = interaction -> InitState();
+ const Target& tgt = init_state.Tgt();
+
+ bool is_neutrino = pdg::IsNeutrino(init_state.ProbePdg());
+
+ // HitNucMass() looks up the PDGLibrary (on-shell) value for the initial
+ // struck nucleon
+ double Mi_onshell = tgt.HitNucMass();
+
+ // On-shell mass of final nucleon (from PDGLibrary)
+ double Mf = interaction->RecoilNucleon()->Mass();
+
+ // Isoscalar mass of nucleon
+ double Miso = (Mi_onshell + Mf)/2;
+
+ // Note that GetProbeP4 defaults to returning the probe 4-momentum in the
+ // struck nucleon rest frame, so we have to explicitly ask for the lab frame
+ // here
+ TLorentzVector * tempNeutrino = init_state.GetProbeP4(kRfLab);
+ TLorentzVector neutrinoMom = *tempNeutrino;
+ delete tempNeutrino;
+ TLorentzVector inNucleonMom(*init_state.TgtPtr()->HitNucP4Ptr());
+ TLorentzVector inNucleonMomOnShell(inNucleonMom);
+
+ const TLorentzVector leptonMom = kinematics.FSLeptonP4();
+ const TLorentzVector outNucleonMom = kinematics.HadSystP4();
+ TLorentzVector outNucleonMomOnShell(outNucleonMom);
+
+ // Apply Pauli blocking if enabled
+ if ( fDoPauliBlocking && tgt.IsNucleus() && !interaction->TestBit(kIAssumeFreeNucleon) ) {
+ int final_nucleon_pdg = interaction->RecoilNucleonPdg();
+ double kF = fPauliBlocker->GetFermiMomentum(tgt, final_nucleon_pdg, tgt.HitNucPosition());
+ double pNf = outNucleonMom.P();
+ if ( pNf < kF )
+ {
+ LOG("LwlynSmith", pWARN) << "Can't calculate final lepton polarization. Set it to zero";
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+ }
+
+ if (isosymmetry)
+ {
+ double inNucleonOnShellEnergy = TMath::Hypot(Miso, inNucleonMomOnShell.P() );
+ double outNucleonOnShellEnergy = TMath::Hypot(Miso, outNucleonMomOnShell.P() );
+ inNucleonMomOnShell.SetE(inNucleonOnShellEnergy);
+ outNucleonMomOnShell.SetE(outNucleonOnShellEnergy);
+ }
+ else
+ {
+ double inNucleonOnShellEnergy = TMath::Hypot(Mi_onshell, inNucleonMomOnShell.P() );
+ inNucleonMomOnShell.SetE(inNucleonOnShellEnergy);
+ }
+
+ // Ordinary 4-momentum transfer
+ TLorentzVector qP4 = neutrinoMom - leptonMom;
+ double Q2 = -qP4.Mag2();
+
+ // Effective 4-momentum transfer (according to the deForest prescription) for
+ // use in computing the hadronic tensor
+ TLorentzVector qTildeP4 = outNucleonMomOnShell - inNucleonMomOnShell;
+ // If the binding energy correction causes an unphysical value
+ // of q0Tilde or Q2tilde, just return 0.
+ if ( qTildeP4.E() < 0 && init_state.Tgt().IsNucleus() && !interaction->TestBit(kIAssumeFreeNucleon) )
+ {
+ LOG("LwlynSmith", pWARN) << "Can't calculate final lepton polarization. Set it to zero";
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+ double Q2tilde = -qTildeP4.Mag2();
+ if ( Q2tilde < 0 )
+ {
+ LOG("LwlynSmith", pWARN) << "Can't calculate final lepton polarization. Set it to zero";
+ fFinalLeptonPolarization = TVector3(0, 0, 0);
+ return fFinalLeptonPolarization;
+ }
+
+ // Store Q2tilde in the kinematic variable representing Q2.
+ // This will ensure that the form factors are calculated correctly
+ // using the de Forest prescription (Q2tilde instead of Q2).
+ interaction->KinePtr()->SetQ2(Q2tilde);
+
+ // Calculate the QEL form factors
+ fFormFactors.Calculate(interaction);
+
+ double FV = fFormFactors.F1V();
+ double FM = fFormFactors.xiF2V();
+ double FA = fFormFactors.FA();
+ double FP = 2*fFormFactors.Fp();
+ double FS = 2*0;
+ double FT = 0;
+ double FFV = FV*FV;
+ double FFM = FM*FM;
+ double FFT = FT*FT;
+ double FFS = FS*FS;
+ double FFVM = (FV + FM)*(FV + FM);
+ double FFAT = (FA + FT)*(FA + FT);
+ double FFMS = (FM - FS)*(FM - FS);
+ double FFTP = (FT - FP)*(FT - FP);
+
+ // Off shell mass of initial nucleon
+ double Mi = inNucleonMom.M();
+ double M = (Mi + Mf)/2;
+ double M2 = M*M;
+ double r = (Mi - Mf)/2/M;
+ double r2 = r*r;
+
+ double tau = Q2/4/M2;
+ double w01 = (1 + tau)*FFAT + tau*FFVM;
+ double w21 = FFVM;
+ double w02 = FFV + FFAT + tau*(FFM + FFT);
+ double w12 = 2*FT*(FA + FT);
+ double w22 = FFT;
+ double w03 = -2*(FV + FM )*(FA + FT);
+ double w04 = 1/4.*(FFS - FFM + 2*(FV*(FS - FM) + (FT - FP)*(FA + FT)) + tau*(FFMS + FFTP));
+ double w14 = 1/2.*((FV + FM)*(FS - FM) + (FA + FT)*(FT - FP));
+ double w24 = 1/4.*FFTP;
+ double w05 = w02 + FS*(FV - tau*FM) + FT*(FA + FT - tau*FP);
+ double w15 = w12 - FM*(FV + FM) - FP*(FA + FT);
+ double w25 = w22 - FP*FT;
+
+ // common factor 2M^2V^2 will be cancelled in the calculation of rho
+ double W1 = w01 + + w21*r2;
+ double W2 = w02 + w12*r + w22*r2;
+ double W3 = w03 ;
+ double W4 = w04 + w14*r + w24*r2;
+ double W5 = w05 + w15*r + w25*r2;
+
+ CalculatePolarizationVectorWithStructureFunctions(
+ fFinalLeptonPolarization,
+ neutrinoMom,
+ leptonMom,
+ inNucleonMom,
+ qP4,
+ is_neutrino,
+ W1,W2,W3,W4,W5,0);
+
+// std::cout << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n";
+// fFinalLeptonPolarization.Print();
+// std::cout << fFinalLeptonPolarization.Mag() << "\n";
+// std::cout << "LW@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" << std::endl;
+
+ return fFinalLeptonPolarization;
+}
diff --git a/src/Physics/QuasiElastic/XSection/LwlynSmithQELCCPXSec.h b/src/Physics/QuasiElastic/XSection/LwlynSmithQELCCPXSec.h
index 49bbb8f36..5541dffd4 100644
--- a/src/Physics/QuasiElastic/XSection/LwlynSmithQELCCPXSec.h
+++ b/src/Physics/QuasiElastic/XSection/LwlynSmithQELCCPXSec.h
@@ -23,6 +23,7 @@
#ifndef _LLEWELLYN_SMITH_QELCC_CROSS_SECTION_H_
#define _LLEWELLYN_SMITH_QELCC_CROSS_SECTION_H_
+
#include "Physics/NuclearState/NuclearModelI.h"
#include "Framework/EventGen/XSecAlgorithmI.h"
#include "Physics/QuasiElastic/XSection/QELFormFactors.h"
@@ -45,6 +46,7 @@ class LwlynSmithQELCCPXSec : public XSecAlgorithmI {
double XSec (const Interaction * i, KinePhaseSpace_t k) const;
double Integral (const Interaction * i) const;
bool ValidProcess (const Interaction * i) const;
+ const TVector3 & FinalLeptonPolarization (const Interaction* i) const;
// Override the Algorithm::Configure methods to load configuration
// data to private data members
diff --git a/src/Physics/QuasiElastic/XSection/MKFFEM.cxx b/src/Physics/QuasiElastic/XSection/MKFFEM.cxx
deleted file mode 100644
index f96749e7c..000000000
--- a/src/Physics/QuasiElastic/XSection/MKFFEM.cxx
+++ /dev/null
@@ -1,149 +0,0 @@
-//____________________________________________________________________________
-/*
- Copyright (c) 2003-2019, The GENIE Collaboration
- For the full text of the license visit http://copyright.genie-mc.org
- or see $GENIE/LICENSE
-
- Author: Igor Kakorin , Joint Institute for Nuclear Research
- based on code of Costas Andreopoulos
- University of Liverpool & STFC Rutherford Appleton Lab
-
- For the class documentation see the corresponding header file.
-
-
-*/
-//____________________________________________________________________________
-
-#include
-
-#include "Framework/Algorithm/AlgConfigPool.h"
-#include "Framework/Algorithm/AlgFactory.h"
-#include "Physics/QuasiElastic/XSection/ELFormFactors.h"
-#include "Physics/QuasiElastic/XSection/ELFormFactorsModelI.h"
-#include "Physics/QuasiElastic/XSection/MKFFEM.h"
-#include "Framework/Conventions/Constants.h"
-#include "Framework/Messenger/Messenger.h"
-#include "Framework/ParticleData/PDGLibrary.h"
-#include "Framework/ParticleData/PDGCodes.h"
-
-using namespace genie;
-using namespace genie::constants;
-
-//____________________________________________________________________________
-MKFFEM::MKFFEM() :
-QELFormFactorsModelI("genie::MKFFEM")
-{
-
-}
-//____________________________________________________________________________
-MKFFEM::MKFFEM(string config) :
-QELFormFactorsModelI("genie::MKFFEM", config)
-{
-
-}
-//____________________________________________________________________________
-MKFFEM::~MKFFEM()
-{
-
-}
-//____________________________________________________________________________
-double MKFFEM::F1P(const Interaction * interaction) const
-{
- fELFF.Calculate(interaction);
- double t = this->tau(interaction);
- double T = 1 / (1 - t);
- return T * (fELFF.Gep() - t * fELFF.Gmp());
-}
-//____________________________________________________________________________
-double MKFFEM::F2P(const Interaction * interaction) const
-{
- fELFF.Calculate(interaction);
- double t = this->tau(interaction);
- double T = 1 / (1 - t);
- return T * (fELFF.Gmp() - fELFF.Gep());
-}
-//____________________________________________________________________________
-double MKFFEM::F1N(const Interaction * interaction) const
-{
- fELFF.Calculate(interaction);
- double t = this->tau(interaction);
- double T = 1 / (1 - t);
- return T * (fELFF.Gen() - t * fELFF.Gmn());
-}
-//____________________________________________________________________________
-double MKFFEM::F2N(const Interaction * interaction) const
-{
- fELFF.Calculate(interaction);
- double t = this->tau(interaction);
- double T = 1 / (1 - t);
- return T * (fELFF.Gmn() - fELFF.Gen());
-}
-//____________________________________________________________________________
-double MKFFEM::F1V(const Interaction * interaction) const
-{
- double F1p = this->F1P(interaction);
- double F1n = this->F1N(interaction);
-
- double _F1V = F1p + F1n;
- return _F1V;
-}
-//____________________________________________________________________________
-double MKFFEM::xiF2V(const Interaction * interaction) const
-{
- double F2p = this->F2P(interaction);
- double F2n = this->F2N(interaction);
-
- double _xiF2V = F2p + F2n;
- return _xiF2V;
-}
-//____________________________________________________________________________
-double MKFFEM::FA(const Interaction * /*interaction*/ ) const
-{
- return 0.;
-}
-//____________________________________________________________________________
-double MKFFEM::Fp(const Interaction * /*interaction*/ ) const
-{
- return 0.;
-}
-//____________________________________________________________________________
-void MKFFEM::Configure(const Registry & config)
-{
- Algorithm::Configure(config);
- this->LoadConfig();
-}
-//____________________________________________________________________________
-void MKFFEM::Configure(string config)
-{
- Algorithm::Configure(config);
- this->LoadConfig();
-}
-//____________________________________________________________________________
-void MKFFEM::LoadConfig(void)
-{
-// Load configuration data from its configuration Registry (or global defaults)
-// to private data members
- fElFFModel =
- dynamic_cast (this->SubAlg("ElasticFormFactorsModel"));
- assert(fElFFModel);
- fELFF.SetModel(fElFFModel);
-
-
-}
-//____________________________________________________________________________
-double MKFFEM::tau(const Interaction * interaction) const
-{
-// computes q^2 / (4 * MNucl^2)
-
- //-- get kinematics & initial state parameters
- const Kinematics & kinematics = interaction->Kine();
- // const InitialState & init_state = interaction->InitState();
- double q2 = kinematics.q2();
-
- PDGLibrary * pdglib = PDGLibrary::Instance();
- double M = (pdglib->Find(kPdgProton)->Mass() + pdglib->Find(kPdgNeutron)->Mass())/2;
-
- //-- calculate q^2 / (4*Mnuc^2)
- return q2/(4*M*M);
-}
-//____________________________________________________________________________
diff --git a/src/Physics/QuasiElastic/XSection/MKFFEM.h b/src/Physics/QuasiElastic/XSection/MKFFEM.h
deleted file mode 100644
index 9e65d43f0..000000000
--- a/src/Physics/QuasiElastic/XSection/MKFFEM.h
+++ /dev/null
@@ -1,69 +0,0 @@
-//____________________________________________________________________________
-/*!
-
-\class genie::MKFFEM
-
-\brief Electromagnetic form factors for MK SPP model
-
-
-\author Igor Kakorin , Joint Institute for Nuclear Research \n
- based on code of
- Costas Andreopoulos
- University of Liverpool & STFC Rutherford Appleton Lab
-
-\created Nov 12, 2019
-
-\cpright Copyright (c) 2003-2019, The GENIE Collaboration
- For the full text of the license visit http://copyright.genie-mc.org
- or see $GENIE/LICENSE
-*/
-//____________________________________________________________________________
-
-#ifndef _MK_EM_FORM_FACTOR_MODEL_H_
-#define _MK_EM_FORM_FACTOR_MODEL_H_
-
-#include "Physics/QuasiElastic/XSection/QELFormFactorsModelI.h"
-#include "Physics/QuasiElastic/XSection/ELFormFactors.h"
-
-namespace genie {
-
-class ELFormFactorsModelI;
-
-class MKFFEM : public QELFormFactorsModelI {
-
-public:
- MKFFEM();
- MKFFEM(string name);
- ~MKFFEM();
-
- double F1V (const Interaction * interaction) const;
- double xiF2V (const Interaction * interaction) const;
- double FA (const Interaction * interaction) const;
- double Fp (const Interaction * interaction) const;
-
- // Overload the Algorithm::Configure() methods to load private data
- // members from configuration options
- void Configure(const Registry & config);
- void Configure(string config);
-
-private:
-
- void LoadConfig (void);
-
- double tau (const Interaction * interaction) const;
-
- double F1P (const Interaction * interaction) const;
- double F2P (const Interaction * interaction) const;
- double F1N (const Interaction * interaction) const;
- double F2N (const Interaction * interaction) const;
-
- const ELFormFactorsModelI * fElFFModel;
-
- mutable ELFormFactors fELFF;
-
-};
-
-} // genie namespace
-
-#endif
-
diff --git a/src/Physics/QuasiElastic/XSection/NievesQELCCPXSec.cxx b/src/Physics/QuasiElastic/XSection/NievesQELCCPXSec.cxx
index afe33592f..503526ebe 100644
--- a/src/Physics/QuasiElastic/XSection/NievesQELCCPXSec.cxx
+++ b/src/Physics/QuasiElastic/XSection/NievesQELCCPXSec.cxx
@@ -13,7 +13,6 @@
#include
#include