BlockG.cc
1 
2 /*
3  * MoMEMta: a modular implementation of the Matrix Element Method
4  * Copyright (C) 2016 Universite catholique de Louvain (UCL), Belgium
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <momemta/Logging.h>
21 #include <momemta/ParameterSet.h>
22 #include <momemta/Module.h>
23 #include <momemta/Solution.h>
24 #include <momemta/Types.h>
25 #include <momemta/Utils.h>
26 #include <momemta/Math.h>
27 
28 #include <Math/GenVector/VectorUtil.h>
29 
79 class BlockG: public Module {
80  public:
81 
82  BlockG(PoolPtr pool, const ParameterSet& parameters): Module(pool, parameters.getModuleName()) {
83 
84  sqrt_s = parameters.globalParameters().get<double>("energy");
85 
86  s12 = get<double>(parameters.get<InputTag>("s12"));
87  s34 = get<double>(parameters.get<InputTag>("s34"));
88 
89  m_particles.push_back(get<LorentzVector>(parameters.get<InputTag>("p1")));
90  m_particles.push_back(get<LorentzVector>(parameters.get<InputTag>("p2")));
91  m_particles.push_back(get<LorentzVector>(parameters.get<InputTag>("p3")));
92  m_particles.push_back(get<LorentzVector>(parameters.get<InputTag>("p4")));
93 
94  if (parameters.exists("branches")) {
95  auto branches_tags = parameters.get<std::vector<InputTag>>("branches");
96  for (auto& t: branches_tags)
97  m_branches.push_back(get<LorentzVector>(t));
98  }
99  };
100 
101  virtual Status work() override {
102 
103  solutions->clear();
104 
105  if (*s12 + *s34 >= SQ(sqrt_s))
106  return Status::NEXT;
107 
108  const LorentzVector& p1 = *m_particles[0];
109  const LorentzVector& p2 = *m_particles[1];
110  const LorentzVector& p3 = *m_particles[2];
111  const LorentzVector& p4 = *m_particles[3];
112 
113  LorentzVector pb;
114  for (size_t i = 0; i < m_branches.size(); i++) {
115  pb += *m_branches[i];
116  }
117 
118  const double pbx = pb.Px();
119  const double pby = pb.Py();
120  const double sin_theta_1 = std::sin(p1.Theta());
121  const double sin_theta_2 = std::sin(p2.Theta());
122  const double sin_theta_3 = std::sin(p3.Theta());
123  const double sin_theta_4 = std::sin(p4.Theta());
124  const double phi_1 = p1.Phi();
125  const double phi_2 = p2.Phi();
126  const double phi_3 = p3.Phi();
127  const double phi_4 = p4.Phi();
128  const double sin_phi_3_2 = std::sin(phi_3 - phi_2);
129  const double sin_phi_2_1 = std::sin(phi_2 - phi_1);
130  const double sin_phi_4_2 = std::sin(phi_4 - phi_2);
131  const double sin_phi_1_3 = std::sin(phi_1 - phi_3);
132  const double sin_phi_1_4 = std::sin(phi_1 - phi_4);
133 
134  /*
135  * p1 = alpha1 p3 + beta1 p4 + gamma1
136  * p2 = alpha2 p3 + beta2 p4 + gamma2
137  */
138 
139  const double denom_1 = sin_theta_1 * sin_phi_2_1;
140  const double denom_2 = sin_theta_2 * sin_phi_2_1;
141 
142  const double alpha_1 = sin_theta_3 * sin_phi_3_2 / denom_1;
143  const double beta_1 = sin_theta_4 * sin_phi_4_2 / denom_1;
144  const double gamma_1 = ( std::cos(phi_2) * pby - std::sin(phi_2) * pbx ) / denom_1;
145 
146  const double alpha_2 = sin_theta_3 * sin_phi_1_3 / denom_2;
147  const double beta_2 = sin_theta_4 * sin_phi_1_4 / denom_2;
148  const double gamma_2 = ( std::sin(phi_1) * pbx - std::cos(phi_1) * pby ) / denom_2;
149 
150  const double cos_theta_34 = ROOT::Math::VectorUtil::CosTheta(p3, p4);
151  const double cos_theta_12 = ROOT::Math::VectorUtil::CosTheta(p1, p2);
152  const double X = 0.5 * (*s34) / (1 - cos_theta_34);
153  const double Y = 0.5 * (*s12) / (1 - cos_theta_12);
154 
155  std::vector<double> gen_p3_solutions;
156  solveQuartic(
157  alpha_1 * alpha_2,
158  alpha_1 * gamma_2 + gamma_1 * alpha_2,
159  gamma_1 * gamma_2 + (beta_1 * alpha_2 + alpha_1 * beta_2) * X - Y,
160  (beta_1 * gamma_2 + gamma_1 * beta_2) * X,
161  beta_1 * beta_2 * SQ(X),
162  gen_p3_solutions
163  );
164 
165  for (const auto& p3_sol: gen_p3_solutions) {
166 
167  const double p4_sol = X / p3_sol;
168  const double p1_sol = alpha_1 * p3_sol + beta_1 * p4_sol + gamma_1;
169  const double p2_sol = alpha_2 * p3_sol + beta_2 * p4_sol + gamma_2;
170 
171  if (p1_sol < 0 || p2_sol < 0 || p3_sol < 0 || p4_sol < 0)
172  continue;
173 
174  LorentzVector gen_p1(p1_sol * sin_theta_1 * std::cos(phi_1), p1_sol * sin_theta_1 * std::sin(phi_1), p1_sol * std::cos(p1.Theta()), p1_sol);
175  LorentzVector gen_p2(p2_sol * sin_theta_2 * std::cos(phi_2), p2_sol * sin_theta_2 * std::sin(phi_2), p2_sol * std::cos(p2.Theta()), p2_sol);
176  LorentzVector gen_p3(p3_sol * sin_theta_3 * std::cos(phi_3), p3_sol * sin_theta_3 * std::sin(phi_3), p3_sol * std::cos(p3.Theta()), p3_sol);
177  LorentzVector gen_p4(p4_sol * sin_theta_4 * std::cos(phi_4), p4_sol * sin_theta_4 * std::sin(phi_4), p4_sol * std::cos(p4.Theta()), p4_sol);
178 
179  // Check if solutions are physical
180  LorentzVector tot = gen_p1 + gen_p2 + gen_p3 + gen_p4 + pb;
181  double q1Pz = std::abs(tot.Pz() + tot.E()) / 2.;
182  double q2Pz = std::abs(tot.Pz() - tot.E()) / 2.;
183  if (q1Pz > sqrt_s / 2 || q2Pz > sqrt_s / 2)
184  continue;
185 
186  if (!ApproxComparison(tot.Pt(), 0.)) {
187 #ifndef NDEBUG
188  LOG(trace) << "[BlockG] Throwing solution because total Pt is incorrect. "
189  << "Expected " << 0. << ", got " << tot.Pt();
190 #endif
191  continue;
192  }
193 
194  if (!ApproxComparison((gen_p1 + gen_p2).M2(), *s12)) {
195 #ifndef NDEBUG
196  LOG(trace) << "[BlockG] Throwing solution because of invalid invariant mass. " <<
197  "Expected " << *s12 << ", got " << (gen_p1 + gen_p2).M2();
198 #endif
199  continue;
200  }
201 
202  if (!ApproxComparison((gen_p3 + gen_p4).M2(), *s34)) {
203 #ifndef NDEBUG
204  LOG(trace) << "[BlockG] Throwing solution because of invalid invariant mass. " <<
205  "Expected " << *s34 << ", got " << (gen_p3 + gen_p4).M2();
206 #endif
207  continue;
208  }
209 
210  double jacobian = 1 / std::abs( 2 *
211  (1 - cos_theta_12) * (1 - cos_theta_34) * (
212  alpha_1 * gamma_2 * p3_sol + alpha_2 * p3_sol * (gamma_1 + 2 * alpha_1 * p3_sol) -
213  p4_sol * (beta_2 * gamma_1 + beta_1 * gamma_2 + 2 * beta_1 * beta_2 * p4_sol)
214  ) * SQ(sqrt_s) * sin_phi_2_1 );
215  jacobian *= ( sin_theta_3 * sin_theta_4 * p1_sol * p2_sol * p3_sol * p4_sol ) / ( 16 * pow(2*M_PI, 8) );
216 
217  Solution s = { { gen_p1, gen_p2, gen_p3, gen_p4 }, jacobian, true };
218  solutions->push_back(s);
219  }
220 
221  if (!solutions->size())
222  return Status::NEXT;
223 
224  return Status::OK;
225  }
226 
227 
228  private:
229  double sqrt_s;
230 
231  // Inputs
232  std::vector<Value<LorentzVector>> m_branches;
233  std::vector<Value<LorentzVector>> m_particles;
234  Value<double> s12, s34;
235  // Outputs
236  std::shared_ptr<SolutionCollection> solutions = produce<SolutionCollection>("solutions");
237 };
238 
239 REGISTER_MODULE(BlockG)
240  .Input("s12")
241  .Input("s34")
242  .Input("p1")
243  .Input("p2")
244  .Input("p3")
245  .Input("p4")
246  .OptionalInputs("branches")
247  .Output("solutions")
248  .GlobalAttr("energy:double");
bool solveQuartic(const double a, const double b, const double c, const double d, const double e, std::vector< double > &roots, bool verbose=false)
Finds the real solutions to .
Definition: Math.cc:117
virtual Status work() override
Main function.
Definition: BlockG.cc:101
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.
Final (main) Block G, describing .
Definition: BlockG.cc:79
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
#define SQ(x)
Compute .
Definition: Math.h:25
Module(PoolPtr pool, const std::string &name)
Constructor.
Definition: Module.h:61