MatrixElement.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 // Must be loaded before `momemta/Logging.h`, otherwise there's conflict between usage
20 // of `log()` and `namespace log`
21 #include <numeric>
22 #include <LHAPDF/LHAPDF.h>
23 
24 #include <momemta/Logging.h>
25 #include <momemta/MatrixElement.h>
26 #include <momemta/MatrixElementFactory.h>
27 #include <momemta/ParameterSet.h>
28 #include <momemta/Math.h>
29 #include <momemta/Module.h>
30 #include <momemta/Types.h>
31 #include <momemta/Utils.h>
32 
150 class MatrixElement: public Module {
151  struct ParticleId {
152  int64_t pdg_id;
153  int64_t me_index;
154  };
155 
156  public:
157 
158  MatrixElement(PoolPtr pool, const ParameterSet& parameters): Module(pool, parameters.getModuleName()) {
159 
160  sqrt_s = parameters.globalParameters().get<double>("energy");
161 
162  use_pdf = parameters.get<bool>("use_pdf", true);
163 
164  m_partons = get<std::vector<LorentzVector>>(parameters.get<InputTag>("initialState"));
165 
166  const auto& particles_set = parameters.get<ParameterSet>("particles");
167 
168  auto particle_tags = particles_set.get<std::vector<InputTag>>("inputs");
169  for (auto& tag: particle_tags)
170  m_particles.push_back(get<LorentzVector>(tag));
171 
172  const auto& particles_ids_set = particles_set.get<std::vector<ParameterSet>>("ids");
173  for (const auto& s: particles_ids_set) {
174  ParticleId id;
175  id.pdg_id = s.get<int64_t>("pdg_id");
176  id.me_index = s.get<int64_t>("me_index");
177  m_particles_ids.push_back(id);
178  }
179 
180  if (m_particles.size() != m_particles_ids.size()) {
181  LOG(fatal) << "The number of particles ids is not consistent with the number of particles. Did you"
182  " forget some ids?";
183 
184  throw Module::invalid_configuration("Inconsistent number of ids and number of particles");
185  }
186 
187  const auto& jacobians_tags = parameters.get<std::vector<InputTag>>("jacobians", std::vector<InputTag>());
188  for (const auto& tag: jacobians_tags) {
189  m_jacobians.push_back(get<double>(tag));
190  }
191 
192  std::string matrix_element = parameters.get<std::string>("matrix_element");
193  const ParameterSet& matrix_element_configuration = parameters.get<ParameterSet>("matrix_element_parameters");
194  m_ME = MatrixElementFactory::get().create(matrix_element, matrix_element_configuration);
195 
196  if (parameters.exists("override_parameters")) {
197  const ParameterSet& matrix_element_params = parameters.get<ParameterSet>("override_parameters");
198  auto p = m_ME->getParameters();
199 
200  for (const auto& name: matrix_element_params.getNames()) {
201  double value = matrix_element_params.get<double>(name);
202  p->setParameter(name, value);
203  }
204 
205  p->cacheParameters();
206  p->cacheCouplings();
207  }
208 
209  // PDF, if asked
210  if (use_pdf) {
211  // Silence LHAPDF
212  LHAPDF::setVerbosity(0);
213 
214  std::string pdf = parameters.get<std::string>("pdf");
215  m_pdf.reset(LHAPDF::mkPDF(pdf, 0));
216 
217  double pdf_scale = parameters.get<double>("pdf_scale");
218  pdf_scale_squared = SQ(pdf_scale);
219  }
220 
221  // Prepare arrays for sorting particles
222  for (size_t i = 0; i < m_particles_ids.size(); i++) {
223  indexing.push_back(m_particles_ids[i].me_index - 1);
224  }
225 
226  // Pre-allocate memory for the finalState array
227  finalState.resize(m_particles_ids.size());
228 
229  // Sort the array taking into account the indexing in the configuration
230  std::vector<int64_t> suite(indexing.size());
231  std::iota(suite.begin(), suite.end(), 0);
232 
233  permutations = get_permutations(suite, indexing);
234  };
235 
236  virtual void beginIntegration() {
237  // Don't assume the non-zero helicities will be the same for each event
238  // In principle they are, but this protects against buggy calls to the ME (e.g. returning NaN or inf)
239  m_ME->resetHelicities();
240  }
241 
242  virtual Status work() override {
243  static std::vector<LorentzVector> empty_vector;
244 
245  *m_integrand = 0;
246  const std::vector<LorentzVector>& partons = *m_partons;
247 
248  LorentzVectorRefCollection particles;
249  for (const auto& p: m_particles)
250  particles.push_back(std::ref(*p));
251 
252  for (size_t i = 0; i < m_particles_ids.size(); i++) {
253  finalState[i] = std::make_pair(m_particles_ids[i].pdg_id, toVector(particles[i].get()));
254  }
255 
256  // Sort the array taking into account the indexing in the configuration
257  apply_permutations(finalState, permutations);
258 
259  std::pair<std::vector<double>, std::vector<double>> initialState { toVector(partons[0]),
260  toVector(partons[1]) };
261 
262  auto result = m_ME->compute(initialState, finalState);
263 
264  double x1 = std::abs(partons[0].Pz() / (sqrt_s / 2.));
265  double x2 = std::abs(partons[1].Pz() / (sqrt_s / 2.));
266 
267  // Compute flux factor 1/(2*x1*x2*s)
268  double phaseSpaceIn = 1. / (2. * x1 * x2 * SQ(sqrt_s));
269 
270  double integrand = phaseSpaceIn;
271  for (const auto& jacobian: m_jacobians) {
272  integrand *= (*jacobian);
273  }
274 
275  // PDF
276  double final_integrand = 0;
277  for (const auto& me: result) {
278  double pdf1 = use_pdf ? m_pdf->xfxQ2(me.first.first, x1, pdf_scale_squared) / x1 : 1;
279  double pdf2 = use_pdf ? m_pdf->xfxQ2(me.first.second, x2, pdf_scale_squared) / x2 : 1;
280 
281  final_integrand += me.second * pdf1 * pdf2;
282  }
283 
284  final_integrand *= integrand;
285  *m_integrand = final_integrand;
286 
287  return Status::OK;
288  }
289 
290  private:
291  double sqrt_s;
292  bool use_pdf;
293  double pdf_scale_squared = 0;
294  std::shared_ptr<momemta::MatrixElement> m_ME;
295  std::shared_ptr<LHAPDF::PDF> m_pdf;
296 
297  std::vector<int64_t> indexing;
298  std::vector<size_t> permutations;
299  std::vector<std::pair<int, std::vector<double>>> finalState;
300 
301  // Inputs
303 
304  std::vector<Value<LorentzVector>> m_particles;
305  std::vector<ParticleId> m_particles_ids;
306 
307  std::vector<Value<double>> m_jacobians;
308 
309  // Outputs
310  std::shared_ptr<double> m_integrand = produce<double>("output");
311 };
312 
313 REGISTER_MODULE(MatrixElement)
314  .Input("initialState")
315  .OptionalInputs("jacobians")
316  .Inputs("particles/inputs")
317  .Output("output")
318  .GlobalAttr("energy:double")
319  .Attr("matrix_element:string")
320  .Attr("matrix_element_parameters:pset")
321  .OptionalAttr("override_parameters:pset")
322  .Attr("particles:pset")
323  .Attr("use_pdf:bool=true")
324  .OptionalAttr("pdf:string")
325  .OptionalAttr("pdf_scale:double");
virtual Status work() override
Main function.
Mathematical functions.
virtual void beginIntegration()
Called once at the beginning of the integration.
virtual void create(const std::string &name, const momemta::any &value)
Add a new element to the ParameterSet.
Definition: ParameterSet.cc:48
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
A class representing a value produced by a module.
Definition: Value.h:30
Module(PoolPtr pool, const std::string &name)
Constructor.
Definition: Module.h:61
Compute the integrand: matrix element, PDFs, jacobians.