1 // -*- C++ -*-
2 //
3 // This file is part of HepMC
4 // Copyright (C) 2014-2020 The HepMC collaboration (see AUTHORS for details)
5 //
6 ///
7 /// @file GenEvent.h
8 /// @brief Definition of \b class GenEvent
9 ///
10 #ifndef HEPMC3_GENEVENT_H
11 #define HEPMC3_GENEVENT_H
12 
13 #include "HepMC3/Units.h"
14 #include "HepMC3/GenParticle_fwd.h"
15 #include "HepMC3/GenVertex_fwd.h"
16 #include "HepMC3/GenPdfInfo_fwd.h"
17 #include "HepMC3/GenHeavyIon_fwd.h"
18 #include "HepMC3/GenCrossSection_fwd.h"
19 
20 #if !defined(__CINT__)
21 #include "HepMC3/GenHeavyIon.h"
22 #include "HepMC3/GenPdfInfo.h"
23 #include "HepMC3/GenCrossSection.h"
24 #include "HepMC3/GenRunInfo.h"
25 #include <mutex>
26 #endif // __CINT__
27 
28 #ifdef HEPMC3_ROOTIO
29 class TBuffer;
30 #endif
31 
32 
33 namespace HepMC3 {
34 
35 struct GenEventData;
36 
37 /// @brief Stores event-related information
38 ///
39 /// Manages event-related information.
40 /// Contains lists of GenParticle and GenVertex objects
41 class GenEvent {
42 
43 public:
44 
45     /// @brief Event constructor without a run
46     GenEvent(Units::MomentumUnit momentum_unit = Units::GEV,
47              Units::LengthUnit length_unit = Units::MM);
48 
49 #if !defined(__CINT__)
50 
51     /// @brief Constructor with associated run
52     GenEvent(std::shared_ptr<GenRunInfo> run,
53              Units::MomentumUnit momentum_unit = Units::GEV,
54              Units::LengthUnit length_unit = Units::MM);
55 
56     /// @brief Copy constructor
57     GenEvent(const GenEvent&);
58 
59     /// @brief Destructor
60     ~GenEvent();
61 
62     /// @brief Assignment operator
63     GenEvent& operator=(const GenEvent&);
64 
65     /// @name Particle and vertex access
66     //@{
67 
68     /// @brief Get list of particles (const)
69     const std::vector<ConstGenParticlePtr>& particles() const;
70     /// @brief Get list of vertices (const)
71     const std::vector<ConstGenVertexPtr>& vertices() const;
72 
73 
74     /// @brief Get/set list of particles (non-const)
particles()75     const std::vector<GenParticlePtr>& particles() { return m_particles; }
76     /// @brief Get/set list of vertices (non-const)
vertices()77     const std::vector<GenVertexPtr>& vertices() { return m_vertices; }
78 
79     //@}
80 
81 
82     /// @name Event weights
83     //@{
84 
85     /// Get event weight values as a vector
weights()86     const std::vector<double>& weights() const { return m_weights; }
87     /// Get event weights as a vector (non-const)
weights()88     std::vector<double>& weights() { return m_weights; }
89     /// Get event weight accessed by index (or the canonical/first one if there is no argument)
90     /// @note It's the user's responsibility to ensure that the given index exists!
91     double weight(const unsigned long& index=0) const { if ( index < weights().size() ) return weights().at(index); else  throw std::runtime_error("GenEvent::weight(const unsigned long&): weight index outside of range"); return 0.0; }
92     /// Get event weight accessed by weight name
93     /// @note Requires there to be an attached GenRunInfo, otherwise will throw an exception
94     /// @note It's the user's responsibility to ensure that the given name exists!
weight(const std::string & name)95     double weight(const std::string& name) const {
96         if (!run_info()) throw std::runtime_error("GenEvent::weight(const std::string&): named access to event weights requires the event to have a GenRunInfo");
97         return weight(run_info()->weight_index(name));
98     }
99     /// Get event weight accessed by weight name
100     /// @note Requires there to be an attached GenRunInfo, otherwise will throw an exception
101     /// @note It's the user's responsibility to ensure that the given name exists!
weight(const std::string & name)102     double& weight(const std::string& name) {
103         if (!run_info()) throw std::runtime_error("GenEvent::weight(const std::string&): named access to event weights requires the event to have a GenRunInfo");
104         int pos = run_info()->weight_index(name);
105         if ( pos < 0 ) throw std::runtime_error("GenEvent::weight(const std::string&): no weight with given name in this run");
106         if ( pos >= int(m_weights.size())) throw std::runtime_error("GenEvent::weight(const std::string&): weight index outside of range");
107         return m_weights[pos];
108     }
109     /// Get event weight names, if there are some
110     /// @note Requires there to be an attached GenRunInfo with registered weight names, otherwise will throw an exception
weight_names()111     const std::vector<std::string>& weight_names() const {
112         if (!run_info()) throw std::runtime_error("GenEvent::weight_names(): access to event weight names requires the event to have a GenRunInfo");
113         const std::vector<std::string>& weightnames = run_info()->weight_names();
114         if (weightnames.empty()) throw std::runtime_error("GenEvent::weight_names(): no event weight names are registered for this run");
115         return weightnames;
116     }
117 
118     //@}
119 
120 
121     /// @name Auxiliary info and event metadata
122     //@{
123 
124     /// @brief Get a pointer to the the GenRunInfo object.
run_info()125     std::shared_ptr<GenRunInfo> run_info() const {
126         return m_run_info;
127     }
128     /// @brief Set the GenRunInfo object by smart pointer.
set_run_info(std::shared_ptr<GenRunInfo> run)129     void set_run_info(std::shared_ptr<GenRunInfo> run) {
130         m_run_info = run;
131         if ( run && !run->weight_names().empty() )
132             m_weights.resize(run->weight_names().size(), 1.0);
133     }
134 
135     /// @brief Get event number
event_number()136     int  event_number() const { return m_event_number; }
137     /// @brief Set event number
set_event_number(const int & num)138     void set_event_number(const int& num) { m_event_number = num; }
139 
140     /// @brief Get momentum unit
momentum_unit()141     const Units::MomentumUnit& momentum_unit() const { return m_momentum_unit; }
142     /// @brief Get length unit
length_unit()143     const Units::LengthUnit& length_unit() const { return m_length_unit; }
144     /// @brief Change event units
145     /// Converts event from current units to new ones
146     void set_units( Units::MomentumUnit new_momentum_unit, Units::LengthUnit new_length_unit);
147 
148     /// @brief Get heavy ion generator additional information
heavy_ion()149     GenHeavyIonPtr heavy_ion() { return attribute<GenHeavyIon>("GenHeavyIon"); }
150     /// @brief Get heavy ion generator additional information (const version)
heavy_ion()151     ConstGenHeavyIonPtr heavy_ion() const { return attribute<GenHeavyIon>("GenHeavyIon"); }
152     /// @brief Set heavy ion generator additional information
set_heavy_ion(GenHeavyIonPtr hi)153     void set_heavy_ion(GenHeavyIonPtr hi) { add_attribute("GenHeavyIon",hi); }
154 
155     /// @brief Get PDF information
pdf_info()156     GenPdfInfoPtr pdf_info() { return attribute<GenPdfInfo>("GenPdfInfo"); }
157     /// @brief Get PDF information (const version)
pdf_info()158     ConstGenPdfInfoPtr pdf_info() const { return attribute<GenPdfInfo>("GenPdfInfo"); }
159     /// @brief Set PDF information
set_pdf_info(GenPdfInfoPtr pi)160     void set_pdf_info(GenPdfInfoPtr pi) { add_attribute("GenPdfInfo",pi); }
161 
162     /// @brief Get cross-section information
cross_section()163     GenCrossSectionPtr cross_section() { return attribute<GenCrossSection>("GenCrossSection"); }
164     /// @brief Get cross-section information (const version)
cross_section()165     ConstGenCrossSectionPtr cross_section() const { return attribute<GenCrossSection>("GenCrossSection"); }
166     /// @brief Set cross-section information
set_cross_section(GenCrossSectionPtr cs)167     void set_cross_section(GenCrossSectionPtr cs) { add_attribute("GenCrossSection",cs); }
168 
169     //@}
170 
171 
172     /// @name Event position
173     //@{
174 
175     /// Vertex representing the overall event position
176     const FourVector& event_pos() const;
177 
178     /// @brief Vector of beam particles
179     std::vector<ConstGenParticlePtr> beams() const;
180 
181     /// @brief Vector of beam particles
182     const std::vector<GenParticlePtr> & beams();
183 
184     /// @brief Shift position of all vertices in the event by @a delta
185     void shift_position_by( const FourVector & delta );
186 
187     /// @brief Shift position of all vertices in the event to @a op
shift_position_to(const FourVector & newpos)188     void shift_position_to( const FourVector & newpos ) {
189         const FourVector delta = newpos - event_pos();
190         shift_position_by(delta);
191     }
192 
193     /// @brief Boost event using x,y,z components of @a v as velocities
194     bool boost( const FourVector&  v );
195     /// @brief Rotate event using x,y,z components of @a v as rotation angles
196     bool rotate( const FourVector&  v );
197     /// @brief Change sign of @a axis
198     bool reflect(const int axis);
199 
200     //@}
201 
202 
203     /// @name Additional attributes
204     //@{
205     /// @brief Add event attribute to event
206     ///
207     /// This will overwrite existing attribute if an attribute
208     /// with the same name is present
209     void add_attribute(const std::string &name, const std::shared_ptr<Attribute> &att,  const int& id = 0) {
210         ///Disallow empty strings
211         if (name.length()==0) return;
212         if (!att)  return;
213         std::lock_guard<std::recursive_mutex> lock(m_lock_attributes);
214         if (m_attributes.count(name)==0) m_attributes[name]=std::map<int, std::shared_ptr<Attribute> >();
215         m_attributes[name][id] = att;
216         att->m_event = this;
217         if ( id > 0 && id <= int(particles().size()) )
218             att->m_particle = particles()[id - 1];
219         if ( id < 0 && -id <= int(vertices().size()) )
220             att->m_vertex = vertices()[-id - 1];
221     }
222 
223     /// @brief Remove attribute
224     void remove_attribute(const std::string &name,  const int& id = 0);
225 
226     /// @brief Get attribute of type T
227     template<class T>
228     std::shared_ptr<T> attribute(const std::string &name,  const int& id = 0) const;
229 
230     /// @brief Get attribute of any type as string
231     std::string attribute_as_string(const std::string &name,  const int& id = 0) const;
232 
233     /// @brief Get list of attribute names
234     std::vector<std::string> attribute_names( const int& id = 0) const;
235 
236     /// @brief Get a copy of the list of attributes
237     /// @note To avoid thread issues, this is returns a copy. Better solution may be needed.
attributes()238     std::map< std::string, std::map<int, std::shared_ptr<Attribute> > > attributes() const {
239         std::lock_guard<std::recursive_mutex> lock(m_lock_attributes);
240         return m_attributes;
241     }
242 
243     //@}
244 
245 
246     /// @name Particle and vertex modification
247     //@{
248 
249     /// @brief Add particle
250     void add_particle( GenParticlePtr p );
251 
252     /// @brief Add vertex
253     void add_vertex( GenVertexPtr v );
254 
255     /// @brief Remove particle from the event
256     ///
257     /// This function  will remove whole sub-tree starting from this particle
258     /// if it is the only incoming particle of this vertex.
259     /// It will also production vertex of this particle if this vertex
260     /// has no more outgoing particles
261     void remove_particle( GenParticlePtr v );
262 
263     /// @brief Remove a set of particles
264     ///
265     /// This function follows rules of GenEvent::remove_particle to remove
266     /// a list of particles from the event.
267     void remove_particles( std::vector<GenParticlePtr> v );
268 
269     /// @brief Remove vertex from the event
270     ///
271     /// This will remove all sub-trees of all outgoing particles of this vertex
272     void remove_vertex( GenVertexPtr v );
273 
274     /// @brief Add whole tree in topological order
275     ///
276     /// This function will find the beam particles (particles
277     /// that have no production vertices or their production vertices
278     /// have no particles) and will add the whole decay tree starting from
279     /// these particles.
280     ///
281     /// @note Any particles on this list that do not belong to the tree
282     ///       will be ignored.
283     void add_tree( const std::vector<GenParticlePtr> &particles );
284 
285     /// @brief Reserve memory for particles and vertices
286     ///
287     /// Helps optimize event creation when size of the event is known beforehand
288     void reserve(const size_t& particles, const size_t& vertices = 0);
289 
290     /// @brief Remove contents of this event
291     void clear();
292 
293     //@}
294 
295     /// @name Deprecated functionality
296     //@{
297 
298     /// @brief Add particle by raw pointer
299     /// @deprecated Use GenEvent::add_particle( const GenParticlePtr& ) instead
300     void add_particle( GenParticle *p );
301 
302     /// @brief Add vertex by raw pointer
303     /// @deprecated Use GenEvent::add_vertex( const GenVertexPtr& ) instead
304     void add_vertex  ( GenVertex *v );
305 
306 
307     /// @brief Set incoming beam particles
308     /// @deprecated Backward compatibility
309     void set_beam_particles(GenParticlePtr p1, GenParticlePtr p2);
310 
311 
312     /// @brief Add  particle to root vertex
313 
314     void add_beam_particle(GenParticlePtr p1);
315 
316 
317     //@}
318 
319 #endif // __CINT__
320 
321 
322     /// @name Methods to fill GenEventData and to read it back
323     //@{
324 
325     /// @brief Fill GenEventData object
326     void write_data(GenEventData &data) const;
327 
328     /// @brief Fill GenEvent based on GenEventData
329     void read_data(const GenEventData &data);
330 
331 #ifdef HEPMC3_ROOTIO
332     /// @brief ROOT I/O streamer
333     void Streamer(TBuffer &b);
334     //@}
335 #endif
336 
337 private:
338 
339     /// @name Fields
340     //@{
341 
342 #if !defined(__CINT__)
343 
344     /// List of particles
345     std::vector<GenParticlePtr> m_particles;
346     /// List of vertices
347     std::vector<GenVertexPtr> m_vertices;
348 
349     /// Event number
350     int m_event_number;
351 
352     /// Event weights
353     std::vector<double> m_weights;
354 
355     /// Momentum unit
356     Units::MomentumUnit m_momentum_unit;
357     /// Length unit
358     Units::LengthUnit m_length_unit;
359 
360     /// The root vertex is stored outside the normal vertices list to block user access to it
361     GenVertexPtr m_rootvertex;
362 
363     /// Global run information.
364     std::shared_ptr<GenRunInfo> m_run_info;
365 
366     /// @brief Map of event, particle and vertex attributes
367     ///
368     /// Keys are name and ID (0 = event, <0 = vertex, >0 = particle)
369     mutable std::map< std::string, std::map<int, std::shared_ptr<Attribute> > > m_attributes;
370 
371     /// @brief Attribute map key type
372     typedef std::map< std::string, std::map<int, std::shared_ptr<Attribute> > >::value_type att_key_t;
373 
374     /// @brief Attribute map value type
375     typedef std::map<int, std::shared_ptr<Attribute> >::value_type att_val_t;
376 
377     /// @brief Mutex lock for the m_attibutes map.
378     mutable std::recursive_mutex m_lock_attributes;
379 #endif // __CINT__
380 
381     //@}
382 
383 };
384 
385 #if !defined(__CINT__)
386 //
387 // Template methods
388 //
389 template<class T>
attribute(const std::string & name,const int & id)390 std::shared_ptr<T> GenEvent::attribute(const std::string &name,  const int& id) const {
391     std::lock_guard<std::recursive_mutex> lock(m_lock_attributes);
392     std::map< std::string, std::map<int, std::shared_ptr<Attribute> > >::iterator i1 =
393         m_attributes.find(name);
394     if ( i1 == m_attributes.end() ) {
395         if ( id == 0 && run_info() ) {
396             return run_info()->attribute<T>(name);
397         }
398         return std::shared_ptr<T>();
399     }
400 
401     std::map<int, std::shared_ptr<Attribute> >::iterator i2 = i1->second.find(id);
402     if (i2 == i1->second.end() ) return std::shared_ptr<T>();
403 
404     if (!i2->second->is_parsed() ) {
405 
406         std::shared_ptr<T> att = std::make_shared<T>();
407         att->m_event = this;
408 
409         if ( id > 0 && id <= int(particles().size()) )
410             att->m_particle = m_particles[id - 1];
411         if ( id < 0 && -id <= int(vertices().size()) )
412             att->m_vertex = m_vertices[-id - 1];
413         if ( att->from_string(i2->second->unparsed_string()) &&
414                 att->init() ) {
415             // update map with new pointer
416             i2->second = att;
417             return att;
418         } else {
419             return std::shared_ptr<T>();
420         }
421     }
422     else return std::dynamic_pointer_cast<T>(i2->second);
423 }
424 #endif // __CINT__
425 
426 } // namespace HepMC3
427 #endif
428