cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.3
A generic central exclusive processes event generator
Loading...
Searching...
No Matches
Process.cpp
Go to the documentation of this file.
1/*
2 * CepGen: a central exclusive processes event generator
3 * Copyright (C) 2013-2024 Laurent Forthomme
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 * 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 <iomanip>
20
26#include "CepGen/Physics/PDG.h"
28#include "CepGen/Utils/Math.h"
30#include "CepGen/Utils/String.h"
31
32namespace cepgen {
33 namespace proc {
34 auto compute_value = [](double in, const Process::Mapping& type) -> double {
35 switch (type) {
37 case Process::Mapping::power_law: //FIXME
38 default:
39 return in;
41 return in * in;
43 return std::exp(in);
44 }
45 };
46
48 : NamedModule(params),
49 mp_(PDG::get().mass(PDG::proton)),
50 mp2_(mp_ * mp_),
51 rnd_gen_(RandomGeneratorFactory::get().build(steer<ParametersList>("randomGenerator"))) {
52 if (const auto& kin = steer<ParametersList>("kinematics"); !kin.empty())
53 kin_.setParameters(kin);
54 if (steer<bool>("hasEvent"))
55 event_.reset(new Event);
56 }
57
58 Process::Process(const Process& proc) : Process(proc.parameters()) { *this = proc; }
59
61 s_ = proc.s_;
62 sqs_ = proc.sqs_;
63 inv_sqs_ = proc.inv_sqs_;
64 mA2_ = proc.mA2_;
65 mB2_ = proc.mB2_;
66 mX2_ = proc.mX2_;
67 mY2_ = proc.mY2_;
68 point_coord_ = proc.point_coord_;
69 base_jacobian_ = proc.base_jacobian_;
70 if (proc.event_)
71 event_.reset(new Event(*proc.event_));
72 CG_DEBUG("Process").log([&](auto& log) {
73 log << "Process " << name_ << " cloned with "
74 << utils::s("integration variable", mapped_variables_.size(), true) << ":";
75 for (const auto& var : mapped_variables_)
76 log << "\n\t" << var.index << ") " << var.description << " (type: " << var.type << ", limits: " << var.limits
77 << ").";
78 if (event_)
79 log << "\n\t" << *event_;
80 });
81 kin_ = proc.kin_;
82 return *this;
83 }
84
85 std::unique_ptr<Process> Process::clone() const {
86 throw CG_FATAL("Process:clone") << "Process \"" << name_ << "\" has no cloning method implementation!";
87 }
88
90
92
94
96
98
100
102
104
106
108
110
112
114 if (event()[Particle::CentralSystem].size() <= i)
115 throw CG_FATAL("Process:pc") << "Trying to retrieve central particle #" << i << " while only "
116 << event()[Particle::CentralSystem].size() << " is/are registered.";
117 return event()[Particle::CentralSystem].at(i).get().momentum();
118 }
119
120 const Momentum& Process::pc(size_t i) const {
121 if (event()(Particle::CentralSystem).size() <= i)
122 throw CG_FATAL("Process:pc") << "Trying to retrieve central particle #" << i << " while only "
123 << event()(Particle::CentralSystem).size() << " is/are registered.";
124 return event()(Particle::CentralSystem).at(i).momentum();
125 }
126
127 double Process::shat() const { return (q1() + q2()).mass2(); }
128
131 //--- initialise the "constant" (wrt x) part of the Jacobian
132 base_jacobian_ = 1.;
133 mapped_variables_.clear();
134 CG_DEBUG("Process:clear") << "Process event content, and integration variables cleared.";
135 }
136
137 void Process::dumpVariables(std::ostream* os) const {
138 std::ostringstream ss;
139 ss << "List of variables handled by this process:";
140 for (const auto& var : mapped_variables_)
141 ss << "\n\t(" << var.index << ") " << var.type << " mapping (" << var.description << ")"
142 << " in range " << var.limits;
143 if (os)
144 (*os) << ss.str();
145 else
146 CG_LOG << ss.str();
147 }
148
150 double& out, const Mapping& type, const Limits& lim, const std::string& name, const std::string& descr) {
151 if (lim.min() == lim.max()) {
152 if (lim.hasMin()) {
153 out = compute_value(lim.min(), type);
154 CG_DEBUG("Process:defineVariable")
155 << "Quantity " << descr << " is set to be constant with a value " << out << ".";
156 return *this;
157 } else
158 throw CG_FATAL("Process:defineVariable")
159 << "The limits for '" << descr << "' (" << lim << ") could not be retrieved from the user configuration.";
160 }
161
162 double jacob_weight = 1.; // initialise the local weight for this variable
163 switch (type) {
164 case Mapping::linear:
165 jacob_weight = lim.range();
166 break;
167 case Mapping::square:
168 jacob_weight = 2. * lim.range();
169 break;
171 jacob_weight = lim.range();
172 break;
174 jacob_weight = log(lim.max() / lim.min());
175 break;
176 }
177 const auto var_desc =
178 (!descr.empty() ? descr : (!name.empty() ? name : utils::format("var%z", mapped_variables_.size())));
179 mapped_variables_.emplace_back(MappingVariable{name, var_desc, lim, out, type, mapped_variables_.size()});
180 point_coord_.emplace_back(0.);
181 base_jacobian_ *= jacob_weight;
182 CG_DEBUG("Process:defineVariable") << "\n\t" << descr << " has been mapped to variable "
183 << mapped_variables_.size() << ".\n\t"
184 << "Allowed range for integration: " << lim << ".\n\t"
185 << "Variable integration mode: " << type << ".\n\t"
186 << "Weight in the Jacobian: " << jacob_weight << ".";
187 return *this;
188 }
189
190 double Process::variableValue(size_t i, double x) const {
191 const auto& var = mapped_variables_.at(i);
192 return compute_value(var.limits.x(x), var.type);
193 }
194
196 if (mapped_variables_.size() == 0)
197 throw CG_FATAL("Process:vars") << "No variables are mapped for this process!";
198 if (base_jacobian_ == 0.)
199 throw CG_FATAL("Process:vars") << "Point-independent component of the Jacobian for this "
200 << "process is null.\n\t"
201 << "Please check the validity of the phase space!";
202
203 double jacobian = 1.;
204 for (const auto& var : mapped_variables_) {
205 if (!var.limits.valid())
206 continue;
207 if (var.index >= point_coord_.size())
208 throw CG_FATAL("Process:x") << "Failed to retrieve coordinate " << var.index << " from "
209 << "a dimension-" << ndim() << " process!";
210 const auto& xv = point_coord_.at(var.index); // between 0 and 1
211 var.value = compute_value(var.limits.x(xv), var.type);
212 switch (var.type) {
213 case Mapping::linear: {
214 // jacobian *= 1
215 } break;
217 jacobian *= var.value;
218 } break;
219 case Mapping::square: {
220 jacobian *= var.limits.x(xv);
221 } break;
222 case Mapping::power_law: {
223 const double y = var.limits.max() / var.limits.min();
224 var.value = var.limits.min() * std::pow(y, xv);
225 jacobian *= var.value;
226 } break;
227 }
228 CG_DEBUG_LOOP("Process:vars") << "\n\tvariable " << var.index << std::left << std::setw(60)
229 << (!var.description.empty() ? " (" + var.description + ")" : "") << " in range "
230 << std::setw(20) << var.limits << " has value " << std::setw(20) << var.value
231 << " (x=" << point_coord_.at(var.index) << std::right << ")";
232 }
233 return jacobian;
234 }
235
236 double Process::weight(const std::vector<double>& x) {
237 point_coord_ = x;
238
239 //--- generate and initialise all variables and generate auxiliary
240 // (x-dependent) part of the Jacobian for this phase space point.
241 const auto aux_jacobian = generateVariables();
242
243 CG_DEBUG_LOOP("Process:weight").log([&](auto& log) {
244 log << "Jacobian: " << base_jacobian_ << " * " << aux_jacobian << " = " << (base_jacobian_ * aux_jacobian)
245 << ".\n\t";
246 dumpPoint(&log.stream());
247 });
248
249 if (!utils::positive(aux_jacobian))
250 return 0.;
251
252 //--- compute the integrand
253 const auto me_integrand = computeWeight();
254 CG_DEBUG_LOOP("Process:weight") << "Integrand = " << me_integrand << "\n\t"
255 << "Proc.-specific integrand * Jacobian (excl. global Jacobian) = "
256 << (me_integrand * aux_jacobian) << ".";
257 if (!utils::positive(me_integrand))
258 return 0.;
259
260 //--- combine every component into a single weight for this point
261 return (base_jacobian_ * aux_jacobian) * me_integrand * constants::GEVM2_TO_PB;
262 }
263
265 if (event_)
266 event_->restore();
267 }
268
269 const Event& Process::event() const {
270 if (!event_)
271 throw CG_FATAL("Process:event") << "Process does not have an event object!";
272 return *event_;
273 }
274
276 if (!event_)
277 throw CG_FATAL("Process:event") << "Process does not have an event object!";
278 return *event_;
279 }
280
282 if (!event_)
283 throw CG_FATAL("Process:event") << "Process does not have an event object!";
284 return event_.get();
285 }
286
288 CG_DEBUG("Process:initialise") << "Preparing to set the kinematics parameters. Input parameters: "
289 << ParametersDescription(kin_.parameters()) << ".";
290
291 clear(); // also resets the "first run" flag
292
293 // build the coupling objects
294 const auto& alpha_em = steer<ParametersList>("alphaEM");
295 if (!alpha_em.empty())
296 alphaem_ = AlphaEMFactory::get().build(alpha_em);
297 const auto& alpha_s = steer<ParametersList>("alphaS");
298 if (!alpha_s.empty())
299 alphas_ = AlphaSFactory::get().build(alpha_s);
300
301 const auto& p1 = kin_.incomingBeams().positive().momentum();
302 const auto& p2 = kin_.incomingBeams().negative().momentum();
303 //--- define incoming system
304 if (event_) {
305 auto& ib1 = event_->oneWithRole(Particle::IncomingBeam1);
306 ib1.setIntegerPdgId(kin_.incomingBeams().positive().integerPdgId());
307 ib1.setMomentum(p1);
308 auto& ib2 = event_->oneWithRole(Particle::IncomingBeam2);
309 ib2.setIntegerPdgId(kin_.incomingBeams().negative().integerPdgId());
310 ib2.setMomentum(p2);
311 auto& ob1 = event_->oneWithRole(Particle::OutgoingBeam1);
312 ob1.setIntegerPdgId(kin_.incomingBeams().positive().integerPdgId());
315 auto& ob2 = event_->oneWithRole(Particle::OutgoingBeam2);
316 ob2.setIntegerPdgId(kin_.incomingBeams().negative().integerPdgId());
319 for (auto& cp : (*event_)[Particle::CentralSystem])
320 cp.get().setIntegerPdgId(cp.get().integerPdgId());
321 }
322 s_ = kin_.incomingBeams().s();
323 sqs_ = std::sqrt(s_);
324 inv_sqs_ = 1. / sqs_;
325
326 mA2_ = mX2_ = p1.mass2();
327 mB2_ = mY2_ = p2.mass2();
328 wcm_ = 0.5 * (1. + std::sqrt(1. - 4. * std::sqrt(mA2_ * mB2_) / s_));
329
331
332 if (event_) {
333 CG_DEBUG("Process:initialise").log([this, &p1, &p2](auto& log) {
334 log << "Kinematics successfully set!\n"
335 << " sqrt(s) = " << sqs_ * 1.e-3 << " TeV,\n"
336 << " p1=" << p1 << ",\tmass=" << p1.mass() << " GeV\n"
337 << " p2=" << p2 << ",\tmass=" << p2.mass() << " GeV.\n";
338 dumpVariables(&log.stream());
339 });
340 clearEvent();
341 }
342 }
343
345 if (!rnd_gen_)
346 throw CG_FATAL("Process:randomGenerator") << "Process-local random generator was not yet initialised.";
347 return *rnd_gen_;
348 }
349
350 double Process::alphaEM(double q) const {
351 if (!alphaem_)
352 throw CG_FATAL("Process:alphaEM")
353 << "Trying to compute the electromagnetic running coupling while it is not initialised.";
354 return (*alphaem_)(q);
355 }
356
357 double Process::alphaS(double q) const {
358 if (!alphas_)
359 throw CG_FATAL("Process:alphaS")
360 << "Trying to compute the strong running coupling while it is not initialised.";
361 return (*alphas_)(q);
362 }
363
364 void Process::dumpPoint(std::ostream* os) const {
365 std::ostringstream oss;
366 oss << "Number of integration parameters: " << mapped_variables_.size() << ", point: {"
367 << utils::merge(point_coord_, ", ") << "}.";
368 if (!os)
369 CG_INFO("Process") << oss.str();
370 else
371 (*os) << oss.str();
372 }
373
374 void Process::setEventContent(const std::unordered_map<Particle::Role, spdgids_t>& part_ids) {
375 if (!event_)
376 return;
377 if (part_ids.count(Particle::Role::CentralSystem) == 0)
378 throw CG_FATAL("Process") << "The central system was not specified for this process.";
379
380 *event_ = Event::minimal(part_ids.at(Particle::Role::CentralSystem).size());
381 for (const auto& role_vs_parts : part_ids) {
382 auto evt_parts = (*event_)[role_vs_parts.first];
383 if (evt_parts.size() != role_vs_parts.second.size())
384 throw CG_FATAL("Process") << "Invalid number of '" << role_vs_parts.first << "' given. "
385 << "Expecting " << evt_parts.size() << ", got " << role_vs_parts.second.size()
386 << ".";
387 for (size_t i = 0; i < evt_parts.size(); ++i) {
388 auto& evt_part = evt_parts.at(i).get();
389 const auto user_evt_part_pdgid = role_vs_parts.second.at(i);
390 evt_part.setIntegerPdgId(user_evt_part_pdgid);
391 evt_part.momentum().setMass(PDG::get().mass(user_evt_part_pdgid));
392 }
393 }
394 event_->freeze(); // freeze the event as it is
395 }
396
399 if (event().hasRole(Particle::Intermediate)) {
400 Momentum interm_mom;
401 for (size_t i = 0; i < event()[Particle::CentralSystem].size(); ++i)
402 interm_mom += pc(i);
404 }
405 }
406
408 auto desc = ParametersDescription();
409 desc.add<ParametersDescription>("alphaEM", AlphaEMFactory::get().describeParameters("fixed"))
410 .setDescription("electromagnetic coupling evolution algorithm");
411 desc.add<ParametersDescription>("alphaS", AlphaSFactory::get().describeParameters("pegasus"))
412 .setDescription("strong coupling evolution algorithm");
413 desc.add<bool>("hasEvent", true).setDescription("does the process carry an event definition");
414 desc.add<ParametersDescription>("randomGenerator", RandomGeneratorFactory::get().describeParameters("stl"))
415 .setDescription("random number generator engine");
416 desc.add("kinematics", Kinematics::description());
417 return desc;
418 }
419
420 std::ostream& operator<<(std::ostream& os, const Process::Mapping& type) {
421 switch (type) {
423 return os << "linear";
425 return os << "exponential";
427 return os << "squared";
429 return os << "power law";
430 }
431 return os;
432 }
433 } // namespace proc
434} // namespace cepgen
#define CG_FATAL(mod)
Definition Exception.h:61
#define CG_DEBUG_LOOP(mod)
Definition Message.h:224
#define CG_LOG
Definition Message.h:212
#define CG_DEBUG(mod)
Definition Message.h:220
#define CG_INFO(mod)
Definition Message.h:216
spdgid_t integerPdgId() const
Beam particle PDG id Set the beam particle PDG id.
Definition Beam.h:47
const Momentum & momentum() const
Beam particle 4-momentum Set the beam particle 4-momentum.
Definition Beam.h:54
bool elastic() const
Does the beam remain on-shell after parton emission? Specify if the beam remains on-shell after parto...
Definition Beam.h:40
Container for the information on the in- and outgoing particles' kinematics.
Definition Event.h:28
Particle & oneWithRole(Particle::Role role)
First Particle object with a given role in the event.
Definition Event.cpp:181
size_t size() const
Number of particles in the event.
Definition Event.cpp:303
static Event minimal(size_t num_out_particles=1)
Build a trivial event with the minimal information.
Definition Event.cpp:42
const Beam & positive() const
Reference to the positive-z beam information.
double s() const
Incoming beams squared centre of mass energy (in GeV^2)
const Beam & negative() const
Reference to the negative-z beam information.
void setParameters(const ParametersList &) override
Set module parameters.
IncomingBeams & incomingBeams()
Beam/primary particle kinematics.
Definition Kinematics.h:36
static ParametersDescription description()
const ParametersList & parameters() const override
List containing all parameters handled.
Validity interval for a variable.
Definition Limits.h:28
double range() const
Full variable range allowed.
Definition Limits.cpp:65
bool hasMin() const
Have a lower limit?
Definition Limits.cpp:73
double min() const
Lower limit to apply on the variable.
Definition Limits.h:52
double max() const
Upper limit to apply on the variable.
Definition Limits.h:54
Container for a particle's 4-momentum, along with useful methods to ease the development of any matri...
Definition Momentum.h:33
Base runtime module object.
Definition NamedModule.h:28
const std::string & name() const
Module unique indexing name.
Definition NamedModule.h:42
const std::string name_
Module unique indexing name.
Definition NamedModule.h:45
A singleton holding all physics constants associated to particles.
Definition PDG.h:28
double mass(spdgid_t) const
Particle mass (in GeV)
Definition PDG.cpp:90
static PDG & get()
Retrieve a unique instance of this particles info collection.
Definition PDG.cpp:41
A description object for parameters collection.
Momentum & momentum()
Retrieve the momentum object associated with this particle Retrieve the momentum object associated wi...
Definition Particle.h:124
Particle & setMomentum(const Momentum &, bool offshell=false)
Associate a momentum object to this particle.
Definition Particle.cpp:104
@ FinalState
Stable, final state particle.
@ Unfragmented
Particle to be hadronised externally.
@ IncomingBeam2
incoming beam particle
Definition Particle.h:53
@ Parton2
beam incoming parton
Definition Particle.h:59
@ OutgoingBeam1
outgoing beam state/particle
Definition Particle.h:54
@ IncomingBeam1
incoming beam particle
Definition Particle.h:52
@ OutgoingBeam2
outgoing beam state/particle
Definition Particle.h:55
@ Parton1
beam incoming parton
Definition Particle.h:58
@ CentralSystem
Central particles system.
Definition Particle.h:56
@ Intermediate
Intermediate two-parton system.
Definition Particle.h:57
Class template to define any process to compute using this MC integrator/events generator.
Definition Process.h:34
void clearEvent()
Restore the event object to its initial state.
Definition Process.cpp:264
void dumpPoint(std::ostream *=nullptr) const
Dump the coordinate of the phase-space point being evaluated.
Definition Process.cpp:364
virtual void prepareKinematics()
Compute the incoming state kinematics.
Definition Process.h:115
const Momentum & pA() const
Positive-z incoming beam particle's 4-momentum.
Definition Process.cpp:91
void initialise()
Initialise the process once the kinematics has been set.
Definition Process.cpp:287
const Momentum & pX() const
Positive-z outgoing beam particle's 4-momentum.
Definition Process.cpp:99
const Momentum & q2() const
Negative-z incoming parton's 4-momentum.
Definition Process.cpp:111
virtual void addEventContent()=0
Set the incoming and outgoing state to be expected in the process.
virtual void fillKinematics()=0
Fill the Event object with the particles' kinematics.
Process & defineVariable(double &out, const Mapping &type, const Limits &lim, const std::string &name, const std::string &description="")
Register a variable to be handled and populated whenever a new phase space point weight is to be calc...
Definition Process.cpp:149
utils::RandomGenerator & randomGenerator() const
Accessor for this process' random number generator.
Definition Process.cpp:344
virtual std::unique_ptr< Process > clone() const
Copy all process attributes into a new object.
Definition Process.cpp:85
void dumpVariables(std::ostream *=nullptr) const
List all variables handled by this generic process.
Definition Process.cpp:137
Mapping
Type of mapping to apply on the variable.
Definition Process.h:126
@ exponential
an exponential mapping
@ power_law
a power-law mapping inherited from LPAIR
double shat() const
Definition Process.cpp:127
Process(const ParametersList &)
Definition Process.cpp:47
double alphaEM(double q) const
Compute the electromagnetic running coupling algorithm at a given scale.
Definition Process.cpp:350
const Momentum & pB() const
Negative-z incoming beam particle's 4-momentum.
Definition Process.cpp:95
void setEventContent(const std::unordered_map< Particle::Role, spdgids_t > &)
Set the incoming and outgoing states to be defined in this process (and prepare the Event object acco...
Definition Process.cpp:374
Momentum & pc(size_t)
Central particle's 4-momentum.
Definition Process.cpp:113
double weight(const std::vector< double > &)
Compute the weight for a phase-space point.
Definition Process.cpp:236
Event * eventPtr()
Event pointer read/write accessor.
Definition Process.cpp:281
const Momentum & pY() const
Negative-z outgoing beam particle's 4-momentum.
Definition Process.cpp:103
std::unique_ptr< utils::RandomGenerator > rnd_gen_
Process-local random number generator engine.
Definition Process.h:161
virtual double computeWeight()=0
Compute the phase space point weight.
static ParametersDescription description()
Definition Process.cpp:407
void clear()
Reset process prior to the phase space and variables definition.
Definition Process.cpp:129
const Event & event() const
Handled particles objects and their relationships.
Definition Process.cpp:269
size_t ndim() const
Number of dimensions on which the integration is performed.
Definition Process.h:60
double alphaS(double q) const
Compute the strong coupling algorithm at a given scale.
Definition Process.cpp:357
double generateVariables() const
Generate and initialise all variables handled by this process.
Definition Process.cpp:195
const Momentum & q1() const
Positive-z incoming parton's 4-momentum.
Definition Process.cpp:107
Process & operator=(const Process &)
Assignment operator.
Definition Process.cpp:60
double variableValue(size_t i, double x) const
Retrieve the physical value for one variable.
Definition Process.cpp:190
A random number generator.
constexpr double GEVM2_TO_PB
Conversion factor between GeV and barn i.e. in GeV .
Definition Constants.h:37
auto compute_value
Definition Process.cpp:34
std::ostream & operator<<(std::ostream &os, const Process::Mapping &type)
Definition Process.cpp:420
std::string format(const std::string &fmt, Args... args)
Format a string using a printf style format descriptor.
Definition String.h:59
std::string s(const std::string &word, float num, bool show_number)
Add a trailing "s" when needed.
Definition String.cpp:219
bool positive(const T &val)
Check if a number is positive and finite.
Definition Math.cpp:26
std::string merge(const std::vector< T > &vec, const std::string &delim)
Merge a collection of a printable type in a single string.
Definition String.cpp:239
Common namespace for this Monte Carlo generator.