cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
HepMC3EventInterface.cpp
Go to the documentation of this file.
1/*
2 * CepGen: a central exclusive processes event generator
3 * Copyright (C) 2022-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 <HepMC3/FourVector.h>
20#include <HepMC3/GenEvent.h>
21#include <HepMC3/GenParticle.h>
22#include <HepMC3/GenRunInfo.h>
23#include <HepMC3/GenVertex.h>
24#include <HepMC3/Version.h>
25
26#include <list>
27#include <numeric>
28
30#include "CepGen/Event/Event.h"
32#include "CepGen/Physics/PDG.h"
35
36namespace HepMC3 {
37 CepGenEvent::CepGenEvent(const cepgen::Event& evt) : GenEvent(Units::GEV, Units::MM) {
38 add_attribute("AlphaQCD", make_shared<DoubleAttribute>(evt.metadata("alphaS")));
39 add_attribute("AlphaEM", make_shared<DoubleAttribute>(evt.metadata("alphaEM")));
40
41 weights().push_back(1.); // unweighted events
42
43 // filling the particles content
44 const FourVector origin(0., 0., 0., 0.);
45 int cm_id = 0;
46
47 auto v1 = make_shared<GenVertex>(origin), v2 = make_shared<GenVertex>(origin), vcm = make_shared<GenVertex>(origin);
48 unsigned short idx = 0;
49 for (const auto& part_orig : evt.particles()) {
50 const auto& mom_orig = part_orig.momentum();
51 FourVector pmom(mom_orig.px(), mom_orig.py(), mom_orig.pz(), mom_orig.energy());
52 auto part = make_shared<GenParticle>(pmom, part_orig.integerPdgId(), (int)part_orig.status());
53 part->set_generated_mass(cepgen::PDG::get().mass(part_orig.pdgId()));
54 assoc_map_[idx] = part;
55
56 switch (part_orig.role()) {
58 v1->add_particle_in(part);
59 break;
61 v2->add_particle_in(part);
62 break;
64 v1->add_particle_out(part);
65 break;
67 v2->add_particle_out(part);
68 break;
70 v1->add_particle_out(part);
71 vcm->add_particle_in(part);
72 break;
74 v2->add_particle_out(part);
75 vcm->add_particle_in(part);
76 break;
78 // skip the two-parton system and propagate the parentage
79 cm_id = idx;
80 continue;
82 default: {
83 const auto& moth = part_orig.mothers();
84 if (moth.empty())
85 // skip disconnected lines
86 continue;
87 // get mother(s) id(s)
88 const short m1 = *moth.begin();
89 const short m2 = moth.size() > 1 ? *moth.rbegin() : -1;
90 // check if particle is connected to the two-parton system
91 if (m1 == cm_id || (m2 >= 0 && (m1 < cm_id && cm_id <= m2))) // also supports range
92 vcm->add_particle_out(part);
93 // if part of the decay chain of central system, find parents
94 else if (assoc_map_.count(m1) != 0) {
95 auto vprod = assoc_map_.at(m1)->end_vertex();
96 std::list<short> ids{m1}; // list of mother particles
97 if (assoc_map_.count(m2) != 0 && m2 > m1) {
98 ids.resize(m2 - m1 + 1);
99 std::iota(ids.begin(), ids.end(), m1);
100 }
101 if (!vprod) {
102 vprod = make_shared<GenVertex>();
103 for (const auto& id : ids)
104 vprod->add_particle_in(assoc_map_.at(id));
105 add_vertex(vprod);
106 }
107 vprod->add_particle_out(part);
108 } else
109 throw CG_FATAL("HepMC3:fillEvent") << "Other particle requested! Not yet implemented!";
110 } break;
111 }
112 idx++;
113 }
114 add_vertex(v1);
115 add_vertex(v2);
116 add_vertex(vcm);
117 }
118
119 std::ostream& operator<<(std::ostream& os, const FourVector& vec) {
120 return os << "(" << vec.x() << ", " << vec.y() << ", " << vec.z() << "; " << vec.t() << ")";
121 }
122
123 CepGenEvent::operator cepgen::Event() const {
124 cepgen::Event evt;
125 auto convert_particle = [](const GenParticle& part,
126 const cepgen::Particle::Role& role =
128 auto convert_momentum = [](const FourVector& mom) -> cepgen::Momentum {
129 return cepgen::Momentum::fromPxPyPzE(mom.px(), mom.py(), mom.pz(), mom.e());
130 };
131 auto cg_part = cepgen::Particle(role, 0, (cepgen::Particle::Status)part.status());
132 cg_part.setPdgId((long)part.pdg_id());
133 cg_part.setMomentum(convert_momentum(part.momentum()));
134 return cg_part;
135 };
136
137 auto ip1 = beams().at(0), ip2 = beams().at(1);
138 std::unordered_map<size_t, size_t> h_to_cg;
139 std::vector<int> beam_vtx_ids;
140 for (const auto& vtx : vertices()) {
141 if (vtx->particles_in().size() == 1) {
142 auto role1 = cepgen::Particle::Role::UnknownRole, role2 = role1, role3 = role1;
145 size_t id_beam_in = 0;
146 if (auto& part = vtx->particles_in().at(0); part) {
147 if (part->id() == ip1->id()) {
151 } else if (part->id() == ip2->id()) {
155 }
156 auto cg_part = convert_particle(*part, role1);
157 cg_part.setStatus(status1);
158 evt.addParticle(cg_part);
159 h_to_cg[part->id()] = cg_part.id();
160 id_beam_in = cg_part.id();
161 }
162 if (vtx->particles_out_size() == 2) { //FIXME handle cases with multiple partons?
163 size_t num_op = 0;
164 for (auto op : vtx->particles_out()) {
165 auto cg_part = convert_particle(*op, num_op == 0 ? role2 : role3);
166 cg_part.setStatus(num_op == 0 ? status2 : status3);
167 cg_part.addMother(evt[id_beam_in]);
168 evt.addParticle(cg_part);
169 h_to_cg[op->id()] = cg_part.id();
170 ++num_op;
171 }
172 }
173 beam_vtx_ids.emplace_back(vtx->id());
174 }
175 }
176
180 cg_interm.setMomentum(part1.momentum() + part2.momentum(), true);
181 cg_interm.addMother(part1);
182 cg_interm.addMother(part2);
183 evt.addParticle(cg_interm);
184
185 for (const auto& vtx : vertices()) {
186 if (cepgen::utils::contains(beam_vtx_ids, vtx->id()))
187 continue;
188 for (auto op : vtx->particles_out()) {
189 auto cg_part = convert_particle(*op, cepgen::Particle::Role::CentralSystem);
191 evt.addParticle(cg_part);
192 h_to_cg[op->id()] = cg_part.id();
193 }
194 }
195 return evt;
196 }
197
199 // set of sanity checks to perform on the HepMC event content
200 if (vertices().size() < 3) {
201 CG_ERROR("HepMC3:CepGenEvent:merge") << "Failed to retrieve the three primordial vertices in event.";
202 return;
203 }
204 const auto v1 = vertices().at(0), v2 = vertices().at(1), vcm = vertices().at(2);
205 if (v1->particles_in().size() != 1) {
206 CG_ERROR("HepMC3:CepGenEvent:merge") << "Invalid first incoming beam particles multiplicity: found "
207 << v1->particles_in().size() << ", expecting one.";
208 return;
209 }
210 if (v2->particles_in().size() != 1) {
211 CG_ERROR("HepMC3:CepGenEvent:merge") << "Invalid second incoming beam particles multiplicity: found "
212 << v2->particles_in().size() << ", expecting one.";
213 return;
214 }
215 // set of sanity checks to ensure the compatibility between the HepMC and CepGen event records
216 const auto ip1 = v1->particles_in().at(0), ip2 = v2->particles_in().at(0);
217 const auto &cg_ip1 = evt.oneWithRole(cepgen::Particle::Role::IncomingBeam1),
219 if (ip1->momentum().x() != cg_ip1.momentum().px() || ip1->momentum().y() != cg_ip1.momentum().py() ||
220 ip1->momentum().z() != cg_ip1.momentum().pz() || ip1->momentum().t() != cg_ip1.momentum().energy()) {
221 CG_ERROR("HepMC3:CepGenEvent:merge") << "Invalid first incoming beam particle kinematics.";
222 return;
223 }
224 if (ip2->momentum().x() != cg_ip2.momentum().px() || ip2->momentum().y() != cg_ip2.momentum().py() ||
225 ip2->momentum().z() != cg_ip2.momentum().pz() || ip2->momentum().t() != cg_ip2.momentum().energy()) {
226 CG_ERROR("HepMC3:CepGenEvent:merge") << "Invalid second incoming beam particle kinematics.";
227 return;
228 }
230 if (cs.size() != (size_t)vcm->particles_out().size()) {
231 CG_ERROR("HepMC3:CepGenEvent:merge")
232 << "Central system particles multiplicities differ between CepGen and HepMC3 event records.";
233 return;
234 }
235 // freeze the "primordial" central system size
236 const auto cs_size = cs.size();
237
238 // helper function to browse particles decay products and store them into the CepGen event content
239 std::function<void(const ConstGenParticlePtr& hp, cepgen::ParticleRef cp)> browse_children =
240 [&](const ConstGenParticlePtr& hp, cepgen::ParticleRef cp) {
241 if (hp->children().empty())
242 return;
243 cp.get().setStatus(cepgen::Particle::Status::Propagator);
244 for (const auto& h_child : hp->children()) {
245 cepgen::Particle cg_child(cp.get().role(), 0);
246 cg_child.setPdgId((long)h_child->pdg_id());
247 const auto& c_mom = h_child->momentum();
249 cg_child.setMomentum(cepgen::Momentum::fromPxPyPzE(c_mom.x(), c_mom.y(), c_mom.z(), c_mom.t()));
250 cg_child.addMother(cp);
251 browse_children(h_child, evt.addParticle(cg_child));
252 }
253 };
254
255 for (size_t icg = 0; icg < cs_size; ++icg) { // try to find the associated CepGen event particle
256 const auto cg_cp_mom3 = cs[icg].get().momentum().p();
257 for (const auto& h_cp : vcm->particles_out()) { // loop over the central system particles
258 if (fabs(cg_cp_mom3 - h_cp->momentum().length()) > 1.e-10)
259 continue;
260 // found the association between the HepMC and CepGen particles kinematics
261 browse_children(h_cp, cs[icg]);
262 break;
263 }
264 }
265 }
266
267 void CepGenEvent::dump() const {
268 CG_LOG.log([&](auto& log) {
269 log << "HepMC3::CepGenEvent\n"
270 << " Attributes:\n";
271 for (const auto& attr : {"AlphaEM", "AlphaQCD"})
272 log << " * " << attr << " = " << attribute_as_string(attr) << "\n";
273 log << " Vertices:";
274 for (const auto& vtxPtr : vertices()) {
275 FourVector in_sys, out_sys;
276 log << "\n * vertex#" << (-vtxPtr->id()) << " (status: " << vtxPtr->status() << ")"
277 << "\n in: ";
278 for (const auto& ipPtr : vtxPtr->particles_in())
279 log << "\n * " << ipPtr->pdg_id() << " (status: " << ipPtr->status() << "): " << ipPtr->momentum(),
280 in_sys += ipPtr->momentum();
281 log << "\n total: " << in_sys << "\n out:";
282 for (const auto& opPtr : vtxPtr->particles_out())
283 log << "\n * " << opPtr->pdg_id() << " (status: " << opPtr->status() << "): " << opPtr->momentum(),
284 out_sys += opPtr->momentum();
285 const auto imbal = in_sys - out_sys;
286 log << "\n total: " << out_sys << "\n (im)balance: " << imbal << " (norm: " << imbal.length() << ").";
287 }
288 log << "\n" << std::string(70, '-');
289 });
290 }
291} // namespace HepMC3
#define CG_FATAL(mod)
Definition Exception.h:61
#define CG_ERROR(mod)
Definition Exception.h:60
#define CG_LOG
Definition Message.h:212
void merge(cepgen::Event &) const
Merge this event with another CepGen event record.
CepGenEvent(const cepgen::Event &)
Construct an event interface from a CepGen Event object.
void dump() const
Write the event content in the standard stream.
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:190
ParticleRef addParticle(Particle &part, bool replace=false)
Set the information on one particle in the process.
Definition Event.cpp:323
Particles particles() const
Vector of all particles in the event.
Definition Event.cpp:353
EventMetadata metadata
List of auxiliary information.
Definition Event.h:136
Container for a particle's 4-momentum, along with useful methods to ease the development of any matri...
Definition Momentum.h:33
static Momentum fromPxPyPzE(double px, double py, double pz, double e)
Build a 4-momentum from its four momentum and energy coordinates.
Definition Momentum.cpp:82
static PDG & get()
Retrieve a unique instance of this particles info collection.
Definition PDG.cpp:41
Kinematic information for one particle.
Definition Particle.h:33
Momentum & momentum()
Retrieve the momentum object associated with this particle Retrieve the momentum object associated wi...
Definition Particle.h:123
Particle & setMomentum(const Momentum &, bool offshell=false)
Associate a momentum object to this particle.
Definition Particle.cpp:77
Particle & addMother(Particle &part)
Set the mother particle.
Definition Particle.cpp:47
Status
Internal status code for a particle.
Definition Particle.h:36
@ PrimordialIncoming
Incoming beam particle.
@ Incoming
Incoming parton.
@ FinalState
Stable, final state particle.
@ Unfragmented
Particle to be hadronised externally.
@ Propagator
Generic propagator.
@ 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
@ UnknownRole
Undefined role.
Definition Particle.h:51
@ 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 & setStatus(Status status)
Definition Particle.h:96
Particle & setPdgId(pdgid_t pdg, short ch=0)
Set the PDG identifier (along with the particle's electric charge)
Definition Particle.cpp:93
std::ostream & operator<<(std::ostream &os, const FourVector &vec)
bool contains(const std::vector< T > &coll, const T &item)
Check if a vector contains an item.
Definition Collections.h:47
std::reference_wrapper< Particle > ParticleRef
Reference to a Particle object.
Definition Particle.h:168