SecondaryBlockCD.cc
1 /*
2  * MoMEMta: a modular implementation of the Matrix Element Method
3  * Copyright (C) 2016 Universite catholique de Louvain (UCL), Belgium
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <momemta/ParameterSet.h>
20 #include <momemta/Module.h>
21 #include <momemta/Solution.h>
22 #include <momemta/Math.h>
23 #include <momemta/InputTag.h>
24 #include <momemta/Types.h>
25 
26 #include <Math/GenVector/VectorUtil.h>
27 
70 class SecondaryBlockCD: public Module {
71  public:
72 
73  SecondaryBlockCD(PoolPtr pool, const ParameterSet& parameters): Module(pool, parameters.getModuleName()) {
74  sqrt_s = parameters.globalParameters().get<double>("energy");
75 
76  s12 = get<double>(parameters.get<InputTag>("s12"));
77 
78  p1 = get<LorentzVector>(parameters.get<InputTag>("p1"));
79  p2 = get<LorentzVector>(parameters.get<InputTag>("p2"));
80  };
81 
82  virtual Status work() override {
83 
84  solutions->clear();
85 
86  const double m1 = p1->M();
87  const double sq_m1 = SQ(m1);
88  const double m2 = p2->M();
89  const double sq_m2 = SQ(m2);
90 
91  // Don't spend time on unphysical part of phase-space
92  if (*s12 >= SQ(sqrt_s) || sq_m1 + sq_m2 >= *s12)
93  return Status::NEXT;
94 
95  std::vector<double> E1_solutions; // up to two solutions
96  const double theta1 = p1->Theta();
97  const double phi1 = p1->Phi();
98 
99  const double E2 = p2->E();
100  const double norm2 = p2->P();
101 
102  const double cos_theta12 = ROOT::Math::VectorUtil::CosTheta(*p1, *p2);
103 
104  // Equation to be solved for E1 : s12 = (p1+p2)^2 ==> [ 4*SQ(cos_theta12)*SQ(norm2)-4*SQ(E2) ] * SQ(E1) + [ 4*(s12 - SQ(m1) - SQ(m2))*E2 ] * E1 + 4*SQ(m1)*SQ(cos_theta12)*(SQ(m2)-SQ(E2) = 0)
105  const double quadraticTerm = 4 * SQ(E2) - 4 * SQ(norm2) * SQ(cos_theta12);
106  const double linearTerm = 4 * E2 * (sq_m1 + sq_m2 - *s12);
107  const double indepTerm = SQ(sq_m1 + sq_m2 - *s12) + 4 * sq_m1 * SQ(norm2) * SQ(cos_theta12);
108 
109  bool foundSolution = solveQuadratic(quadraticTerm, linearTerm, indepTerm, E1_solutions);
110 
111  if (!foundSolution) {
112  return Status::NEXT;
113  }
114 
115  for (const double& E1: E1_solutions) {
116  // Skip unphysical solutions
117  if (E1 <= 0 || E1 <= m1)
118  continue;
119 
120  // Avoid introducing spurious solution from the equation s12 = (p1+p2)^2 that has to be squared in the computation
121  if ((sq_m1 + sq_m2 + 2 * E1 * E2 - *s12) * cos_theta12 < 0)
122  continue;
123 
124  LorentzVector gen_p1_sol;
125  double norm1 = std::sqrt(SQ(E1) - sq_m1);
126  double gen_pt1_sol = norm1 * std::sin(theta1);
127  gen_p1_sol.SetPxPyPzE(
128  gen_pt1_sol * std::cos(phi1),
129  gen_pt1_sol * std::sin(phi1),
130  norm1 * std::cos(theta1),
131  E1);
132 
133  if (!ApproxComparison(gen_p1_sol.M() / gen_p1_sol.E(), m1 / gen_p1_sol.E())) {
134 #ifndef NDEBUG
135  LOG(trace) << "[SecondaryBlockCD] Throwing solution because of invalid mass. " <<
136  "Expected " << m1 << ", got " << gen_p1_sol.M();
137 #endif
138  continue;
139  }
140 
141 
142  if (!ApproxComparison((gen_p1_sol + *p2).M2(), *s12)) {
143 #ifndef NDEBUG
144  LOG(trace) << "[SecondaryBlockCD] Throwing solution because of invalid invariant mass. " <<
145  "Expected " << *s12 << ", got " << (gen_p1_sol + *p2).M2();
146 #endif
147  continue;
148  }
149 
150  // Compute jacobian
151  double jacobian = std::abs( std::sin(theta1) * SQ(norm1) / (32 * CB(M_PI) * (norm1 * E2 - E1 * norm2 * cos_theta12)) );
152 
153  Solution s { {gen_p1_sol}, jacobian, true };
154  solutions->push_back(s);
155  }
156 
157  return (solutions->size() > 0) ? Status::OK : Status::NEXT;
158  }
159 
160  private:
161  double sqrt_s;
162 
163  // Inputs
164  Value<double> s12;
167 
168  // Output
169  std::shared_ptr<SolutionCollection> solutions = produce<SolutionCollection>("solutions");
170 };
171 
172 REGISTER_MODULE(SecondaryBlockCD)
173  .Input("s12")
174  .Input("p1")
175  .Input("p2")
176  .Output("solutions")
177  .GlobalAttr("energy: double");
bool ApproxComparison(double value, double expected)
Compare two doubles and return true if they are approximatively equal.
Definition: Math.cc:409
Generic solution structure representing a set of particles, along with its jacobian.
Definition: Solution.h:28
Mathematical functions.
bool solveQuadratic(const double a, const double b, const double c, std::vector< double > &roots, bool verbose=false)
Finds the real solutions to .
Definition: Math.cc:26
An identifier of a module&#39;s output.
Definition: InputTag_fwd.h:37
Parent class for all the modules.
Definition: Module.h:37
A class encapsulating a lua table.
Definition: ParameterSet.h:82
virtual Status work() override
Main function.
#define SQ(x)
Compute .
Definition: Math.h:25
Module(PoolPtr pool, const std::string &name)
Constructor.
Definition: Module.h:61
#define CB(x)
Compute .
Definition: Math.h:27
Secondary Block C/D, describing .