SecondaryBlockB.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 
77 class SecondaryBlockB: public Module {
78  public:
79 
80  SecondaryBlockB(PoolPtr pool, const ParameterSet& parameters): Module(pool, parameters.getModuleName()),
81  sqrt_s(parameters.globalParameters().get<double>("energy")) {
82  s12 = get<double>(parameters.get<InputTag>("s12"));
83  s123 = get<double>(parameters.get<InputTag>("s123"));
84 
85  m_p1 = get<LorentzVector>(parameters.get<InputTag>("p1"));
86  m_p2 = get<LorentzVector>(parameters.get<InputTag>("p2"));
87  m_p3 = get<LorentzVector>(parameters.get<InputTag>("p3"));
88  };
89 
90  virtual Status work() override {
91 
92  solutions->clear();
93 
94  const double m1 = m_p1->M();
95  const double m2 = m_p2->M();
96  const double m3 = m_p3->M();
97  const double m1_squared = SQ(m1);
98  const double m2_squared = SQ(m2);
99  const double m3_squared = SQ(m3);
100 
101  // Don't spend time on unphysical part of phase-space
102  if (*s123 > SQ(sqrt_s) || *s12 > *s123 || m1_squared + m2_squared >= *s12 || *s12 + m3_squared >= *s123)
103  return Status::NEXT;
104 
105  // Solving the equations
106  // s_{12} = (p_1 + p_2)^2
107  // s_{123} = (p_1 + p_2 + p_3)^2
108  // using \vec{p_i}.\vec{p_j} = p_i^T * p_j^T * cos(\Phi_{ij}) + p_i^z * p_j^z
109  // allows to express p1t as p1t_linear * E1 + p1t_indep and p1z as p1z_linear * E1 + p1z_indep
110  const double E2 = m_p2->E();
111  const double E3 = m_p3->E();
112  const double p2z = m_p2->Pz();
113  const double p3z = m_p3->Pz();
114  const double p2t = m_p2->Pt();
115  const double p3t = m_p3->Pt();
116  const double cosPhi12 = std::cos(ROOT::Math::VectorUtil::DeltaPhi(*m_p1, *m_p2));
117  const double cosPhi13 = std::cos(ROOT::Math::VectorUtil::DeltaPhi(*m_p1, *m_p3));
118  const double cosPhi23 = std::cos(ROOT::Math::VectorUtil::DeltaPhi(*m_p2, *m_p3));
119 
120  const double denominator = cosPhi13 * p2z * p3t - cosPhi12 * p2t * p3z;
121  const double E2E3 = E2 * E3;
122  const double p2zp3z = p2z * p3z;
123  const double p2tp3t = p2t * p3t;
124  const double E3p2z_E2p3z = E3 * p2z - E2 * p3z;
125  const double p1t_linear = E3p2z_E2p3z / denominator;
126  const double p1t_indep = (p2z * (2 * (E2E3 - p2zp3z - cosPhi23 * p2tp3t) + m3_squared - *s123 + *s12) - p3z * (m1_squared + m2_squared - *s12)) / (2. * denominator);
127 
128  const double p1z_linear = (cosPhi12 * E3 * p2t - cosPhi13 * E2 * p3t) / (-denominator);
129  const double p1z_indep = (-(cosPhi13 * p3t * (m1_squared + m2_squared - *s12)) + cosPhi12 * p2t * (2 * (E2E3 - cosPhi23 * p2tp3t - p2zp3z) + m3_squared + *s12 - *s123)) / (2 * (-denominator));
130 
131  // Now, using E_1^2 - |\vec{p_1}|^2 = m_1^2
132  // one can obtain E1.
133  const double p1t_linear_squared = SQ(p1t_linear);
134  const double p1t_indep_squared = SQ(p1t_indep);
135  const double p1z_linear_squared = SQ(p1z_linear);
136  const double p1z_indep_squared = SQ(p1z_indep);
137 
138  const double E1_indep = m1_squared + p1t_indep_squared + p1z_indep_squared;
139  const double E1_linear = 2 * (p1t_indep * p1t_linear + p1z_indep * p1z_linear);
140  const double E1_quadratic = -1 + p1t_linear_squared + p1z_linear_squared;
141 
142  std::vector<double> E1_solutions; // up to two solutions
143  bool foundSolution = solveQuadratic(E1_quadratic, E1_linear, E1_indep, E1_solutions);
144  if (!foundSolution)
145  return Status::NEXT;
146 
147  // Use now the obtained E1 solutions to build p1
148  for (const double& E1: E1_solutions) {
149  // Skip unphysical solutions
150  const double p1t = p1t_linear * E1 + p1t_indep;
151  if (E1 <= m1 || p1t < 0)
152  continue;
153 
154  const double p1z = p1z_linear * E1 + p1z_indep;
155  const double phi1 = m_p1->Phi();
156  LorentzVector p1_sol;
157  p1_sol.SetPxPyPzE(
158  p1t * std::cos(phi1),
159  p1t * std::sin(phi1),
160  p1z,
161  E1);
162 
163  if (!ApproxComparison(p1_sol.M() / p1_sol.E(), m1 / p1_sol.E())) {
164 #ifndef NDEBUG
165  LOG(trace) << "[SecondaryBlockB] Throwing solution because of invalid mass. " <<
166  "Expected " << m1 << ", got " << p1_sol.M();
167 #endif
168  continue;
169  }
170 
171  if (!ApproxComparison((p1_sol + *m_p2 + *m_p3).M2(), *s123)) {
172 #ifndef NDEBUG
173  LOG(trace) << "[SecondaryBlockB] Throwing solution because of invalid invariant mass. " <<
174  "Expected " << *s123 << ", got " << (p1_sol + *m_p2 + *m_p3).M2();
175 #endif
176  continue;
177  }
178 
179  if (!ApproxComparison((p1_sol + *m_p2).M2(), *s12)) {
180 #ifndef NDEBUG
181  LOG(trace) << "[SecondaryBlockB] Throwing solution because of invalid invariant mass. " <<
182  "Expected " << *s12 << ", got " << (p1_sol + *m_p2).M2();
183 #endif
184  continue;
185  }
186 
187  // Compute jacobian
188  const double jacobian = p1t / (64 * CB(M_PI) * std::abs(cosPhi12 * p2t * (E1 * p3z - E3 * p1z) + cosPhi13 * p3t * (E2 * p1z - E1 * p2z) + p1t * E3p2z_E2p3z));
189 
190  Solution solution { {p1_sol}, jacobian, true };
191  solutions->push_back(solution);
192  }
193  return (solutions->size() > 0) ? Status::OK : Status::NEXT;
194 
195  }
196 
197  private:
198  double sqrt_s;
199 
200  // Inputs
201  Value<double> s12;
202  Value<double> s123;
206 
207  // Output
208  std::shared_ptr<SolutionCollection> solutions = produce<SolutionCollection>("solutions");
209 };
210 
211 REGISTER_MODULE(SecondaryBlockB)
212  .Input("s12")
213  .Input("s123")
214  .Input("p1")
215  .Input("p2")
216  .Input("p3")
217  .Output("solutions")
218  .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
Secondary Block B, describing
#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
virtual Status work() override
Main function.