cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.3
A generic central exclusive processes event generator
Loading...
Searching...
No Matches
Event.cpp
Go to the documentation of this file.
1/*
2 * CepGen: a central exclusive processes event generator
3 * Copyright (C) 2013-2023 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 <algorithm>
20#include <cmath>
21
23#include "CepGen/Event/Event.h"
25#include "CepGen/Physics/PDG.h"
26#include "CepGen/Utils/String.h"
27
28namespace cepgen {
29 Event::Event(bool compressed) : compressed_(compressed) {}
30
31 Event::Event(const Event& oth) { *this = oth; }
32
34 clear();
35 particles_ = oth.particles_;
36 evtcontent_ = oth.evtcontent_;
37 compressed_ = oth.compressed_;
38 metadata = oth.metadata;
39 return *this;
40 }
41
42 Event Event::minimal(size_t num_out_particles) {
43 auto evt = Event();
44 // add the two incoming beam particles
45 auto ib1 = evt.addParticle(Particle::Role::IncomingBeam1);
46 ib1.get().setStatus(Particle::Status::PrimordialIncoming);
47 auto ib2 = evt.addParticle(Particle::Role::IncomingBeam2);
48 ib2.get().setStatus(Particle::Status::PrimordialIncoming);
49
50 // add the two incoming partons
51 auto part1 = evt.addParticle(Particle::Role::Parton1);
52 part1.get().setStatus(Particle::Status::Incoming);
53 part1.get().addMother(ib1);
54 auto part2 = evt.addParticle(Particle::Role::Parton2);
55 part2.get().setStatus(Particle::Status::Incoming);
56 part2.get().addMother(ib2);
57 // add the two-parton system
58 auto twopart = evt.addParticle(Particle::Role::Intermediate);
59 twopart.get().setStatus(Particle::Status::Propagator);
60 twopart.get().addMother(part1);
61 twopart.get().addMother(part2);
62
63 // add the two outgoing beam particles
64 auto ob1 = evt.addParticle(Particle::Role::OutgoingBeam1);
65 ob1.get().setStatus(Particle::Status::FinalState);
66 ob1.get().addMother(ib1);
67 auto ob2 = evt.addParticle(Particle::Role::OutgoingBeam2);
68 ob2.get().setStatus(Particle::Status::FinalState);
69 ob2.get().addMother(ib2);
70
71 // finally add the central system
72 for (size_t i = 0; i < num_out_particles; ++i) {
73 auto cs = evt.addParticle(Particle::Role::CentralSystem);
74 cs.get().setStatus(Particle::Status::FinalState);
75 cs.get().addMother(twopart);
76 }
77 return evt;
78 }
79
80 void Event::clear() {
81 particles_.clear();
82 metadata.clear();
83 }
84
86 if (particles_.count(Particle::CentralSystem) > 0)
87 evtcontent_.cs = particles_[Particle::CentralSystem].size();
88 if (particles_.count(Particle::OutgoingBeam1) > 0)
89 evtcontent_.op1 = particles_[Particle::OutgoingBeam1].size();
90 if (particles_.count(Particle::OutgoingBeam2) > 0)
91 evtcontent_.op2 = particles_[Particle::OutgoingBeam2].size();
92 }
93
95 if (particles_.count(Particle::CentralSystem) > 0)
96 particles_[Particle::CentralSystem].resize(evtcontent_.cs);
97 if (particles_.count(Particle::OutgoingBeam1) > 0)
98 particles_[Particle::OutgoingBeam1].resize(evtcontent_.op1);
99 if (particles_.count(Particle::OutgoingBeam2) > 0)
100 particles_[Particle::OutgoingBeam2].resize(evtcontent_.op2);
101 }
102
103 bool Event::compressed() const { return compressed_; }
104
106 if (compressed_)
107 return *this;
108 Event out(/*compressed=*/true);
109 int i = 0;
110 //--- add all necessary particles
111 for (const auto& role : {Particle::IncomingBeam1,
118 if (particles_.count(role) == 0)
119 continue;
120 for (const auto& old_part : operator()(role)) {
121 auto& new_part = out.addParticle(role).get();
122 new_part = old_part; // copy all attributes
123 new_part.setId(i++);
124 new_part.clearMothers();
125 new_part.clearDaughters();
126 }
127 }
128 //--- fix parentage for outgoing beam particles
129 if (out[Particle::OutgoingBeam1].size() > 1 || out[Particle::OutgoingBeam2].size() > 1)
130 CG_WARNING("Event:compress") << "Event compression not designed for already fragmented beam remnants!\n\t"
131 << "Particles parentage is not guaranteed to be conserved.";
132 if (particles_.count(Particle::OutgoingBeam1) > 0)
133 for (auto& part : out[Particle::OutgoingBeam1])
134 part.get().addMother(out[Particle::IncomingBeam1][0].get());
135 if (particles_.count(Particle::OutgoingBeam2) > 0)
136 for (auto& part : out[Particle::OutgoingBeam2])
137 part.get().addMother(out[Particle::IncomingBeam2][0].get());
138 //--- fix parentage for incoming partons
139 for (auto& part : out[Particle::Parton1])
140 if (particles_.count(Particle::IncomingBeam1) > 0)
141 part.get().addMother(out[Particle::IncomingBeam1][0].get());
142 if (particles_.count(Particle::IncomingBeam2) > 0)
143 for (auto& part : out[Particle::Parton2])
144 part.get().addMother(out[Particle::IncomingBeam2][0].get());
145 //--- fix parentage for central system
146 if (particles_.count(Particle::Parton1) > 0 && particles_.count(Particle::Parton2) > 0)
147 for (auto& part : out[Particle::CentralSystem]) {
148 part.get().addMother(out[Particle::Parton1][0]);
149 part.get().addMother(out[Particle::Parton2][0]);
150 }
151 return out;
152 }
153
155 ParticlesRefs out;
156 //--- retrieve all particles with a given role
157 for (auto& part : particles_[role])
158 out.emplace_back(std::ref(part));
159 return out;
160 }
161
163 if (particles_.count(role) == 0)
164 throw CG_FATAL("Event") << "Failed to retrieve a particle with " << role << " role.";
165 //--- retrieve all particles with a given role
166 return particles_.at(role);
167 }
168
170 ParticlesIds out;
171 //--- retrieve all particles ids with a given role
172 if (particles_.count(role) == 0)
173 return out;
174
175 for (const auto& part : particles_.at(role))
176 out.insert(part.id());
177
178 return out;
179 }
180
182 //--- retrieve the first particle of a given role
183 auto parts_by_role = operator[](role);
184 if (parts_by_role.empty())
185 throw CG_FATAL("Event") << "No particle retrieved with " << role << " role.";
186 if (parts_by_role.size() > 1)
187 throw CG_FATAL("Event") << "More than one particle with " << role << " role: " << parts_by_role.size()
188 << " particles.";
189 return parts_by_role.front().get();
190 }
191
193 //--- retrieve the first particle of a given role
194 const Particles& parts_by_role = operator()(role);
195 if (parts_by_role.empty())
196 throw CG_FATAL("Event") << "No particle retrieved with " << role << " role.";
197 if (parts_by_role.size() > 1)
198 throw CG_FATAL("Event") << "More than one particle with " << role << " role: " << parts_by_role.size()
199 << " particles";
200 return *parts_by_role.begin();
201 }
202
204 for (auto& role_part : particles_)
205 for (auto& part : role_part.second)
206 if (part.id() == id)
207 return part;
208
209 throw CG_FATAL("Event") << "Failed to retrieve the particle with id=" << id << ".";
210 }
211
212 const Particle& Event::operator()(int id) const {
213 for (const auto& role_part : particles_) {
214 auto it = std::find_if(
215 role_part.second.begin(), role_part.second.end(), [&id](const auto& part) { return part.id() == id; });
216 if (it != role_part.second.end())
217 return *it;
218 }
219
220 throw CG_FATAL("Event") << "Failed to retrieve the particle with id=" << id << ".";
221 }
222
224 ParticlesRefs out;
225 std::transform(ids.begin(), ids.end(), std::back_inserter(out), [this](const auto& id) {
226 return std::ref(this->operator[](id));
227 });
228 return out;
229 }
230
232 Particles out;
233 std::transform(
234 ids.begin(), ids.end(), std::back_inserter(out), [this](const auto& id) { return this->operator()(id); });
235 return out;
236 }
237
238 Particles Event::mothers(const Particle& part) const { return operator()(part.mothers()); }
239
240 ParticlesRefs Event::mothers(const Particle& part) { return operator[](part.mothers()); }
241
242 Particles Event::daughters(const Particle& part) const { return operator()(part.daughters()); }
243
245
246 Particles Event::stableDaughters(const Particle& part, bool recursive) const {
247 Particles parts;
248 for (const auto& daugh : operator()(part.daughters())) {
249 if (daugh.status() == Particle::Status::FinalState)
250 parts.emplace_back(daugh);
251 else if (recursive) {
252 const auto daugh_daugh = stableDaughters(daugh, recursive);
253 parts.insert(
254 parts.end(), std::make_move_iterator(daugh_daugh.begin()), std::make_move_iterator(daugh_daugh.end()));
255 }
256 }
257 return parts;
258 }
259
260 ParticlesRefs Event::stableDaughters(const Particle& part, bool recursive) {
261 ParticlesRefs parts;
262 for (const auto& daugh : operator[](part.daughters())) {
263 if (daugh.get().status() == Particle::Status::FinalState)
264 parts.emplace_back(daugh);
265 else if (recursive) {
266 const auto daugh_daugh = stableDaughters(daugh, recursive);
267 parts.insert(
268 parts.end(), std::make_move_iterator(daugh_daugh.begin()), std::make_move_iterator(daugh_daugh.end()));
269 }
270 }
271 return parts;
272 }
273
275 ParticleRoles out;
276 std::transform(
277 particles_.begin(), particles_.end(), std::back_inserter(out), [](const auto& pr) { return pr.first; });
278 return out;
279 }
280
282 CG_DEBUG_LOOP("Event") << "Particle with PDGid = " << part.integerPdgId() << " has role " << part.role();
283 if (part.role() <= 0)
284 throw CG_FATAL("Event") << "Trying to add a particle with role=" << (int)part.role() << ".";
285
286 auto& part_with_same_role = particles_[part.role()]; // list of particles with the same role
287 if (part.id() < 0)
288 part.setId(part_with_same_role.empty() || !replace
289 ? size() // set the id if previously invalid/non-existent
290 : part_with_same_role[0].id()); // set the previous id if replacing a particle
291 if (replace)
292 part_with_same_role = {part};
293 else
294 part_with_same_role.emplace_back(part);
295 return std::ref(part_with_same_role.back());
296 }
297
299 Particle np(role, PDG::invalid);
300 return addParticle(np, replace);
301 }
302
303 size_t Event::size() const {
304 return std::accumulate(particles_.begin(), particles_.end(), 0, [](size_t size, const auto& role_part) {
305 return size + role_part.second.size();
306 });
307 }
308
309 bool Event::empty() const { return particles_.empty(); }
310
312 Particles out;
313 for (const auto& role_part : particles_)
314 out.insert(out.end(), role_part.second.begin(), role_part.second.end());
315
316 std::sort(out.begin(), out.end());
317 return out;
318 }
319
321 Particles out;
322 for (const auto& role_part : particles_)
323 std::copy_if(role_part.second.begin(), role_part.second.end(), std::back_inserter(out), [](const auto& part) {
324 return (short)part.status() > 0;
325 });
326
327 std::sort(out.begin(), out.end());
328 return out;
329 }
330
332 Momentum me;
333 for (const auto& cp : operator()(Particle::Role::CentralSystem))
334 if (cp.status() == Particle::Status::FinalState) {
335 const auto pdg = cp.integerPdgId();
336 if (pdg == 12 || pdg == 14 || pdg == 16) // neutrinos
337 me += cp.momentum();
338 if (pdg == 1000022 || pdg == 1000023 || pdg == 1000025 || 1000035) // neutralinos
339 me += cp.momentum();
340 }
341 return me;
342 }
343
344 void Event::checkKinematics() const {
345 // check the kinematics through parentage
346 for (const auto& part : particles()) {
347 ParticlesIds daughters = part.daughters();
348 if (daughters.empty())
349 continue;
350 Momentum ptot;
351 for (const auto& daughter : daughters) {
352 const auto& d = operator()(daughter);
353 const auto mothers = d.mothers();
354 ptot += d.momentum();
355 if (mothers.size() < 2)
356 continue;
357 for (const auto& moth : mothers)
358 if (moth != part.id())
359 ptot -= operator()(moth).momentum();
360 }
361 const double mass_diff = (ptot - part.momentum()).mass();
362 if (fabs(mass_diff) > MIN_PRECISION) {
363 dump();
364 throw CG_FATAL("Event") << "Error in momentum balance for particle " << part.id() << ": mdiff = " << mass_diff
365 << ".";
366 }
367 }
368 }
369
370 void Event::dump() const { CG_INFO("Event") << *this; }
371
372 std::ostream& operator<<(std::ostream& out, const Event& ev) {
373 const auto parts = ev.particles();
374 std::ostringstream os;
375
376 Momentum p_total;
377 for (const auto& part : parts) {
378 const ParticlesIds mothers = part.mothers();
379 {
380 std::ostringstream oss_pdg;
381 if (part.pdgId() == PDG::invalid && !mothers.empty()) {
382 //--- if particles compound
383 std::string delim;
384 for (size_t i = 0; i < mothers.size(); ++i)
385 try {
386 oss_pdg << delim << (PDG::Id)ev(*std::next(mothers.begin(), i)).pdgId(), delim = "/";
387 } catch (const Exception&) {
388 oss_pdg << delim << ev(*std::next(mothers.begin(), i)).pdgId(), delim = "/";
389 }
390 os << utils::format("\n %2d\t\t %-7s", part.id(), oss_pdg.str().c_str());
391 } else {
392 //--- if single particle/HI
393 if (HeavyIon::isHI(part.pdgId()))
394 oss_pdg << HeavyIon::fromPdgId(part.pdgId());
395 else
396 try {
397 oss_pdg << (PDG::Id)part.pdgId();
398 } catch (const Exception&) {
399 oss_pdg << "?";
400 }
401 os << utils::format("\n %2d\t%-+10d %-7s", part.id(), part.integerPdgId(), oss_pdg.str().c_str());
402 }
403 }
404 os << "\t";
405 if (part.charge() != (int)part.charge()) {
406 if (part.charge() * 2 == (int)(part.charge() * 2))
407 os << utils::format("%-d/2", (int)(part.charge() * 2));
408 else if (part.charge() * 3 == (int)(part.charge() * 3))
409 os << utils::format("%-d/3", (int)(part.charge() * 3));
410 else
411 os << utils::format("%-.2f", part.charge());
412 } else
413 os << utils::format("%-g", part.charge());
414 os << "\t";
415 {
416 std::ostringstream oss;
417 oss << part.role();
418 os << utils::format("%-8s %6d\t", oss.str().c_str(), part.status());
419 }
420 if (!mothers.empty()) {
421 std::ostringstream oss;
422 unsigned short i = 0;
423 for (const auto& moth : mothers) {
424 oss << (i > 0 ? "+" : "") << moth;
425 ++i;
426 }
427 os << utils::format("%6s ", oss.str().c_str());
428 } else
429 os << " ";
430 const auto& mom = part.momentum();
431 os << utils::format(
432 "% 9.6e % 9.6e % 9.6e % 9.6e % 12.5f", mom.px(), mom.py(), mom.pz(), mom.energy(), mom.mass());
433
434 // discard non-primary, decayed particles
435 if (part.status() >= Particle::Status::Undefined) {
436 const int sign = (part.status() == Particle::Status::Undefined) ? -1 : +1;
437 p_total += sign * mom;
438 }
439 }
440 //--- set a threshold to the computation precision
441 p_total.truncate();
442 //
443 return out << utils::format(
444 "Event content:\n"
445 " Id\tPDG id\t Name\t\tCharge\tRole\t Status\tMother\tpx py pz E "
446 " "
447 " \t M \n"
448 " --\t------\t ----\t\t------\t----\t ------\t------\t----GeV/c--- ----GeV/c--- ----GeV/c--- "
449 "----GeV/c---\t --GeV/c²--"
450 "%s\n"
451 " ----------------------------------------------------------------------------------------------------"
452 "--"
453 "----------------------------\n"
454 "\t\t\t\t\t\t\tBalance% 9.6e % 9.6e % 9.6e % 9.6e",
455 os.str().c_str(),
456 p_total.px(),
457 p_total.py(),
458 p_total.pz(),
459 p_total.energy());
460 }
461
463 : std::unordered_map<std::string, float>{{"time:generation", -1.f},
464 {"time:total", -1.f},
465 {"weight", 1.f},
466 {"alphaEM", (float)constants::ALPHA_EM},
467 {"alphaS", (float)constants::ALPHA_QCD}} {}
468} // namespace cepgen
#define CG_FATAL(mod)
Definition Exception.h:61
#define CG_WARNING(mod)
Definition Message.h:228
#define CG_DEBUG_LOOP(mod)
Definition Message.h:224
#define CG_INFO(mod)
Definition Message.h:216
Container for the information on the in- and outgoing particles' kinematics.
Definition Event.h:28
Particles stableParticles() const
Vector of all stable particles in the event.
Definition Event.cpp:320
Event compress() const
Compress the event record.
Definition Event.cpp:105
const Particles & operator()(Particle::Role role) const
Get a list of constant Particle objects corresponding to a certain role in the process kinematics.
Definition Event.cpp:162
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
ParticleRoles roles() const
List of roles defined for the given event (really process-dependant for the central system)
Definition Event.cpp:274
ParticlesIds ids(Particle::Role role) const
Get a list of particle identifiers in Event corresponding to a certain role in the process kinematics...
Definition Event.cpp:169
bool empty() const
Is the particles map empty?
Definition Event.cpp:309
Momentum missingMomentum() const
Compute the missing momentum for central particles in this event.
Definition Event.cpp:331
Particles daughters(const Particle &part) const
List of all the daughters from a particle.
Definition Event.cpp:242
ParticleRef addParticle(Particle &part, bool replace=false)
Set the information on one particle in the process.
Definition Event.cpp:281
Particles particles() const
Vector of all particles in the event.
Definition Event.cpp:311
EventMetadata metadata
List of auxiliary information.
Definition Event.h:129
Event(bool compressed=false)
Build an empty event.
Definition Event.cpp:29
bool compressed() const
Is the event already without intermediate-channel information?
Definition Event.cpp:103
Particles stableDaughters(const Particle &part, bool recursive=false) const
List all the stable daughters of a particle in this event.
Definition Event.cpp:246
void freeze()
Store a snapshot of the primordial event block.
Definition Event.cpp:85
Particles mothers(const Particle &part) const
List of all parent Particle object for this given particle.
Definition Event.cpp:238
void clear()
Empty the whole event content.
Definition Event.cpp:80
ParticlesRefs operator[](Particle::Role role)
List of references to Particle objects corresponding to a certain role in the process kinematics.
Definition Event.cpp:154
Event & operator=(const Event &)
Assignment operator.
Definition Event.cpp:33
void dump() const
Dump all the known information on every Particle object contained in this Event container in the outp...
Definition Event.cpp:370
static Event minimal(size_t num_out_particles=1)
Build a trivial event with the minimal information.
Definition Event.cpp:42
void restore()
Restore the event to its "empty" state.
Definition Event.cpp:94
Container for a particle's 4-momentum, along with useful methods to ease the development of any matri...
Definition Momentum.h:33
double pz() const
Longitudinal momentum (in GeV)
Definition Momentum.h:120
double px() const
Momentum along the -axis (in GeV)
Definition Momentum.h:112
double py() const
Momentum along the -axis (in GeV)
Definition Momentum.h:116
Momentum & truncate(double tolerance=1.e-10)
Apply a threshold to all values with a given tolerance.
Definition Momentum.cpp:198
double energy() const
Energy (in GeV)
Definition Momentum.h:136
A class-in-the-middle PDG identifier for printout operations.
Definition PDG.h:55
@ invalid
Definition PDG.h:34
Kinematic information for one particle.
Definition Particle.h:33
ParticlesIds daughters() const
Number of daughter particles.
Definition Particle.h:150
long integerPdgId() const
Retrieve the integer value of the PDG identifier.
Definition Particle.cpp:132
@ PrimordialIncoming
Incoming beam particle.
@ Incoming
Incoming parton.
@ FinalState
Stable, final state particle.
@ Propagator
Generic propagator.
@ Undefined
Undefined particle.
int id() const
Unique identifier (in a Event object context) Set the particle unique identifier in an event.
Definition Particle.h:77
ParticlesIds mothers() const
Identifier to the mother particles.
Definition Particle.h:146
@ 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
Particle & setId(int id)
Definition Particle.h:79
Role role() const
Role in the considered process Set the particle role in the process.
Definition Particle.h:89
constexpr double ALPHA_QCD
Strong coupling constant .
Definition Constants.h:34
constexpr double ALPHA_EM
Electromagnetic coupling constant .
Definition Constants.h:28
std::string format(const std::string &fmt, Args... args)
Format a string using a printf style format descriptor.
Definition String.h:59
Common namespace for this Monte Carlo generator.
std::vector< Particle::Role > ParticleRoles
List of particles' roles.
Definition Particle.h:174
std::reference_wrapper< Particle > ParticleRef
Reference to a Particle object.
Definition Particle.h:171
std::set< int > ParticlesIds
A set of integer-type particle identifiers.
Definition Particle.h:30
std::vector< ParticleRef > ParticlesRefs
List of references to Particle objects.
Definition Particle.h:173
std::ostream & operator<<(std::ostream &os, const Exception::Type &type)
Definition Exception.cpp:59
std::vector< Particle > Particles
List of Particle objects.
Definition Particle.h:172
static HeavyIon fromPdgId(pdgid_t)
Build from a custom PDG id.
Definition HeavyIon.cpp:34
static bool isHI(const spdgid_t &)
Check if the PDG id is compatible with a HI.
Definition HeavyIon.cpp:54