6 #include "art/Framework/Core/EDProducer.h"
7 #include "art/Framework/Principal/Event.h"
8 #include "art/Framework/Principal/Handle.h"
9 #include "art/Framework/Services/Registry/ServiceHandle.h"
10 #include "art/Persistency/Common/PtrMaker.h"
11 #include "art/Utilities/ToolMacros.h"
12 #include "cetlib/cpu_timer.h"
13 #include "fhiclcpp/ParameterSet.h"
14 #include "messagefacility/MessageLogger/MessageLogger.h"
24 #include "CLHEP/Random/RandomEngine.h"
25 #include "CLHEP/Random/JamesRandom.h"
26 #include "CLHEP/Random/RandFlat.h"
27 #include "nusimdata/SimulationBase/MCParticle.h"
37 #include <gsl/gsl_integration.h>
40 #include "TDatabasePDG.h"
67 void configure(fhicl::ParameterSet
const &pset)
override;
99 std::vector<TLorentzVector>
mom;
122 double I1(
double x,
double y,
double z);
123 double I2(
double x,
double y,
double z);
124 double NuDiLepDecayWidth(
double hnl_mass,
double ue4,
double um4,
bool nu_is_muon,
bool lep_is_muon);
135 return a*a + b*b + c*c - 2*a*b - 2*b*c - 2*c*
a;
142 double sumofdaughtermass = childA_mass + childB_mass + childC_mass;
143 if (parent_mass < sumofdaughtermass) {
147 double E_A, E_B, E_C;
148 double P_A, P_B, P_C;
157 E_A = childA_mass + (parent_mass - sumofdaughtermass) * std::min(r1, r2);
158 E_B = childB_mass + (parent_mass - sumofdaughtermass) * std::min(1-r1,1-r2);
159 E_C = childC_mass + (parent_mass - sumofdaughtermass) *
abs(r1-r2);
161 P_A = sqrt(E_A*E_A - childA_mass*childA_mass);
162 P_B = sqrt(E_B*E_B - childB_mass*childB_mass);
163 P_C = sqrt(E_C*E_C - childC_mass*childC_mass);
165 P_max = std::max(std::max(P_A,P_B),P_C);
166 P_sum = P_A + P_B + P_C;
168 }
while(P_max > P_sum - P_max);
177 double cos_thAB = (P_C*P_C - P_B*P_B - P_A*P_A) / (2. * P_A * P_B);
178 double sin_thAB = sqrt(1. - cos_thAB * cos_thAB);
179 double cos_thAC = (P_B*P_B - P_C*P_C - P_A*P_A) / (2. * P_A * P_C);
180 double sin_thAC = sqrt(1. - cos_thAC * cos_thAC);
183 double gammaB = (2*
GetRandom() - 1.) * M_PI;
184 double gammaC = -gammaB;
187 sin_thAB*cos(gammaB)*dirA.CosTheta()*sin(dirA.Phi()) - sin_thAB*sin(gammaB)*sin(dirA.Phi()) + cos_thAB*sqrt(1.-dirA.CosTheta()*dirA.CosTheta()) * cos(dirA.Phi()),
188 sin_thAB*cos(gammaB)*dirA.CosTheta()*cos(dirA.Phi()) - sin_thAB*sin(gammaB)*cos(dirA.Phi()) + cos_thAB*sqrt(1.-dirA.CosTheta()*dirA.CosTheta()) * sin(dirA.Phi()),
189 -sin_thAB*cos(gammaB)*sqrt(1. - dirA.CosTheta() * dirA.CosTheta()) + cos_thAB*dirA.CosTheta());
192 sin_thAC*cos(gammaC)*dirA.CosTheta()*sin(dirA.Phi()) - sin_thAC*sin(gammaC)*sin(dirA.Phi()) + cos_thAC*sqrt(1.-dirA.CosTheta()*dirA.CosTheta()) * cos(dirA.Phi()),
193 sin_thAC*cos(gammaC)*dirA.CosTheta()*cos(dirA.Phi()) - sin_thAC*sin(gammaC)*cos(dirA.Phi()) + cos_thAC*sqrt(1.-dirA.CosTheta()*dirA.CosTheta()) * sin(dirA.Phi()),
194 -sin_thAC*cos(gammaC)*sqrt(1. - dirA.CosTheta() * dirA.CosTheta()) + cos_thAC*dirA.CosTheta());
196 ret.
A = TLorentzVector(P_A*dirA, E_A);
197 ret.
B = TLorentzVector(P_B*dirB, E_B);
198 ret.
C = TLorentzVector(P_C*dirC, E_C);
204 double *xyz = (
double *)param;
209 return 12.*(s - x*x - y*
y)*(1 + z*z - s)*sqrt(
lambda(s,x*x,y*y))*sqrt(
lambda(1.,s,z*z))/
s;
213 double *xyz = (
double *)param;
218 return 24*y*z*(1. + x*x -
s)*sqrt(
lambda(s,y*y,z*z))*sqrt(
lambda(1.,s,z*z))/s;
230 double result,
error;
245 double result,
error;
253 double hnl_mass_pow5 = hnl_mass*hnl_mass*hnl_mass*hnl_mass*hnl_mass;
254 double u4 = nu_is_muon ? um4 : ue4;
261 if (hnl_mass < lep_mass * 2.)
return 0.;
263 int CC = (lep_is_muon == nu_is_muon);
265 double I1val =
I1(0., lep_mass / hnl_mass, lep_mass / hnl_mass);
266 double I2val =
I2(0., lep_mass / hnl_mass, lep_mass / hnl_mass);
268 double width = (Gfermi*Gfermi*hnl_mass_pow5) * u4 * ((gL*gR + CC*gR)*I1val + (gL*gL+gR*gR+CC*(1+2.*gL))*I2val);
279 if (2*muon_mass > flux.
mass) {
284 double ue4 = flux.
C1;
285 double um4 = flux.
C2;
289 ret.
width = nue_width + numu_width;
291 if (ret.
width == 0.)
return ret;
304 nu_pdg_sign = (
GetRandom() > 0.5) ? 1:-1;
310 int nu_pdg = nu_pdg_sign * ((
GetRandom() > numu_width / (numu_width + nue_width)) ? 14 : 12);
311 ret.
pdg.push_back(nu_pdg);
312 ret.
mom.push_back(momenta.
A);
314 ret.
pdg.push_back(13);
315 ret.
mom.push_back(momenta.
B);
316 ret.
pdg.push_back(-13);
317 ret.
mom.push_back(momenta.
C);
325 int lep_pdg = is_muon ? 13 : 11;
333 if (lep_mass + piplus_mass > flux.
mass) {
338 double u4 = is_muon ? flux.
C2 : flux.
C1;
339 double lep_ratio = (lep_mass * lep_mass) / (flux.
mass * flux.
mass);
340 double pion_ratio = (piplus_mass * piplus_mass) / (flux.
mass * flux.
mass);
341 double Ifunc = ((1 + lep_ratio + pion_ratio)*(1.+lep_ratio) - 4*lep_ratio) * sqrt(
lambda(1., lep_ratio, pion_ratio));
342 ret.
width = u4 * (Gfermi * Gfermi *fpion * fpion * abs_Vud_squared * flux.
mass * flux.
mass * flux.
mass * Ifunc) / (16 * M_PI);
350 lep_pdg_sign = (
GetRandom() > 0.5) ? 1 : -1;
361 double this_dalitz = 0.;
367 LB = TLorentzVector(p*dir, sqrt(p*p + lep_mass*lep_mass));
368 PI = TLorentzVector(-p*dir, sqrt(p*p + piplus_mass*piplus_mass));
369 LB.Boost(flux.
mom.BoostVector());
370 PI.Boost(flux.
mom.BoostVector());
372 this_dalitz = ((flux.
secondary_pdg > 0 ) != (lep_pdg_sign > 0)) ? \
376 assert(this_dalitz < dalitz_max);
377 if (this_dalitz > dalitz_max) {
378 std::cerr <<
"VERY VERY BAD!!!! Incorrect dalitz max!!!\n";
379 std::cout <<
"VERY VERY BAD!!!! Incorrect dalitz max!!!\n";
380 std::cout <<
"PK: " << flux.
kmom.E() <<
" " << flux.
kmom.Px() <<
" " << flux.
kmom.Py() <<
" " << flux.
kmom.Pz() << std::endl;
381 std::cout <<
"PA: " << flux.
sec.E() <<
" " << flux.
sec.Px() <<
" " << flux.
sec.Py() <<
" " << flux.
sec.Pz() << std::endl;
382 std::cout <<
"PN: " << flux.
mom.E() <<
" " << flux.
mom.Px() <<
" " << flux.
mom.Py() <<
" " << flux.
mom.Pz() << std::endl;
383 std::cout <<
"PP: " << PI.E() <<
" " << PI.Px() <<
" " << PI.Py() <<
" " << PI.Pz() << std::endl;
384 std::cout <<
"PB: " << LB.E() <<
" " << LB.Px() <<
" " << LB.Py() <<
" " << LB.Pz() << std::endl;
386 std::cout <<
"This Dalitz: " << this_dalitz << std::endl;
387 std::cout <<
"Max Dalitz: " << dalitz_max << std::endl;
392 }
while (
GetRandom() > this_dalitz / dalitz_max);
395 ret.
mom.push_back(LB);
396 ret.
pdg.push_back(lep_pdg*lep_pdg_sign);
399 ret.
mom.emplace_back(PI);
400 ret.
pdg.push_back(211*lep_pdg_sign);
413 double E = sqrt(P*P + hnl_mass * hnl_mass);
420 hnl.
mom = TLorentzVector(P * TVector3(1, 0, 0), E);
426 hnl.
sec = TLorentzVector(-P * TVector3(1, 0, 0), sqrt(P*P + lep_mass*lep_mass));
430 width += ((*this.*
F)(hnl)).width;
445 double P = sqrt(E*E - hnl_mass * hnl_mass);
450 double e0 = sqrt(p0*p0 + hnl_mass*hnl_mass);
451 double beta = (-e0*p0 + E*P) / (E*E + p0*p0);
452 TVector3 boost(beta, 0, 0);
459 hnl.
mom = TLorentzVector(p0 * TVector3(1, 0, 0), e0);
460 hnl.
mom.Boost(boost);
463 std::cout <<
"Reference Energy: " << E << std::endl;
464 std::cout <<
"HNL 4P: " << hnl.
mom.E() <<
" " << hnl.
mom.Px() << std::endl;
469 hnl.
kmom.Boost(boost);
470 hnl.
sec = TLorentzVector(-p0 * TVector3(1, 0, 0), sqrt(p0*p0 + lep_mass*lep_mass));
471 hnl.
sec.Boost(boost);
475 width += ((*this.*
F)(hnl)).width;
478 std::cout <<
"REFERENCE WIDTH: " << width << std::endl;
483 std::cout <<
"REFERENCE DECAY LENGTH: " << mean_dist << std::endl;
485 return length / mean_dist;
518 fDecayConfig = pset.get<std::vector<std::string>>(
"Decays");
525 std::cerr <<
"ERROR: Selected unavailable decay (" << d <<
")" << std::endl;
535 if (fReferenceHNLEnergy < 0. && fReferenceHNLKaonEnergy > 0.) {
549 throw cet::exception(
"HNLMakeDecay Tool: BAD CONFIG. Existing configuration results in a KDAR-flux partial decay length (" +
556 bool has_allowed_decay =
false;
559 has_allowed_decay =
true;
564 if (!has_allowed_decay) {
565 throw cet::exception(
"HNLMakeDecay Tool: BAD MASS. Configured mass (" +
std::to_string(flux.
mass) +
566 ") is smaller than any configured decay.");
570 std::vector<HNLMakeDecay::DecayFinalState> decays;
571 double total_width = 0.;
573 decays.push_back((*this.*
F)(flux));
574 total_width += decays.back().width;
577 std::cout <<
"TOTAL DECAY WIDTH: " << total_width << std::endl;
578 if (total_width == 0.)
return false;
581 double sum_width = 0.;
582 int idecay = decays.size()-1;
584 for (
unsigned i = 0; i < decays.size()-1; i++) {
585 sum_width += decays[i].width;
586 if (rand < sum_width / total_width) {
593 TVector3 decay_pos = in +
GetRandom() * (out -
in);
606 std::cerr <<
"ERROR: bad mean_dist value (" << mean_dist <<
"). Decay weighting approximations invalid. Ignoring event." << std::endl;
607 std::cout <<
"ERROR: bad mean_dist value (" << mean_dist <<
"). Decay weighting approximations invalid. Ignoring event." << std::endl;
612 weight = (out -
in).Mag() / mean_dist;
616 for (
const TLorentzVector &
p: decays[idecay].mom) {
double fMinDetectorDistance
process_name opflash particleana ie ie ie z
double fReferenceRayLength
double CalculateMaxWeight()
process_name opflash particleana ie x
BEGIN_PROLOG could also be cerr
std::map< std::string, double > fAvailableDecayMasses
ThreebodyMomentum isotropic_threebody_momentum(double parent_mass, double childA_mass, double childB_mass, double childC_mass)
double lambda(double a, double b, double c)
DecayFinalState EPi(const MeVPrtlFlux &flux)
double NuDiLepDecayWidth(double hnl_mass, double ue4, double um4, bool nu_is_muon, bool lep_is_muon)
void configure(fhicl::ParameterSet const &pset) override
Interface for configuring the particular algorithm tool.
HNLMakeDecay class definiton.
double twobody_momentum(double parent_mass, double childA_mass, double childB_mass)
DecayFinalState LepPi(const MeVPrtlFlux &flux, bool is_muon)
gsl_integration_workspace * fIntegrator
std::vector< HNLDecayFunction > fSelectedDecays
std::map< std::string, HNLDecayFunction > fAvailableDecays
IMeVPrtlDecay interface class definiton.
process_name opflash particleana ie ie y
IMeVPrtlStage interface class definiton. General interface behind each stage. Provides random number ...
double I1_integrand(double s, void *param)
double HNLLepPiLNVDalitz(TLorentzVector K, TLorentzVector LA, TLorentzVector N, TLorentzVector PI, TLorentzVector LB)
Provides a base class aware of world box coordinates.
DecayFinalState(HNLMakeDecay::* HNLDecayFunction)(const MeVPrtlFlux &flux)
HNLMakeDecay(fhicl::ParameterSet const &pset)
Constructor.
static const Constants & Instance()
std::vector< TVector3 > daughter_mom
std::vector< TLorentzVector > mom
std::vector< double > daughter_e
process_name showerreco Particles Coinciding wih the Vertex services ScanOptions nu_mu CC
double I2(double x, double y, double z)
if &&[-z"$BASH_VERSION"] then echo Attempting to switch to bash bash shellSwitch exit fi &&["$1"= 'shellSwitch'] shift declare a IncludeDirectives for Dir in
double I1(double x, double y, double z)
double I2_integrand(double s, void *param)
std::vector< std::string > fDecayConfig
std::string to_string(WindowPattern const &pattern)
then echo File list $list not found else cat $list while read file do echo $file sed s
DecayFinalState NuMupMum(const MeVPrtlFlux &flux)
std::vector< int > daughter_pdg
double HNLLepPiDalitzMax(double mK, double mA, double mN, double mP, double mB)
double CalculateKDARDecayLength()
double forwardPrtlEnergy(double parentM, double secM, double prtlM, double parentE)
double fReferenceHNLEnergy
double MaxWeight() override
TVector3 RandomUnitVector()
double TimeOfFlight(const MeVPrtlFlux &flux, TVector3 decay)
DecayFinalState MuPi(const MeVPrtlFlux &flux)
BEGIN_PROLOG could also be cout
~HNLMakeDecay()
Destructor.
This is an interface for an art Tool which decays "Prtl" inside a detector volume. It maps MeVPrtlFlux to MeVPrtlDecay.
double HNLLepPiLNCDalitz(TLorentzVector K, TLorentzVector LA, TLorentzVector N, TLorentzVector PI, TLorentzVector LB)
double fReferenceHNLKaonEnergy
bool Decay(const MeVPrtlFlux &flux, const TVector3 &in, const TVector3 &out, MeVPrtlDecay &decay, double &weight) override