All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HiggsMakeDecay_tool.cc
Go to the documentation of this file.
1 /**
2  *
3  */
4 
5 // Framework Includes
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"
15 
16 // local includes
19 
21 
22 // LArSoft includes
24 #include "CLHEP/Random/RandomEngine.h"
25 #include "CLHEP/Random/JamesRandom.h"
26 #include "CLHEP/Random/RandFlat.h"
27 #include "nusimdata/SimulationBase/MCParticle.h"
28 
29 // std includes
30 #include <string>
31 #include <iostream>
32 #include <memory>
33 #include <utility>
34 
35 // constants
36 #include "TDatabasePDG.h"
37 
38 //------------------------------------------------------------------------------------------------------------------------------------------
39 // implementation follows
40 
41 namespace evgen {
42 namespace ldm {
43 /**
44  * @brief HiggsMakeDecay class definiton
45  *
46  * Implementation of model taken from:
47  * https://arxiv.org/abs/1909.11670
48  */
49 class HiggsMakeDecay : public IMeVPrtlDecay {
50 public:
51  /**
52  * @brief Constructor
53  */
54  HiggsMakeDecay(fhicl::ParameterSet const &pset);
55 
56  /**
57  * @brief Destructor
58  */
60 
61  void configure(fhicl::ParameterSet const &pset) override;
62 
63  bool Decay(const MeVPrtlFlux &flux, const TVector3 &in, const TVector3 &out, MeVPrtlDecay &decay, double &weight) override;
64  int RandDaughter(double elec_width, double muon_width, double piplus_width, double pizero_width);
65 
66  // returns the max weight of configured
67  double MaxWeight() override {
68  return fMaxWeight;
69  }
70 
71 private:
78 
79  double fMaxWeight;
80 
85 
86 };
87 
88 // converts a random number (x) between 0 and 1 to a number
89 // from an exponential distribution with mean forced to lie
90 // between a and b
91 double flat_to_exp_rand(double x, double mean, double a, double b) {
92  double A = (1. - exp(-(b-a)/mean));
93  return - mean * log(1 - x * A) + a;
94 }
95 
96 // returns the weight associated with forcing the decay to happen within a center length
97 double forcedecay_weight(double mean, double a, double b) {
98  return exp(-a/mean) - exp(-b/mean);
99 }
100 
101 double higgs_momentum(double kaon_mass, double pion_mass, double higs_mass) {
102  return sqrt(kaon_mass * kaon_mass * kaon_mass * kaon_mass
103  -2 * kaon_mass * kaon_mass * pion_mass * pion_mass
104  -2 * kaon_mass * kaon_mass * higs_mass * higs_mass
105  + pion_mass * pion_mass * pion_mass * pion_mass
106  + higs_mass * higs_mass * higs_mass * higs_mass
107  -2 * pion_mass * pion_mass * higs_mass * higs_mass) / ( 2 * kaon_mass );
108 }
109 
110 
111 // Get the partial width for lepton decays
112 double LeptonPartialWidth(double lep_mass, double higs_mass, double mixing) {
113  if (lep_mass * 2 >= higs_mass) return 0.;
114 
115  double higgs_vev = Constants::Instance().higgs_vev;
116 
117  double width = (mixing * mixing * lep_mass * lep_mass * higs_mass / (8 * M_PI * higgs_vev * higgs_vev)) * pow(1 - 4 * lep_mass * lep_mass / (higs_mass * higs_mass), 3. / 2.);
118  return width;
119 }
120 
121 double ElectronPartialWidth(double higs_mass, double mixing) {
122  return LeptonPartialWidth(Constants::Instance().elec_mass, higs_mass, mixing);
123 }
124 
125 double MuonPartialWidth(double higs_mass, double mixing) {
126  return LeptonPartialWidth(Constants::Instance().muon_mass, higs_mass, mixing);
127 }
128 
129 double PionPartialWidth(double pion_mass, double higs_mass, double mixing) {
130  if (pion_mass * 2 >= higs_mass) return 0.;
131 
132  double higgs_vev = Constants::Instance().higgs_vev;
133 
134  double form_factor = (2. / 9.) * higs_mass * higs_mass + (11. / 9.) * pion_mass * pion_mass;
135 
136  double width = (mixing * mixing * 3 * form_factor * form_factor / (32 * M_PI * higgs_vev * higgs_vev * higs_mass)) * pow(1- 4. * pion_mass * pion_mass / (higs_mass * higs_mass), 1. / 2.);
137 
138  return width;
139 }
140 
141 double PiPlusPartialWidth(double higs_mass, double mixing) {
142  return PionPartialWidth(Constants::Instance().piplus_mass, higs_mass, mixing);
143 }
144 
145 double PiZeroPartialWidth(double higs_mass, double mixing) {
146  return PionPartialWidth(Constants::Instance().pizero_mass, higs_mass, mixing);
147 }
148 
149 HiggsMakeDecay::HiggsMakeDecay(fhicl::ParameterSet const &pset):
150  IMeVPrtlStage("HiggsMakeDecay")
151 {
152  this->configure(pset);
153 }
154 
155 //------------------------------------------------------------------------------------------------------------------------------------------
156 
158 {
159 }
160 
161 //------------------------------------------------------------------------------------------------------------------------------------------
162 void HiggsMakeDecay::configure(fhicl::ParameterSet const &pset)
163 {
164  fReferenceRayLength = pset.get<double>("ReferenceRayLength", -1);
165  fReferenceRayDistance = pset.get<double>("ReferenceRayDistance", 0.);
166  fReferenceHiggsMass = pset.get<double>("ReferenceHiggsMass", -1);
167  fReferenceHiggsMixing = pset.get<double>("ReferenceHiggsMixing", -1);
168  fReferenceHiggsEnergy = pset.get<double>("ReferenceHiggsEnergy", -1);
169  fReferenceHiggsKaonEnergy = pset.get<double>("ReferenceHiggsEnergyFromKaonEnergy", -1.);
170 
171  fAllowElectronDecay = pset.get<bool>("AllowElectronDecay", true);
172  fAllowMuonDecay = pset.get<bool>("AllowMuonDecay", true);
173  fAllowPionDecay = pset.get<bool>("AllowPionDecay", true);
174  fAllowPi0Decay = pset.get<bool>("AllowPi0Decay", true);
175 
176  if (fReferenceHiggsEnergy < 0. && fReferenceHiggsKaonEnergy > 0.) {
177  fReferenceHiggsEnergy = std::min(forwardPrtlEnergy(Constants::Instance().kplus_mass, Constants::Instance().piplus_mass, fReferenceHiggsMass, fReferenceHiggsKaonEnergy),
178  forwardPrtlEnergy(Constants::Instance().klong_mass, Constants::Instance().pizero_mass, fReferenceHiggsMass, fReferenceHiggsKaonEnergy));
179  }
180 
181  // if configured to, divide out some of the decay weight
182  if (fReferenceRayLength > 0. && fReferenceHiggsMass > 0. && fReferenceHiggsMixing > 0. && fReferenceHiggsEnergy > 0.) {
183  // Get each partial width
184  double width_elec = ElectronPartialWidth(fReferenceHiggsMass, fReferenceHiggsMixing);
185  double width_muon = MuonPartialWidth(fReferenceHiggsMass, fReferenceHiggsMixing);
186  double width_piplus = PiPlusPartialWidth(fReferenceHiggsMass, fReferenceHiggsMixing);
187  double width_pizero = PiZeroPartialWidth(fReferenceHiggsMass, fReferenceHiggsMixing);
188 
189  // total lifetime
190  double lifetime_ns = Constants::Instance().hbar / (width_elec + width_muon + width_piplus + width_pizero);
191 
192  // multiply by gamma*v to get the length
193  double gamma_v = sqrt(fReferenceHiggsEnergy * fReferenceHiggsEnergy - fReferenceHiggsMass * fReferenceHiggsMass) * Constants::Instance().c_cm_per_ns / fReferenceHiggsMass;
194  double mean_dist = lifetime_ns * gamma_v;
195 
196  // compute the decay weight
197  fMaxWeight = forcedecay_weight(mean_dist, fReferenceRayDistance, fReferenceRayDistance + fReferenceRayLength);
198 
199  // Scale by the allowed BR
200  fMaxWeight *= (width_elec*fAllowElectronDecay + width_muon*fAllowMuonDecay + width_piplus*fAllowPionDecay + width_pizero*fAllowPi0Decay) / (width_elec + width_muon + width_piplus + width_pizero);
201 
202  }
203  else {
204  fMaxWeight = -1.;
205  }
206 }
207 
208 int HiggsMakeDecay::RandDaughter(double elec_width, double muon_width, double piplus_width, double pizero_width) {
209  double total_width = elec_width + muon_width + piplus_width + pizero_width;
210 
211  double flat_rand = CLHEP::RandFlat::shoot(fEngine, 0, 1.);
212 
213  if (flat_rand < elec_width / total_width) {
214  return 11;
215  }
216  else if (flat_rand < (elec_width + muon_width) / total_width) {
217  return 13;
218  }
219  else if (flat_rand < (elec_width + muon_width + piplus_width) / total_width) {
220  return 211;
221  }
222  else {
223  return 111;
224  }
225 
226  // unreachable
227  return -1;
228 }
229 
230 bool HiggsMakeDecay::Decay(const MeVPrtlFlux &flux, const TVector3 &in, const TVector3 &out, MeVPrtlDecay &decay, double &weight) {
231  // Handle bad mass value
232  if (flux.mass < 2*Constants::Instance().elec_mass) {
233  throw cet::exception("HiggsMakeDecay Tool: BAD MASS. Configured mass (" + std::to_string(flux.mass) +
234  ") is smaller than lowest mass available decay e+e- (" + std::to_string(2*Constants::Instance().elec_mass) +")");
235  }
236 
237  double mixing = flux.C1; // constant-1 saves the mixing
238 
239  // Get each partial width
240  double width_elec = ElectronPartialWidth(flux.mass, mixing);
241  double width_muon = MuonPartialWidth(flux.mass, mixing);
242  double width_piplus = PiPlusPartialWidth(flux.mass, mixing);
243  double width_pizero = PiZeroPartialWidth(flux.mass, mixing);
244 
245  // total lifetime
246  double lifetime_ns = Constants::Instance().hbar / (width_elec + width_muon + width_piplus + width_pizero);
247 
248  // multiply by gamma*v to get the length
249  double mean_dist = lifetime_ns * flux.mom.Gamma() * flux.mom.Beta() * Constants::Instance().c_cm_per_ns;
250 
251  // distance inside detector
252  double in_dist = (flux.pos.Vect() - in).Mag();
253  double out_dist = (flux.pos.Vect() - out).Mag();
254 
255  // compute the decay weight
256  weight = forcedecay_weight(mean_dist, in_dist, out_dist);
257 
258  // if the weight is literally zero, then there is no way in hell
259  // that this higgs is going to decay in the detector -- reject it
260  if (weight == 0) {
261  return false;
262  }
263 
264  // Scale by the allowed BR
265  weight *= (width_elec*fAllowElectronDecay + width_muon*fAllowMuonDecay + width_piplus*fAllowPionDecay + width_pizero*fAllowPi0Decay) / (width_elec + width_muon + width_piplus + width_pizero);
266 
267  // get the decay location
268  double flat_rand = CLHEP::RandFlat::shoot(fEngine, 0, 1.);
269  double decay_rand = flat_to_exp_rand(flat_rand, mean_dist, in_dist, out_dist);
270  TVector3 decay_pos3 = flux.pos.Vect() + decay_rand * (in - flux.pos.Vect()).Unit();
271 
272  // decay time
273  double decay_time = TimeOfFlight(flux, decay_pos3);
274  TLorentzVector decay_pos(decay_pos3, decay_time);
275 
276  // get the decay type
277  int daughter_pdg = RandDaughter(width_elec*fAllowElectronDecay, width_muon*fAllowMuonDecay, width_piplus*fAllowPionDecay, width_pizero*fAllowPi0Decay);
278 
279  double daughter_mass = TDatabasePDG::Instance()->GetParticle(daughter_pdg)->Mass();
280 
281  // daughter mom+energy in the parent rest-frame
282  double daughterE_HRF = flux.mass / 2.;
283  double daughterP_HRF = sqrt(daughterE_HRF * daughterE_HRF - daughter_mass * daughter_mass);
284 
285  // make the two daughters in the higgs rest-frame with a random direction
286  TVector3 pA_HRF = RandomUnitVector() * daughterP_HRF;
287 
288  TVector3 pB_HRF = -pA_HRF;
289 
290  TLorentzVector p4A = TLorentzVector(pA_HRF, daughterE_HRF);
291  TLorentzVector p4B = TLorentzVector(pB_HRF, daughterE_HRF);
292 
293  // Boost
294  p4A.Boost(flux.mom.BoostVector());
295  p4B.Boost(flux.mom.BoostVector());
296 
297  // save the decay info
298  decay.decay_width = width_elec + width_muon + width_piplus + width_pizero;
299  decay.mean_lifetime = lifetime_ns;
300  decay.mean_distance = mean_dist;
301 
302  decay.pos = decay_pos;
303 
304  decay.daughter_mom.push_back(p4A.Vect());
305  decay.daughter_e.push_back(p4A.E());
306  decay.daughter_pdg.push_back(daughter_pdg);
307 
308  decay.daughter_mom.push_back(p4B.Vect());
309  decay.daughter_e.push_back(p4B.E());
310  // daughter B is anti-particle
311  if (daughter_pdg == 111) { // pi0 is its own anti-particle
312  decay.daughter_pdg.push_back(daughter_pdg);
313  }
314  else {
315  decay.daughter_pdg.push_back(-daughter_pdg);
316  }
317 
318  return true;
319 }
320 
321 DEFINE_ART_CLASS_TOOL(HiggsMakeDecay)
322 
323 } // namespace ldm
324 } // namespace evgen
double forcedecay_weight(double mean, double a, double b)
TLorentzVector mom
Definition: MeVPrtlFlux.h:14
process_name opflash particleana ie x
double PiZeroPartialWidth(double higs_mass, double mixing)
double ElectronPartialWidth(double higs_mass, double mixing)
CLHEP::HepRandomEngine * fEngine
Definition: IMeVPrtlStage.h:79
process_name gaushit a
void configure(fhicl::ParameterSet const &pset) override
Interface for configuring the particular algorithm tool.
IMeVPrtlDecay interface class definiton.
Definition: IMeVPrtlDecay.h:36
HiggsMakeDecay class definiton.
double higgs_momentum(double kaon_mass, double pion_mass, double higs_mass)
double MuonPartialWidth(double higs_mass, double mixing)
IMeVPrtlStage interface class definiton. General interface behind each stage. Provides random number ...
Definition: IMeVPrtlStage.h:36
Provides a base class aware of world box coordinates.
static const Constants & Instance()
Definition: Constants.h:68
std::vector< TVector3 > daughter_mom
Definition: MeVPrtlDecay.h:16
std::vector< double > daughter_e
Definition: MeVPrtlDecay.h:17
double PionPartialWidth(double pion_mass, double higs_mass, double mixing)
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Definition: UtilFunc.cxx:13
if &&[-z"$BASH_VERSION"] then echo Attempting to switch to bash bash shellSwitch exit fi &&["$1"= 'shellSwitch'] shift declare a IncludeDirectives for Dir in
std::string to_string(WindowPattern const &pattern)
bool Decay(const MeVPrtlFlux &flux, const TVector3 &in, const TVector3 &out, MeVPrtlDecay &decay, double &weight) override
double PiPlusPartialWidth(double higs_mass, double mixing)
HiggsMakeDecay(fhicl::ParameterSet const &pset)
Constructor.
std::vector< int > daughter_pdg
Definition: MeVPrtlDecay.h:18
TLorentzVector pos
Definition: MeVPrtlFlux.h:11
double forwardPrtlEnergy(double parentM, double secM, double prtlM, double parentE)
Definition: Constants.cpp:212
double flat_to_exp_rand(double x, double mean, double a, double b)
float A
Definition: dedx.py:137
double LeptonPartialWidth(double lep_mass, double higs_mass, double mixing)
double TimeOfFlight(const MeVPrtlFlux &flux, TVector3 decay)
Definition: IMeVPrtlDecay.h:47
int RandDaughter(double elec_width, double muon_width, double piplus_width, double pizero_width)
This is an interface for an art Tool which decays &quot;Prtl&quot; inside a detector volume. It maps MeVPrtlFlux to MeVPrtlDecay.