HepMC3 event record library
HEPEVT_Helpers.h
Go to the documentation of this file.
1// -*- C++ -*-
2//
3// This file is part of HepMC
4// Copyright (C) 2014-2023 The HepMC collaboration (see AUTHORS for details)
5//
6#ifndef HEPEVT_HELPERS_H
7#define HEPEVT_HELPERS_H
8/**
9 * @file HEPEVT_Helpers.h
10 * @brief Helper functions used to manipulate with HEPEVT block
11 *
12 */
13#if defined(WIN32)&&(!defined(HEPMC3_NO_EXPORTS))
14#if defined(HepMC3_EXPORTS)
15#define HEPMC3_EXPORT_API __declspec(dllexport)
16#else
17#define HEPMC3_EXPORT_API __declspec(dllimport)
18#endif
19#else
20#define HEPMC3_EXPORT_API
21#endif
22#include <algorithm>
23#include <map>
24
25#include "HepMC3/GenEvent.h"
26#include "HepMC3/GenParticle.h"
27#include "HepMC3/GenVertex.h"
28namespace HepMC3
29{
30
31/** @struct HEPEVT_Templated
32 * @brief C structure representing Fortran common block HEPEVT
33 * T. Sjöstrand et al., "A proposed standard event record",
34 * in `Z physics at LEP 1', eds. G. Altarelli, R. Kleiss and C. Verzegnassi,
35 * Geneva, Switzerland, September 4-5, 1989, CERN 89-08 (Geneva, 1989), Vol. 3, p. 327
36 * Disk representation is given by Fortran WRITE/READ format.
37 */
38template <int max_particles, typename momentum_type = double>
39struct HEPEVT_Templated
40{
41 int nevhep; //!< Event number
42 int nhep; //!< Number of entries in the event
43 int isthep[max_particles]; //!< Status code
44 int idhep [max_particles]; //!< PDG ID
45 int jmohep[max_particles][2]; //!< Position of 1st and 2nd (or last!) mother
46 int jdahep[max_particles][2]; //!< Position of 1nd and 2nd (or last!) daughter
47 momentum_type phep [max_particles][5]; //!< Momentum: px, py, pz, e, m
48 momentum_type vhep [max_particles][4]; //!< Time-space position: x, y, z, t
49};
51/** @struct HEPEVT_Templated
52 * @brief C structure representing Fortran common block HEPEVT
53 * T. Sjöstrand et al., "A proposed standard event record",
54 * in `Z physics at LEP 1', eds. G. Altarelli, R. Kleiss and C. Verzegnassi,
55 * Geneva, Switzerland, September 4-5, 1989, CERN 89-08 (Geneva, 1989), Vol. 3, p. 327
56 * Disk representation is given by Fortran WRITE/READ format.
57 */
58template <int max_particles, typename momentum_type = double>
59struct HEPEVT_Templated_Simple
60{
61 int nevhep; //!< Event number
62 int nhep; //!< Number of entries in the event
63 int isthep[max_particles]; //!< Status code
64 int idhep [max_particles]; //!< PDG ID
65 int jmohep[max_particles*2]; //!< Position of 1st and 2nd (or last!) mother
66 int jdahep[max_particles*2]; //!< Position of 1nd and 2nd (or last!) daughter
67 momentum_type phep [max_particles*5]; //!< Momentum: px, py, pz, e, m
68 momentum_type vhep [max_particles*4]; //!< Time-space position: x, y, z, t
69};
70
71/** @struct HEPEVT_Pointers
72 * @brief C structure representing Fortran common block HEPEVT
73 * T. Sjöstrand et al., "A proposed standard event record",
74 * in `Z physics at LEP 1', eds. G. Altarelli, R. Kleiss and C. Verzegnassi,
75 * Geneva, Switzerland, September 4-5, 1989, CERN 89-08 (Geneva, 1989), Vol. 3, p. 327
76 * Disk representation is given by Fortran WRITE/READ format.
77 */
78template<typename momentum_type = double>
79struct HEPEVT_Pointers
80{
81 int* nevhep; //!< Pointer to Event number
82 int* nhep; //!< Pointer to Number of entries in the event
83 int* isthep; //!< Pointer to Status code
84 int* idhep; //!< Pointer to PDG ID
85 int* jmohep; //!< Pointer to position of 1st and 2nd (or last!) mother
86 int* jdahep; //!< Pointer to position of 1nd and 2nd (or last!) daughter
87 momentum_type* phep; //!< Pointer to momentum: px, py, pz, e, m
88 momentum_type* vhep; //!< Pointer to time-space position: x, y, z, t
89};
90
91/** @brief comparison of two particles */
93{
94 /** @brief comparison of two particles */
95 bool operator()(ConstGenParticlePtr lx, ConstGenParticlePtr rx) const;
96};
97/** @brief Order vertices with equal paths. */
99{
100 /** @brief Order vertices with equal paths. If the paths are equal, order in other quantities.
101 * We cannot use id, as it can be assigned in different way*/
102 bool operator()(const std::pair<ConstGenVertexPtr, int>& lx, const std::pair<ConstGenVertexPtr, int>& rx) const;
103};
104/** @brief Calculates the path to the top (beam) particles */
105void calculate_longest_path_to_top(ConstGenVertexPtr v, std::map<ConstGenVertexPtr, int>& pathl);
106
107
108/** @brief Converts HEPEVT into GenEvent. */
109template <class T>
111{
112 if ( !evt ) { std::cerr << "HEPEVT_to_GenEvent_nonstatic - passed null event." << std::endl; return false;}
113 evt->set_event_number(A->event_number());
114 std::map<GenParticlePtr, int > hepevt_particles;
115 std::map<int, GenParticlePtr > particles_index;
116 std::map<GenVertexPtr, std::pair<std::set<int>, std::set<int> > > hepevt_vertices;
117 std::map<int, GenVertexPtr > vertex_index;
118 int ne=0;
119 ne=A->number_entries();
120 for ( int i = 1; i <= ne; i++ )
121 {
122 GenParticlePtr p = std::make_shared<GenParticle>();
123 p->set_momentum(FourVector(A->px(i), A->py(i), A->pz(i), A->e(i)));
124 p->set_status(A->status(i));
125 p->set_pid(A->id(i)); //Confusing!
126 p->set_generated_mass(A->m(i));
127 hepevt_particles[p] = i;
128 particles_index[i] = p;
129 GenVertexPtr v = std::make_shared<GenVertex>();
130 v->set_position(FourVector(A->x(i), A->y(i), A->z(i), A->t(i)));
131 v->add_particle_out(p);
132 std::set<int> in;
133 std::set<int> out;
134 out.insert(i);
135 vertex_index[i] = v;
136 hepevt_vertices[v] = std::pair<std::set<int>, std::set<int> >(in, out);
137 }
138 /* The part above is always correct as it is a raw information without any topology.*/
139
140 /* In this way we trust mother information. The "Trust daughters" is not implemented.*/
141 for (std::map<GenParticlePtr, int >::iterator it1 = hepevt_particles.begin(); it1 != hepevt_particles.end(); ++it1)
142 for (std::map<GenParticlePtr, int >::iterator it2 = hepevt_particles.begin(); it2 != hepevt_particles.end(); ++it2) {
143 if (A->first_parent(it2->second) <= it1->second && it1->second <= A->last_parent(it2->second)) hepevt_vertices[it2->first->production_vertex()].first.insert(it1->second);
144 }
145 /* Now all incoming sets are correct for all vertices. But we have duplicates.*/
146
147 /* Disconnect all particles from the vertices*/
148 for ( int i = 1; i <= A->number_entries(); i++ ) vertex_index[i]->remove_particle_out(particles_index[i]);
149
150 /*Fill container with vertices with unique sets of incoming particles. Merge the outcoming particle sets.*/
151 std::map<GenVertexPtr, std::pair<std::set<int>, std::set<int> > > final_vertices_map;
152 for (std::map<GenVertexPtr, std::pair<std::set<int>, std::set<int> > >::iterator vs = hepevt_vertices.begin(); vs != hepevt_vertices.end(); ++vs)
153 {
154 if ((final_vertices_map.size() == 0) || (vs->second.first.size() == 0 && vs->second.second.size() != 0)) { final_vertices_map.insert(*vs); continue; } /*Always insert particles out of nowhere*/
155 std::map<GenVertexPtr, std::pair<std::set<int>, std::set<int> > >::iterator v2;
156 for (v2 = final_vertices_map.begin(); v2 != final_vertices_map.end(); ++v2) if (vs->second.first == v2->second.first) {v2->second.second.insert(vs->second.second.begin(), vs->second.second.end()); break;}
157 if (v2 == final_vertices_map.end()) final_vertices_map.insert(*vs);
158 }
159
160 std::vector<GenParticlePtr> final_particles;
161 std::set<int> used;
162 for (std::map<GenVertexPtr, std::pair<std::set<int>, std::set<int> > >:: iterator it = final_vertices_map.begin(); it != final_vertices_map.end(); ++it)
163 {
164 GenVertexPtr v = it->first;
165 std::set<int> in = it->second.first;
166 std::set<int> out = it->second.second;
167 used.insert(in.begin(), in.end());
168 used.insert(out.begin(), out.end());
169 for (std::set<int>::iterator el = in.begin(); el != in.end(); ++el) v->add_particle_in(particles_index[*el]);
170 if (in.size() !=0 ) for (std::set<int>::iterator el = out.begin(); el != out.end(); ++el) v->add_particle_out(particles_index[*el]);
171 }
172 for (std::set<int>::iterator el = used.begin(); el != used.end(); ++el) final_particles.push_back(particles_index[*el]);
173 /* One can put here a check on the number of particles/vertices*/
174
175 evt->add_tree(final_particles);
176
177 return true;
178}
179/** @brief Converts GenEvent into HEPEVT. */
180template <class T>
182{
183 /// This writes an event out to the HEPEVT common block. The daughters
184 /// field is NOT filled, because it is possible to contruct graphs
185 /// for which the mothers and daughters cannot both be make sequential.
186 /// This is consistent with how pythia fills HEPEVT (daughters are not
187 /// necessarily filled properly) and how IO_HEPEVT reads HEPEVT.
188 if ( !evt ) return false;
189
190 /*AV Sorting the vertices by the lengths of their longest incoming paths assures the mothers will not go before the daughters*/
191 /* Calculate all paths*/
192 std::map<ConstGenVertexPtr, int> longest_paths;
193 for (ConstGenVertexPtr v: evt->vertices()) calculate_longest_path_to_top(v, longest_paths);
194 /* Sort paths*/
195 std::vector<std::pair<ConstGenVertexPtr, int> > sorted_paths;
196 std::copy(longest_paths.begin(), longest_paths.end(), std::back_inserter(sorted_paths));
197 std::sort(sorted_paths.begin(), sorted_paths.end(), pair_GenVertexPtr_int_greater());
198
199 std::vector<ConstGenParticlePtr> sorted_particles;
200 std::vector<ConstGenParticlePtr> stable_particles;
201 /*For a valid "Trust mothers" HEPEVT record we must keep mothers together*/
202 for (std::pair<ConstGenVertexPtr, int> it: sorted_paths)
203 {
204 std::vector<ConstGenParticlePtr> Q = it.first->particles_in();
205 std::sort(Q.begin(), Q.end(), GenParticlePtr_greater());
206 std::copy(Q.begin(), Q.end(), std::back_inserter(sorted_particles));
207 /*For each vertex put all outgoing particles w/o end vertex. Ordering of particles to produces reproduceable record*/
208 for (ConstGenParticlePtr pp: it.first->particles_out())
209 if (!(pp->end_vertex())) stable_particles.push_back(pp);
210 }
211 std::sort(stable_particles.begin(), stable_particles.end(), GenParticlePtr_greater());
212 std::copy(stable_particles.begin(), stable_particles.end(), std::back_inserter(sorted_particles));
213
214 int particle_counter;
215 particle_counter = std::min(int(sorted_particles.size()), A->max_number_entries());
216 /* fill the HEPEVT event record (MD code)*/
217 A->set_event_number(evt->event_number());
218 A->set_number_entries(particle_counter);
219 for ( int i = 1; i <= particle_counter; ++i )
220 {
221 A->set_status(i, sorted_particles[i-1]->status());
222 A->set_id(i, sorted_particles[i-1]->pid());
223 FourVector m = sorted_particles[i-1]->momentum();
224 A->set_momentum(i, m.px(), m.py(), m.pz(), m.e());
225 A->set_mass(i, sorted_particles[i-1]->generated_mass());
226 if ( sorted_particles[i-1]->production_vertex() &&
227 sorted_particles[i-1]->production_vertex()->particles_in().size())
228 {
229 FourVector p = sorted_particles[i-1]->production_vertex()->position();
230 A->set_position(i, p.x(), p.y(), p.z(), p.t() );
231 std::vector<int> mothers;
232 mothers.clear();
233
234 for (ConstGenParticlePtr it: sorted_particles[i-1]->production_vertex()->particles_in())
235 for ( int j = 1; j <= particle_counter; ++j )
236 if (sorted_particles[j-1] == (it))
237 mothers.push_back(j);
238 std::sort(mothers.begin(), mothers.end());
239 if (mothers.size() == 0)
240 mothers.push_back(0);
241 if (mothers.size() == 1) mothers.push_back(mothers[0]);
242
243 A->set_parents(i, mothers.front(), mothers.back());
244 }
245 else
246 {
247 A->set_position(i, 0, 0, 0, 0);
248 A->set_parents(i, 0, 0);
249 }
250 A->set_children(i, 0, 0);
251 }
252 return true;
253}
254
255
256/** @brief Converts HEPEVT into GenEvent. */
257template <class T>
259{
260 if ( !evt ) { std::cerr << "HEPEVT_to_GenEvent_static - passed null event." << std::endl; return false;}
261 evt->set_event_number(T::event_number());
262 std::map<GenParticlePtr, int > hepevt_particles;
263 std::map<int, GenParticlePtr > particles_index;
264 std::map<GenVertexPtr, std::pair<std::set<int>, std::set<int> > > hepevt_vertices;
265 std::map<int, GenVertexPtr > vertex_index;
266 int ne=0;
267 ne=T::number_entries();
268 for ( int i = 1; i <= ne; i++ )
269 {
270 GenParticlePtr p = std::make_shared<GenParticle>();
271 p->set_momentum(FourVector(T::px(i), T::py(i), T::pz(i), T::e(i)));
272 p->set_status(T::status(i));
273 p->set_pid(T::id(i)); //Confusing!
274 p->set_generated_mass(T::m(i));
275 hepevt_particles[p] = i;
276 particles_index[i] = p;
277 GenVertexPtr v = std::make_shared<GenVertex>();
278 v->set_position(FourVector(T::x(i), T::y(i), T::z(i), T::t(i)));
279 v->add_particle_out(p);
280 std::set<int> in;
281 std::set<int> out;
282 out.insert(i);
283 vertex_index[i] = v;
284 hepevt_vertices[v] = std::pair<std::set<int>, std::set<int> >(in, out);
285 }
286 /* The part above is always correct as it is a raw information without any topology.*/
287
288 /* In this way we trust mother information. The "Trust daughters" is not implemented.*/
289 for (std::map<GenParticlePtr, int >::iterator it1 = hepevt_particles.begin(); it1 != hepevt_particles.end(); ++it1)
290 for (std::map<GenParticlePtr, int >::iterator it2 = hepevt_particles.begin(); it2 != hepevt_particles.end(); ++it2) {
291 if (T::first_parent(it2->second) <= it1->second && it1->second <= T::last_parent(it2->second)) hepevt_vertices[it2->first->production_vertex()].first.insert(it1->second);
292 }
293 /* Now all incoming sets are correct for all vertices. But we have duplicates.*/
294
295 /* Disconnect all particles from the vertices*/
296 for ( int i = 1; i <= T::number_entries(); i++ ) vertex_index[i]->remove_particle_out(particles_index[i]);
297
298 /*Fill container with vertices with unique sets of incoming particles. Merge the outcoming particle sets.*/
299 std::map<GenVertexPtr, std::pair<std::set<int>, std::set<int> > > final_vertices_map;
300 for (std::map<GenVertexPtr, std::pair<std::set<int>, std::set<int> > >::iterator vs = hepevt_vertices.begin(); vs != hepevt_vertices.end(); ++vs)
301 {
302 if ((final_vertices_map.size() == 0) || (vs->second.first.size() == 0 && vs->second.second.size() != 0)) { final_vertices_map.insert(*vs); continue; } /*Always insert particles out of nowhere*/
303 std::map<GenVertexPtr, std::pair<std::set<int>, std::set<int> > >::iterator v2;
304 for (v2 = final_vertices_map.begin(); v2 != final_vertices_map.end(); ++v2) if (vs->second.first == v2->second.first) {v2->second.second.insert(vs->second.second.begin(), vs->second.second.end()); break;}
305 if (v2 == final_vertices_map.end()) final_vertices_map.insert(*vs);
306 }
307
308 std::vector<GenParticlePtr> final_particles;
309 std::set<int> used;
310 for (std::map<GenVertexPtr, std::pair<std::set<int>, std::set<int> > >:: iterator it = final_vertices_map.begin(); it != final_vertices_map.end(); ++it)
311 {
312 GenVertexPtr v = it->first;
313 std::set<int> in = it->second.first;
314 std::set<int> out = it->second.second;
315 used.insert(in.begin(), in.end());
316 used.insert(out.begin(), out.end());
317 for (const auto& el: in) v->add_particle_in(particles_index[el]);
318 if (in.size() !=0 ) for (const auto& el: out) v->add_particle_out(particles_index[el]);
319 }
320 for (const auto& el: used) final_particles.emplace_back(particles_index[el]);
321 /* One can put here a check on the number of particles/vertices*/
322
323 evt->add_tree(final_particles);
324
325 return true;
326}
327
328/** @brief Converts GenEvent into HEPEVT. */
329template <class T>
331{
332 /// This writes an event out to the HEPEVT common block. The daughters
333 /// field is NOT filled, because it is possible to contruct graphs
334 /// for which the mothers and daughters cannot both be make sequential.
335 /// This is consistent with how pythia fills HEPEVT (daughters are not
336 /// necessarily filled properly) and how IO_HEPEVT reads HEPEVT.
337 if ( !evt ) return false;
338
339 /*AV Sorting the vertices by the lengths of their longest incoming paths assures the mothers will not go before the daughters*/
340 /* Calculate all paths*/
341 std::map<ConstGenVertexPtr, int> longest_paths;
342 for (ConstGenVertexPtr v: evt->vertices()) calculate_longest_path_to_top(v, longest_paths);
343 /* Sort paths*/
344 std::vector<std::pair<ConstGenVertexPtr, int> > sorted_paths;
345 std::copy(longest_paths.begin(), longest_paths.end(), std::back_inserter(sorted_paths));
346 std::sort(sorted_paths.begin(), sorted_paths.end(), pair_GenVertexPtr_int_greater());
347
348 std::vector<ConstGenParticlePtr> sorted_particles;
349 std::vector<ConstGenParticlePtr> stable_particles;
350 /*For a valid "Trust mothers" HEPEVT record we must keep mothers together*/
351 for (std::pair<ConstGenVertexPtr, int> it: sorted_paths)
352 {
353 std::vector<ConstGenParticlePtr> Q = it.first->particles_in();
354 std::sort(Q.begin(), Q.end(), GenParticlePtr_greater());
355 std::copy(Q.begin(), Q.end(), std::back_inserter(sorted_particles));
356 /*For each vertex put all outgoing particles w/o end vertex. Ordering of particles to produces reproduceable record*/
357 for (ConstGenParticlePtr pp: it.first->particles_out())
358 if (!(pp->end_vertex())) stable_particles.push_back(pp);
359 }
360 std::sort(stable_particles.begin(), stable_particles.end(), GenParticlePtr_greater());
361 std::copy(stable_particles.begin(), stable_particles.end(), std::back_inserter(sorted_particles));
362
363 int particle_counter;
364 particle_counter = std::min(int(sorted_particles.size()), T::max_number_entries());
365 /* fill the HEPEVT event record (MD code)*/
366 T::set_event_number(evt->event_number());
367 T::set_number_entries(particle_counter);
368 for ( int i = 1; i <= particle_counter; ++i )
369 {
370 T::set_status(i, sorted_particles[i-1]->status());
371 T::set_id(i, sorted_particles[i-1]->pid());
372 FourVector m = sorted_particles[i-1]->momentum();
373 T::set_momentum(i, m.px(), m.py(), m.pz(), m.e());
374 T::set_mass(i, sorted_particles[i-1]->generated_mass());
375 if ( sorted_particles[i-1]->production_vertex() &&
376 sorted_particles[i-1]->production_vertex()->particles_in().size())
377 {
378 FourVector p = sorted_particles[i-1]->production_vertex()->position();
379 T::set_position(i, p.x(), p.y(), p.z(), p.t() );
380 std::vector<int> mothers;
381 mothers.clear();
382
383 for (ConstGenParticlePtr it: sorted_particles[i-1]->production_vertex()->particles_in())
384 for ( int j = 1; j <= particle_counter; ++j )
385 if (sorted_particles[j-1] == (it))
386 mothers.push_back(j);
387 std::sort(mothers.begin(), mothers.end());
388 if (mothers.size() == 0)
389 mothers.push_back(0);
390 if (mothers.size() == 1) mothers.push_back(mothers[0]);
391
392 T::set_parents(i, mothers.front(), mothers.back());
393 }
394 else
395 {
396 T::set_position(i, 0, 0, 0, 0);
397 T::set_parents(i, 0, 0);
398 }
399 T::set_children(i, 0, 0);
400 }
401 return true;
402}
403
404}
405#endif
Definition of class GenEvent.
Definition of class GenParticle.
Definition of class GenVertex.
Generic 4-vector.
Definition FourVector.h:36
double e() const
Energy component of momentum.
Definition FourVector.h:135
double pz() const
z-component of momentum
Definition FourVector.h:128
double t() const
Time component of position/displacement.
Definition FourVector.h:106
double px() const
x-component of momentum
Definition FourVector.h:114
double py() const
y-component of momentum
Definition FourVector.h:121
double x() const
x-component of position/displacement
Definition FourVector.h:85
double y() const
y-component of position/displacement
Definition FourVector.h:92
double z() const
z-component of position/displacement
Definition FourVector.h:99
Stores event-related information.
Definition GenEvent.h:47
int event_number() const
Get event number.
Definition GenEvent.h:155
void set_event_number(const int &num)
Set event number.
Definition GenEvent.h:157
const std::vector< ConstGenVertexPtr > & vertices() const
Get list of vertices (const).
Definition GenEvent.cc:43
void add_tree(const std::vector< GenParticlePtr > &parts)
Add whole tree in topological order.
Definition GenEvent.cc:268
HepMC3 main namespace.
bool HEPEVT_to_GenEvent_static(GenEvent *evt)
Converts HEPEVT into GenEvent.
bool HEPEVT_to_GenEvent_nonstatic(GenEvent *evt, T *A)
Converts HEPEVT into GenEvent.
void calculate_longest_path_to_top(ConstGenVertexPtr v, std::map< ConstGenVertexPtr, int > &pathl)
Calculates the path to the top (beam) particles.
bool GenEvent_to_HEPEVT_static(const GenEvent *evt)
Converts GenEvent into HEPEVT.
bool GenEvent_to_HEPEVT_nonstatic(const GenEvent *evt, T *A)
Converts GenEvent into HEPEVT.
C structure representing Fortran common block HEPEVT T. Sjöstrand et al., "A proposed standard event ...
bool operator()(ConstGenParticlePtr lx, ConstGenParticlePtr rx) const
comparison of two particles
Order vertices with equal paths.
bool operator()(const std::pair< ConstGenVertexPtr, int > &lx, const std::pair< ConstGenVertexPtr, int > &rx) const
Order vertices with equal paths. If the paths are equal, order in other quantities....