Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-27 09:14:57

0001 // lAger: General Purpose l/A-event Generator
0002 // Copyright (C) 2016-2021 Sylvester Joosten <sjoosten@anl.gov>
0003 //
0004 // This file is part of lAger.
0005 //
0006 // lAger is free software: you can redistribute it and/or modify
0007 // it under the terms of the GNU General Public License as published by
0008 // the Free Shoftware Foundation, either version 3 of the License, or
0009 // (at your option) any later version.
0010 //
0011 // lAger is distributed in the hope that it will be useful,
0012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 // GNU General Public License for more details.
0015 //
0016 // You should have received a copy of the GNU General Public License
0017 // along with lAger.  If not, see <https://www.gnu.org/licenses/>.
0018 //
0019 
0020 #ifndef LAGER_CORE_EVENT_LOADED
0021 #define LAGER_CORE_EVENT_LOADED
0022 
0023 #include <lager/core/assert.hh>
0024 #include <lager/core/event.hh>
0025 #include <lager/core/generator.hh>
0026 #include <lager/core/particle.hh>
0027 
0028 #include <TClonesArray.h>
0029 #include <TFile.h>
0030 #include <TParticle.h>
0031 #include <TTree.h>
0032 
0033 #include <HepMC3/WriterAscii.h>
0034 
0035 #include <fstream>
0036 #include <memory>
0037 #include <string>
0038 #include <vector>
0039 
0040 namespace lager {
0041 
0042 // =============================================================================
0043 // event
0044 //
0045 // base event record that carries a list of all particles
0046 // derive form this class for more specialized event records
0047 // =============================================================================
0048 class event : public generator_data {
0049 public:
0050   event(const event&) = default;
0051   event& operator=(const event&) = default;
0052   explicit event(const double xs = 1., const double w = 1.)
0053       : generator_data{xs}, weight_{w} {}
0054 
0055   // ===========================================================================
0056   // EVENT INFO
0057   //
0058   // access evgen and weight info, cross section is available through the
0059   // generator_data base class
0060   size_t evgen() const { return evgen_; }
0061   double total_cross_section() const { return total_cross_section_; }
0062   double process_cross_section() const { return process_cross_section_; }
0063   double weight() const { return weight_; }
0064   int process() const { return process_; }
0065 
0066   // event CM energy (from beam/target)
0067   double s() const;
0068 
0069   // update MC info (evgen, total cross section and process cross
0070   // section, also apply jacobians if necessary to go to a more sane
0071   // differential form, in case we generated in some clever unintuitive phase
0072   // space)
0073   void update_stat(const size_t evgen, const double txs);
0074   void update_process(const int proc);
0075   // update weight and process number
0076   void update_weight(const double w) { weight_ *= w; }
0077   void reset_weight(const double w = 1.) { weight_ = w; }
0078 
0079   // count the number of tracks with certain properties
0080   size_t count_status(const particle::status_code stat) const {
0081     return std::count_if(part_.begin(), part_.end(),
0082                          [=](const particle& p) { return p.status() == stat; });
0083   }
0084   size_t count_stable() const {
0085     return std::count_if(part_.begin(), part_.end(),
0086                          [](const particle& p) { return p.stable(); });
0087   }
0088   size_t count_final_state() const {
0089     return std::count_if(part_.begin(), part_.end(),
0090                          [](const particle& p) { return p.final_state(); });
0091   }
0092 
0093   // ===========================================================================
0094   // PARICLE INFO
0095   //
0096   // access particle info
0097   particle& operator[](const int index) { return part_[index]; }
0098   const particle& operator[](const int index) const { return part_[index]; }
0099   std::vector<particle>& part() { return part_; }
0100   const std::vector<particle>& part() const { return part_; }
0101   particle& part(const int index) { return part_[index]; }
0102   const particle& part(const int index) const { return part_[index]; }
0103 
0104   // event size
0105   size_t size() const { return part_.size(); }
0106 
0107   // particle iterators
0108   std::vector<particle>::iterator begin() { return part_.begin(); }
0109   std::vector<particle>::const_iterator begin() const { return part_.begin(); }
0110   std::vector<particle>::iterator end() { return part_.end(); }
0111   std::vector<particle>::const_iterator end() const { return part_.end(); }
0112 
0113   // add a misc particle. returns the index of the particle
0114   int add_particle(const particle& p);
0115   int add_particle(const std::pair<particle, particle>& p);
0116 
0117   // add a daughter particle with 1 or 2 parents
0118   // returns the index of the daughter
0119   int add_daughter(particle daughter, const int parent1,
0120                    const int parent2 = -1);
0121   int add_daughter(const std::pair<particle, particle>& daughters,
0122                    const int parent1, const int parent2 = -1);
0123 
0124   // add incoming and target beams
0125   // returns the beam and target index
0126   int add_ibeam(const particle& p);
0127   int add_tbeam(const particle& p);
0128 
0129   // beam and target info
0130   particle& ibeam();
0131   const particle& ibeam() const;
0132   particle& tbeam();
0133   const particle& tbeam() const;
0134   int ibeam_index() const { return ibeam_index_; }
0135   int tbeam_index() const { return tbeam_index_; }
0136 
0137   // ===========================================================================
0138   // DETECTOR INFO
0139   //
0140   // access detector info
0141   std::vector<detected_particle>& detected() { return detected_; }
0142   const std::vector<detected_particle>& detected() const { return detected_; }
0143   detected_particle& detected(const int index) { return detected_[index]; }
0144   const detected_particle& detected(const int index) const;
0145 
0146   int add_detected(const detected_particle& dp);
0147 
0148 private:
0149   size_t evgen_{1}; // total number of generated events including this event
0150   double total_cross_section_{0.};   // estimated total integrated cross section
0151   double process_cross_section_{0.}; // differential process cross section
0152   double weight_{1.};
0153   int process_{0}; // optional process identifier
0154 
0155   double s_; // mandelstam s, automatically calculated from beam and target
0156 
0157   int ibeam_index_{-1};
0158   int tbeam_index_{-1};
0159 
0160   //
0161   std::vector<particle> part_;
0162   std::vector<detected_particle> detected_;
0163 };
0164 } // namespace lager
0165 
0166 // =============================================================================
0167 // event_out
0168 //
0169 // Output for the base event record.
0170 //
0171 // Derive from this class for more specialized event records.
0172 // (where the specialized event record derives from the main event class)
0173 //    * Make sure to define your own push(your_event_type) method, and call the
0174 //      parent push(parent_event_type) from within the method.
0175 //    * you are responsible to create the necessary branches for your custom
0176 //      event type, the main event branches are added by this base class
0177 // =============================================================================
0178 
0179 // TODO needs refactoring of the output plugins
0180 //      --> migrate to config-based approach rather
0181 //          than hardcoded compontents
0182 namespace lager {
0183 class event_out {
0184 public:
0185   constexpr static const int32_t PARTICLE_BUFFER_SIZE{1000};
0186 
0187   event_out(std::shared_ptr<TFile> f,
0188             std::unique_ptr<HepMC3::WriterAscii> ohepmc,
0189             std::unique_ptr<std::ofstream> ogemc,
0190             std::unique_ptr<std::ofstream> osimc, const std::string& name);
0191   ~event_out() { tree_->AutoSave(); }
0192 
0193   // no implicit default constructors
0194   event_out() = delete;
0195   event_out(const event_out&) = delete;
0196   event_out& operator=(const event_out&) = delete;
0197 
0198   // add a event(s) to the event buffer, and flush the buffer to the tree
0199   void push(const event& e);
0200   void push(const std::vector<event>& e);
0201 
0202   TTree* tree() { return tree_; }
0203 
0204 private:
0205   void write_hepmc(const event& e);
0206   void write_gemc(const event& e);
0207   void write_simc(const event& e);
0208 
0209   // clear particle portion of the event buffer
0210   void clear();
0211   // add a particle to the event buffer
0212   void add(const particle& part);
0213   // add a detected particle to the buffer
0214   void add_detected(const detected_particle& dp);
0215   // create branches
0216   void create_branches();
0217 
0218 private:
0219   // file and tree
0220   std::shared_ptr<TFile> file_;
0221   TTree* tree_; // raw pointer because the TFile will have ownership of the tree
0222   std::unique_ptr<HepMC3::WriterAscii> ohepmc_; // HEPMC output stream
0223   std::unique_ptr<std::ofstream> ogemc_;       // GEMC output stream
0224   std::unique_ptr<std::ofstream> osimc_;       // SIMC output stream
0225 
0226   // event data
0227   int32_t index_{0};
0228   int32_t evgen_;
0229   float cross_section_;
0230   float total_cross_section_;
0231   float process_cross_section_;
0232   float weight_;
0233   int32_t process_;
0234   float s_;
0235   int16_t ibeam_index_;
0236   int16_t tbeam_index_;
0237 
0238   // particle data
0239   int16_t n_part_{0};
0240   TClonesArray parts_;
0241   int16_t rc_n_part_{0};
0242   TClonesArray rc_parts_;
0243 };
0244 } // namespace lager
0245 
0246 // =============================================================================
0247 // EVENT IMPLEMENTATION
0248 // =============================================================================
0249 namespace lager {
0250 inline int event::add_particle(const particle& p) {
0251   const int index = part_.size();
0252   part_.push_back(p);
0253   part_[index].update_index(index);
0254   return index;
0255 }
0256 inline int event::add_particle(const std::pair<particle, particle>& p) {
0257   int first = add_particle(p.first);
0258   add_particle(p.second);
0259   return first;
0260 }
0261 
0262 inline int event::add_daughter(particle daughter, const int parent1,
0263                                const int parent2) {
0264   daughter.add_parent(parent1);
0265   daughter.add_parent(parent2);
0266   int index = add_particle(daughter);
0267   part_[parent1].add_daughter(index);
0268   if (parent2 >= 0) {
0269     part_[parent2].add_daughter(index);
0270   }
0271   return index;
0272 }
0273 inline int event::add_daughter(const std::pair<particle, particle>& daughters,
0274                                const int parent1, const int parent2) {
0275   int first = add_daughter(daughters.first, parent1, parent2);
0276   add_daughter(daughters.second, parent1, parent2);
0277   return first;
0278 }
0279 
0280 inline void event::update_stat(const size_t evgen, const double txs) {
0281   evgen_ = evgen;
0282   total_cross_section_ = txs;
0283   update_cross_section(jacobian());
0284   process_cross_section_ = 0.; // not used anymore
0285 }
0286 inline void event::update_process(const int proc) { process_ = proc; }
0287 inline const detected_particle& event::detected(const int index) const {
0288   return detected_[index];
0289 }
0290 
0291 inline int event::add_detected(const detected_particle& dp) {
0292   detected_.push_back(dp);
0293   return detected_.size() - 1;
0294 }
0295 inline int event::add_ibeam(const particle& p) {
0296   ibeam_index_ = add_particle(p);
0297   return ibeam_index_;
0298 }
0299 inline int event::add_tbeam(const particle& p) {
0300   tbeam_index_ = add_particle(p);
0301   return tbeam_index_;
0302 }
0303 inline particle& event::ibeam() {
0304   tassert(ibeam_index_ >= 0, "trying to access beam data, but no beam "
0305                              "data present in the event.");
0306   return part_[ibeam_index_];
0307 }
0308 inline const particle& event::ibeam() const {
0309   tassert(ibeam_index_ >= 0, "trying to access beam data, but no beam "
0310                              "data present in the event.");
0311   return part_[ibeam_index_];
0312 }
0313 inline particle& event::tbeam() {
0314   tassert(tbeam_index_ >= 0, "trying to access target data, but no target "
0315                              "data present in the event.");
0316   return part_[tbeam_index_];
0317 }
0318 inline const particle& event::tbeam() const {
0319   tassert(tbeam_index_ >= 0, "trying to access target data, but no target "
0320                              "data present in the event.");
0321   return part_[tbeam_index_];
0322 }
0323 inline double event::s() const {
0324   // only if beam AND target have been set
0325   if (ibeam_index_ < 0 || tbeam_index_ < 0) {
0326     return 0.;
0327   }
0328   return (ibeam().p() + tbeam().p()).M2();
0329 }
0330 
0331 } // namespace lager
0332 
0333 #endif