BlockA.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 <stdexcept>
29 
78 class BlockA: public Module {
79  public:
80 
81  BlockA(PoolPtr pool, const ParameterSet& parameters): Module(pool, parameters.getModuleName()) {
82 
83  sqrt_s = parameters.globalParameters().get<double>("energy");
84 
85  p1 = get<LorentzVector>(parameters.get<InputTag>("p1"));
86  p2 = get<LorentzVector>(parameters.get<InputTag>("p2"));
87 
88  auto branches_tags = parameters.get<std::vector<InputTag>>("branches");
89  for (auto& t: branches_tags)
90  m_branches.push_back(get<LorentzVector>(t));
91  if (m_branches.empty()) {
92  auto exception = std::invalid_argument("BlockA is not valid without at least a third particle in the event.");
93  LOG(fatal) << exception.what();
94  throw exception;
95  }
96  };
97 
98  virtual Status work() override {
99 
100  solutions->clear();
101 
102  LorentzVector pb;
103  for (size_t i = 0; i < m_branches.size(); i++) {
104  pb += *m_branches[i];
105  }
106 
107  double pbx = pb.Px();
108  double pby = pb.Py();
109  const double theta1 = p1->Theta();
110  const double phi1 = p1->Phi();
111  const double theta2 = p2->Theta();
112  const double phi2 = p2->Phi();
113  const double m1 = p1->M();
114  const double m2 = p2->M();
115 
116  // pT = p1+p2+pb = 0. Equivalent to the following system:
117  // p1x+p2x = -pbx
118  // p1y+p2y = -pby,
119  // where: p1x=modp1*sin(theta1)*cos(phi1), p1y=modp1*sin(theta1)*sin(phi1),
120  // p2x=modp2*sin(theta2)*cos(phi2), p2y=modp2*sin(theta2)*sin(phi2)
121  // Get modp1, modp2 as solutions of this system
122 
123  std::vector<double> modp1;
124  std::vector<double> modp2;
125 
126  const double sin_theta1 = std::sin(theta1);
127  const double cos_phi1 = std::cos(phi1);
128  const double sin_theta2 = std::sin(theta2);
129  const double cos_phi2 = std::cos(phi2);
130  const double sin_phi1 = std::sin(phi1);
131  const double sin_phi2 = std::sin(phi2);
132  const double cos_theta1 = std::cos(theta1);
133  const double cos_theta2 = std::cos(theta2);
134 
135  const double a10 = sin_theta1 * cos_phi1;
136  const double a01 = sin_theta2 * cos_phi2;
137  const double a00 = pbx;
138  const double b10 = sin_theta1 * sin_phi1;
139  const double b01 = sin_theta2 * sin_phi2;
140  const double b00 = pby;
141 
142  bool foundSolution = solve2Linear(a10, a01, a00, b10, b01, b00, modp1, modp2, false);
143 
144  if (!foundSolution)
145  return Status::NEXT;
146 
147  double mod_p1 = modp1[0];
148  double mod_p2 = modp2[0];
149  if (mod_p1 < 0 || mod_p2 < 0)
150  return Status::NEXT;
151 
152  double E1 = sqrt(SQ(mod_p1) + SQ(m1));
153  double E2 = sqrt(SQ(mod_p2) + SQ(m2));
154 
155  LorentzVector gen_p1(mod_p1 * sin_theta1 * cos_phi1, mod_p1 * sin_theta1 * sin_phi1, mod_p1 * cos_theta1, E1);
156  LorentzVector gen_p2(mod_p2 * sin_theta2 * cos_phi2, mod_p2 * sin_theta2 * sin_phi2, mod_p2 * cos_theta2, E2);
157 
158  // Check if solutions are physical
159  LorentzVector tot = gen_p1 + gen_p2 + pb;
160  double q1Pz = std::abs(tot.Pz() + tot.E()) / 2.;
161  double q2Pz = std::abs(tot.Pz() - tot.E()) / 2.;
162  if (q1Pz > sqrt_s / 2 || q2Pz > sqrt_s / 2)
163  return Status::NEXT;
164 
165  // Pt should be 0
166  if (!ApproxComparison(tot.Pt(), 0)) {
167 #ifndef NDEBUG
168  LOG(trace) << "[BlockA] Throwing solution because total Pt is not null: " << tot.Pt();
169 #endif
170  return Status::NEXT;
171  }
172 
173  double jacobian = (SQ(mod_p1) * SQ(mod_p2)) / (8 * SQ(M_PI * sqrt_s) * E1 * E2);
174  jacobian *= 1. / std::abs(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2);
175 
176  Solution s = { {gen_p1, gen_p2}, jacobian, true };
177  solutions->push_back(s);
178 
179  return Status::OK;
180  }
181 
182 
183  private:
184  double sqrt_s;
185 
186  // Inputs
187  Value<LorentzVector> p1, p2;
188  std::vector<Value<LorentzVector>> m_branches;
189  // Outputs
190  std::shared_ptr<SolutionCollection> solutions = produce<SolutionCollection>("solutions");
191 };
192 
193 REGISTER_MODULE(BlockA)
194  .Input("p1")
195  .Input("p2")
196  .OptionalInputs("branches")
197  .Output("solutions")
198  .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.
An identifier of a module&#39;s output.
Definition: InputTag_fwd.h:37
Parent class for all the modules.
Definition: Module.h:37
bool solve2Linear(const double a10, const double a01, const double a00, const double b10, const double b01, const double b00, std::vector< double > &E1, std::vector< double > &E2, bool verbose=false)
Solve a system of two linear equations.
Definition: Math.cc:357
A class encapsulating a lua table.
Definition: ParameterSet.h:82
Final (main) Block A, describing .
Definition: BlockA.cc:78
#define SQ(x)
Compute .
Definition: Math.h:25
Module(PoolPtr pool, const std::string &name)
Constructor.
Definition: Module.h:61
virtual Status work() override
Main function.
Definition: BlockA.cc:98