From a911276c8dfc0441ba588961cb8fb0632c3831c7 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Tue, 19 Sep 2023 13:53:26 +0200 Subject: [PATCH 01/37] Introduce pre-defined keys for MC event header info A number of keys into the ME event header information mapping is defined. This is to ensure that code will use the same keys when ever information is set. Additional, non-predefined keys, are still possible. This makes it much more robust when we ask for specific MC information from the event header, such as - cross-section(s) - weight(s) - Heavy-ion "geometry" parameters - Npart in projectile and target - Ncoll in various views - Overall - Hard - wounded-nucleon on nucleon - nucleon on wounded-nucleon - wounded on wounded - Parton distribution function parameters This is crucial for building a HepMC event structure which can be passed on to say for example Rivet analyses. --- .../SimulationDataFormat/MCEventHeader.h | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h index cf323e197392d..afebbbada470d 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h @@ -27,6 +27,68 @@ namespace dataformats class GeneratorHeader; + /** Common keys for information in MC event header */ + struct MCInfoKeys { + /** @{ + @name HepMC3 heavy-ion fields */ + static constexpr const char* impactParameter = "Bimpact"; + static constexpr const char* nPart = "Npart"; + static constexpr const char* nPartProjectile = "Npart_proj"; + static constexpr const char* nPartTarget = "Npart_targ"; + static constexpr const char* nColl = "Ncoll"; + static constexpr const char* nCollHard = "Ncoll_hard"; + static constexpr const char* nCollNNWounded = "NColl_NNw"; + static constexpr const char* nCollNWoundedN = "NColl_NwN"; + static constexpr const char* nCollNWoundedNwounded = "NColl_NwNW"; + static constexpr const char* planeAngle = "eventPsi"; + static constexpr const char* sigmaInelNN = "sigmaInelNN"; + static constexpr const char* centrality = "centrality"; + static constexpr const char* nSpecProjectileProton = "Nspec_proj_p"; + static constexpr const char* nSpecProjectileNeutron = "Nspec_proj_n"; + static constexpr const char* nSpecTargetProton = "Nspec_targ_p"; + static constexpr const char* nSpecTargetNeutron = "Nspec_targ_n"; + /** @} */ + /** @{ + @name HepMC3 PDF information + + In principle a header can have many of these. In that case, + each set should be prefixed with "_" where "" is a + serial number. + */ + static constexpr const char* pdfParton1Id = "pdf_parton_1_id"; + static constexpr const char* pdfParton2Id = "pdf_parton_2_id"; + static constexpr const char* pdfX1 = "pdf_x1"; + static constexpr const char* pdfX2 = "pdf_x2"; + static constexpr const char* pdfScale = "pdf_scale"; + static constexpr const char* pdfXF1 = "pdf_par_x1"; + static constexpr const char* pdfXF2 = "pdf_par_x2"; + static constexpr const char* pdfCode1 = "pdf_lhc_1_id"; + static constexpr const char* pdfCode2 = "pdf_lhc_2_id"; + /** @} */ + /** @{ + @name HepMC3 cross-section information + + In principle we can have one cross section per weight. In that + case, each should be post-fixed by "_" where "" is a + serial number. These should then matcht possible names of + weights. + */ + static constexpr const char* acceptedEvents = "accepted_events"; + static constexpr const char* attemptedEvents = "attempted_events"; + static constexpr const char* xSection = "cross_section"; + static constexpr const char* xSectionError = "cross_section_error"; + /** @} */ + /** @{ + @name Common fields */ + static constexpr const char* generator = "generator"; + static constexpr const char* generatorVersion = "version"; + static constexpr const char* processName = "processName"; + static constexpr const char* processCode = "processCode"; + static constexpr const char* weight = "weight"; + /** @} */ + + }; + /*****************************************************************/ /*****************************************************************/ From dadc5c6d09e5c28b96703d17e8a1bdaf10f3ddbf Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Tue, 19 Sep 2023 13:58:35 +0200 Subject: [PATCH 02/37] Export _full_ header information to MC event header The generator has been changed so that it exports _all_ relevant and available information from Pythia to the MC event header, including heavy-ion "geometry" parameters. In particular, the information is stored in an HepMC compatible way for later user by f.ex. Rivet. Note, the current code counts up the number of collisions by it self. However, the authors of Pythia have another way of doing that. The code is now there to do it the same way as the Pythia authors, but is currenly disabled. We should decide which is the appropriate way to count Ncoll. I would recommend to follow how the Pythia authors do it. --- Generators/src/GeneratorPythia8.cxx | 73 +++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/Generators/src/GeneratorPythia8.cxx b/Generators/src/GeneratorPythia8.cxx index 13c17003ee612..c055bf2718f26 100644 --- a/Generators/src/GeneratorPythia8.cxx +++ b/Generators/src/GeneratorPythia8.cxx @@ -202,13 +202,40 @@ Bool_t void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) { /** update header **/ - - eventHeader->putInfo("generator", "pythia8"); - eventHeader->putInfo("version", PYTHIA_VERSION_INTEGER); - eventHeader->putInfo("processName", mPythia.info.name()); - eventHeader->putInfo("processCode", mPythia.info.code()); - eventHeader->putInfo("weight", mPythia.info.weight()); - + using Key=o2::dataformats::MCInfoKeys; + + eventHeader->putInfo(Key::generator, "pythia8"); + eventHeader->putInfo(Key::generatorVersion, PYTHIA_VERSION_INTEGER); + eventHeader->putInfo(Key::processName, mPythia.info.name()); + eventHeader->putInfo(Key::processCode, mPythia.info.code()); + eventHeader->putInfo(Key::weight, mPythia.info.weight()); + + auto& info = mPythia.info; + + // Set PDF information + eventHeader->putInfo (Key::pdfParton1Id, info.id1pdf()); + eventHeader->putInfo (Key::pdfParton2Id, info.id2pdf()); + eventHeader->putInfo(Key::pdfX1, info.x1pdf()); + eventHeader->putInfo(Key::pdfX2, info.x2pdf()); + eventHeader->putInfo(Key::pdfScale, info.QFac()); + eventHeader->putInfo(Key::pdfXF1, info.pdf1()); + eventHeader->putInfo(Key::pdfXF2, info.pdf2()); + + // Set cross section + eventHeader->putInfo(Key::xSection, info.sigmaGen()*1e9); + eventHeader->putInfo(Key::xSectionError,info.sigmaErr()*1e9); + + // Set weights (overrides cross-section for each weight) + size_t iw = 0; + auto xsecErr = info.weightContainerPtr->getTotalXsecErr(); + for (auto w : info.weightContainerPtr->getTotalXsec()) { + std::string post = (iw == 0 ? "" : "_"+std::to_string(iw)); + eventHeader->putInfo(Key::weight+post, info.weightValueByIndex(iw)); + eventHeader->putInfo(Key::xSection+post,w*1e9); + eventHeader->putInfo(Key::xSectionError+post,xsecErr[iw]*1e9); + iw++; + } + #if PYTHIA_VERSION_INTEGER < 8300 auto hiinfo = mPythia.info.hiinfo; #else @@ -218,7 +245,7 @@ void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) if (hiinfo) { /** set impact parameter **/ eventHeader->SetB(hiinfo->b()); - eventHeader->putInfo("Bimpact", hiinfo->b()); + eventHeader->putInfo(Key::impactParameter, hiinfo->b()); auto bImp = hiinfo->b(); /** set Ncoll, Npart and Nremn **/ int nColl, nPart; @@ -230,7 +257,8 @@ void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) getNpart(nPartProtonProj, nPartNeutronProj, nPartProtonTarg, nPartNeutronTarg); getNremn(nRemnProtonProj, nRemnNeutronProj, nRemnProtonTarg, nRemnNeutronTarg); getNfreeSpec(nFreeNeutronProj, nFreeProtonProj, nFreeNeutronTarg, nFreeProtonTarg); - eventHeader->putInfo("Ncoll", nColl); + eventHeader->putInfo(Key::nColl, nColl); + // These are all non-HepMC3 fields - of limited use eventHeader->putInfo("Npart", nPart); eventHeader->putInfo("Npart_proj_p", nPartProtonProj); eventHeader->putInfo("Npart_proj_n", nPartNeutronProj); @@ -244,6 +272,19 @@ void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) eventHeader->putInfo("Nfree_proj_p", nFreeProtonProj); eventHeader->putInfo("Nfree_targ_n", nFreeNeutronTarg); eventHeader->putInfo("Nfree_targ_p", nFreeProtonTarg); + + // --- HepMC3 conforming information --- + // This is how the Pythia authors define Ncoll + // eventHeader->putInfo(Key::nColl, + // hiinfo->nAbsProj() + hiinfo->nDiffProj() + + // hiinfo->nAbsTarg() + hiinfo->nDiffTarg() - + // hiiinfo->nCollND() - hiinfo->nCollDD()); + eventHeader->putInfo(Key::nPartProjectile, + hiinfo->nAbsProj()+hiinfo->nDiffProj()); + eventHeader->putInfo(Key::nPartTarget, + hiinfo->nAbsTarg()+hiinfo->nDiffTarg()); + eventHeader->putInfo(Key::nCollHard, hiinfo->nCollNDTot()); + } } @@ -302,6 +343,10 @@ void GeneratorPythia8::getNcoll(const Pythia8::Info& info, int& nColl) auto hiinfo = info.hiInfo; #endif + // This is how the Pythia authors define Ncoll + nColl = (hiinfo->nAbsProj()+hiinfo->nDiffProj()+ + hiinfo->nAbsTarg()+hiinfo->nDiffTarg()- + hiinfo->nCollND() -hiinfo->nCollDD()); nColl = 0; if (!hiinfo) { @@ -330,6 +375,16 @@ void GeneratorPythia8::getNpart(const Pythia8::Info& info, int& nPart) /** compute number of participants as the sum of all participants nucleons **/ + // This is how the Pythia authors calculate Npart +#if PYTHIA_VERSION_INTEGER < 8300 + auto hiinfo = info.hiinfo; +#else + auto hiinfo = info.hiInfo; +#endif + if (hiinfo) + nPart = (hiinfo->nAbsProj() + hiinfo->nDiffProj() + + hiinfo->nAbsTarg() + hiinfo->nDiffTarg()); + int nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg; getNpart(info, nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg); nPart = nProtonProj + nNeutronProj + nProtonTarg + nNeutronTarg; From 2f36720ee34aa9b17db568c69a6e220bd78337a6 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Tue, 19 Sep 2023 14:02:40 +0200 Subject: [PATCH 03/37] Full header read-in and external program This change does two things: **Full header** _All_ information available in the HepMC event header is propagated to the MC event header information map. This includes - Heavy-ion "geometry" parameters (b,Ncoll,Npart,...) - Cross-section(s) - Weight(s) - PDF information - and other attributes defined This is so that we can build a full HepMC event structure later - for example to pass to Rivet analyses ** External program ** The functionality of the generatator is expanded so that it may spawn an event generator program, say `eg`. - The generator opens a FIFO - The generator then executes the program `eg` in the background - The `eg` program is assumed to write HepMC event records on standard output, which is then redirected to the FIFO - The generator reads events from the FIFO For this to work, a number of conditions _must_ be met by the `eg` program: - It _must_ write events in the HepMC event format - It _must_ write the HepMC event records to standard output - It _cannot_ write anything else but the HepMC event record to standard output - It _must_ accept the command line option `-n NEVENTS` to set the number of events to generate. If a particular `eg` program does not meet these requirements, then a simple shell script can be defined to wrap the `eg` appropriately. For example, the CRMC program `crmc` _can_ write HepMC events to standard output, but it will also dump other stuff there. Thus, we can provide the script #!/bin/sh crmc $@ -o hepmc3 -f /dev/stdout | \ sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' which simply filters the output of `crmc`. Another EG program may not accept the `-n EVENTS` command line option, but rather has the command line option `--nevents`, so then we would do something like #!/bin/sh cmdline="eg-program -o /dev/stdout " while test $# -gt 0 ; do case x$1 in x-n) cmdline="$cmdline -n $2"; shift ;; *) cmdline="$cmdline $1" ;; esac shift done $cmdline The command line to run is specified as --configKeyValues "HepMC.progCmd=" and can include not only the program name but also other options to the program. For example --configKeyValues "HepMC.progCmd=crmc -m 5 -i 20800820 -I 20800820" for Pb-Pb collisions with Hijing. With this change, we can use _any_ event generator which is capable to write out its event records in the HepMC format. --- .../include/Generators/GeneratorHepMC.h | 8 +- .../include/Generators/GeneratorHepMCParam.h | 1 + Generators/src/GeneratorHepMC.cxx | 191 +++++++++++++++++- 3 files changed, 198 insertions(+), 2 deletions(-) diff --git a/Generators/include/Generators/GeneratorHepMC.h b/Generators/include/Generators/GeneratorHepMC.h index 341f4b8a0e38a..4244f25be6327 100644 --- a/Generators/include/Generators/GeneratorHepMC.h +++ b/Generators/include/Generators/GeneratorHepMC.h @@ -62,8 +62,9 @@ class GeneratorHepMC : public Generator /** setters **/ void setVersion(Int_t val) { mVersion = val; }; void setFileName(std::string val) { mFileName = val; }; + void setProgCmd(std::string val) { mProgCmd = val; }; void setEventsToSkip(uint64_t val) { mEventsToSkip = val; }; - + void setNEvents(unsigned int val) { mNEvents = val; } protected: /** copy constructor **/ GeneratorHepMC(const GeneratorHepMC&); @@ -77,11 +78,16 @@ class GeneratorHepMC : public Generator const HepMC3::FourVector getBoostedVector(const HepMC3::FourVector& vector, Double_t boost); #endif + /** methods that can be overridded **/ + void updateHeader(o2::dataformats::MCEventHeader* eventHeader) override; + /** HepMC interface **/ std::ifstream mStream; //! std::string mFileName; + std::string mProgCmd; Int_t mVersion; uint64_t mEventsToSkip; + unsigned int mNEvents; #ifdef GENERATORS_WITH_HEPMC3_DEPRECATED HepMC::Reader* mReader; //! HepMC::GenEvent* mEvent; //! diff --git a/Generators/include/Generators/GeneratorHepMCParam.h b/Generators/include/Generators/GeneratorHepMCParam.h index 4c53918c70634..8cfd0a31cdd74 100644 --- a/Generators/include/Generators/GeneratorHepMCParam.h +++ b/Generators/include/Generators/GeneratorHepMCParam.h @@ -31,6 +31,7 @@ namespace eventgen struct GeneratorHepMCParam : public o2::conf::ConfigurableParamHelper { std::string fileName = ""; + std::string progCmd = "";//Program command line to spawn, must write HepMC on stdout int version = 2; uint64_t eventsToSkip = 0; O2ParamDef(GeneratorHepMCParam, "HepMC"); diff --git a/Generators/src/GeneratorHepMC.cxx b/Generators/src/GeneratorHepMC.cxx index 6c062268bfacc..56d0e80248a00 100644 --- a/Generators/src/GeneratorHepMC.cxx +++ b/Generators/src/GeneratorHepMC.cxx @@ -14,15 +14,22 @@ #include "SimulationDataFormat/MCUtils.h" #include "Generators/GeneratorHepMC.h" #include "Generators/GeneratorHepMCParam.h" +#include "SimulationDataFormat/MCEventHeader.h" #include "HepMC3/ReaderAscii.h" #include "HepMC3/ReaderAsciiHepMC2.h" #include "HepMC3/GenEvent.h" #include "HepMC3/GenParticle.h" #include "HepMC3/GenVertex.h" #include "HepMC3/FourVector.h" +#include "HepMC3/Version.h" #include "TParticle.h" #include "TSystem.h" +#include +#include // POSIX only +#include // POISX only +#include + #include #include "FairPrimaryGenerator.h" #include @@ -85,6 +92,7 @@ Bool_t GeneratorHepMC::generateEvent() mEvent->clear(); mReader->read_event(*mEvent); if (mReader->failed()) { + LOG(error) << "Failed to read one event from input"; return kFALSE; } /** set units to desired output **/ @@ -143,6 +151,133 @@ Bool_t GeneratorHepMC::importParticles() return kTRUE; } + namespace + { + void putAttributeInfo(o2::dataformats::MCEventHeader* eventHeader, + const std::string& name, + const std::shared_ptr& a) + { + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name,p->value()); + } + } + + +/*****************************************************************/ + +void GeneratorHepMC::updateHeader(o2::dataformats::MCEventHeader* eventHeader) +{ + /** update header **/ + using Key=o2::dataformats::MCInfoKeys; + + eventHeader->putInfo(Key::generator, "hepmc"); + eventHeader->putInfo(Key::generatorVersion, HEPMC3_VERSION_CODE); + + auto xSection = mEvent->cross_section(); + auto pdfInfo = mEvent->pdf_info(); + auto hiInfo = mEvent->heavy_ion(); + + // Set default cross-section + if (xSection) { + eventHeader->putInfo(Key::xSection, xSection->xsec()); + eventHeader->putInfo(Key::xSectionError, xSection->xsec_err()); + eventHeader->putInfo(Key::acceptedEvents, + xSection->get_accepted_events()); + eventHeader->putInfo(Key::attemptedEvents, + xSection->get_attempted_events()); + } + + // Set weights and cross sections + size_t iw = 0; + for (auto w : mEvent->weights()) { + std::string post = (iw > 0 ? "_"+std::to_string(iw) : ""); + eventHeader->putInfo(Key::weight+post, w); + if (xSection) { + eventHeader->putInfo(Key::xSection, xSection->xsec(iw)); + eventHeader->putInfo(Key::xSectionError,xSection->xsec_err(iw)); + } + iw++; + } + + // Set the PDF information + if (pdfInfo) { + eventHeader->putInfo(Key::pdfParton1Id, pdfInfo->parton_id[0]); + eventHeader->putInfo(Key::pdfParton2Id, pdfInfo->parton_id[1]); + eventHeader->putInfo(Key::pdfX1, pdfInfo->x[0]); + eventHeader->putInfo(Key::pdfX2, pdfInfo->x[1]); + eventHeader->putInfo(Key::pdfScale, pdfInfo->scale); + eventHeader->putInfo(Key::pdfXF1, pdfInfo->xf[0]); + eventHeader->putInfo(Key::pdfXF2, pdfInfo->xf[1]); + eventHeader->putInfo(Key::pdfCode1, pdfInfo->pdf_id[0]); + eventHeader->putInfo(Key::pdfCode2, pdfInfo->pdf_id[1]); + } + + // Set heavy-ion information + if (hiInfo) { + eventHeader->putInfo(Key::impactParameter , + hiInfo->impact_parameter); + eventHeader->putInfo(Key::nPart , + hiInfo->Npart_proj+hiInfo->Npart_targ); + eventHeader->putInfo(Key::nPartProjectile ,hiInfo->Npart_proj); + eventHeader->putInfo(Key::nPartTarget ,hiInfo->Npart_targ); + eventHeader->putInfo(Key::nColl ,hiInfo->Ncoll); + eventHeader->putInfo(Key::nCollHard ,hiInfo->Ncoll_hard); + eventHeader->putInfo(Key::nCollNNWounded , + hiInfo->N_Nwounded_collisions); + eventHeader->putInfo(Key::nCollNWoundedN , + hiInfo->Nwounded_N_collisions); + eventHeader->putInfo(Key::nCollNWoundedNwounded , + hiInfo->Nwounded_Nwounded_collisions); + eventHeader->putInfo(Key::planeAngle , + hiInfo->event_plane_angle); + eventHeader->putInfo(Key::sigmaInelNN , + hiInfo->sigma_inel_NN); + eventHeader->putInfo(Key::centrality ,hiInfo->centrality); + eventHeader->putInfo(Key::nSpecProjectileProton ,hiInfo->Nspec_proj_p); + eventHeader->putInfo(Key::nSpecProjectileNeutron,hiInfo->Nspec_proj_n); + eventHeader->putInfo(Key::nSpecTargetProton ,hiInfo->Nspec_targ_p); + eventHeader->putInfo(Key::nSpecTargetNeutron ,hiInfo->Nspec_targ_n); + } + + for (auto na : mEvent->attributes()) { + std::string name = na.first; + if (name == "GenPdfInfo" || + name == "GenCrossSection" || + name == "GenHeavyIon") continue; + + for (auto ia : na.second) { + int no = ia.first; + auto at = ia.second; + std::string post = (no == 0 ? "" : std::to_string(no)); + + putAttributeInfo(eventHeader, name+post, at); + } + } +} + + /*****************************************************************/ Bool_t GeneratorHepMC::Init() @@ -152,14 +287,68 @@ Bool_t GeneratorHepMC::Init() /** init base class **/ Generator::Init(); - /** open file **/ std::string filename = gSystem->ExpandPathName(mFileName.c_str()); + + // If a EG command line is given, then we make a fifo on a temporary + // file, and directs the EG to write to that fifo. We will then set + // up the HepMC3 reader to read from that fifo. + // + // o2-sim -g hepmc --configKeyValues "HepMC.progCmd=" ... + // + // where is the command line to run an event generator. The + // event generator should output HepMC event records to standard + // output. Nothing else, but the HepMC event record may be output + // to standard output. If the EG has other output to standard + // output, then a filter can be set-up. For example + // + // crmc -n 3 -o hepmc3 -c /optsw/inst/etc/crmc.param -f /dev/stdout \ + // | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' + // + // What's more, the event generator program must accept the command + // line argument `-n NEVENTS` to set the number of events to + // produce. + // + // All of this can conviniently be achieved via a wrapper script + // around the actual EG program. + if (not mProgCmd.empty()) { + // Set filename to be a temporary name + // Should perhaps use + // + // TString base("xxxxxx"); + // auto fp = gSystem->TempFileName(base); + // fclose(fp); + // + filename = std::tmpnam(nullptr); + + // Make a fifo + int ret = mkfifo(filename.c_str(), 0600); + if (ret != 0) { + LOG(fatal) << "Failed to make fifo \"" << filename << "\""; + return false; + } + + // Build command line, rediret stdout to our fifo and put + // in the background. + std::string cmd = + mProgCmd + + " -n " + std::to_string(mNEvents) + + " > " + filename + " &"; + LOG(info) << "EG command line is \"" << cmd << "\""; + + ret = std::system(cmd.c_str()); + if (ret != 0) { + LOG(fatal) << "Failed to spawn \"" << cmd << "\""; + return false; + } + } + /** open file **/ mStream.open(filename); if (!mStream.is_open()) { LOG(fatal) << "Cannot open input file: " << filename << std::endl; return kFALSE; } + LOG(info) << "Set up reader to read from \"" << filename << "\"" << std::endl; /** create reader according to HepMC version **/ switch (mVersion) { case 2: From ae319c5e9f0e6f97d95370984b8b7b47178704cb Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Tue, 19 Sep 2023 14:22:40 +0200 Subject: [PATCH 04/37] New generator GeneratorTParticle The generator `GeneratorTParticle` will read in particles from a `TChain` containing a branch with a `TClonesArray` of `TParticle` objects. The generator can operate in two modes - Data is read from a file(s) - Data is read from a file being generated by a child program The first mode is selected by -g tparticle --configKeyValues "TParticle.fileNames=foo.root,bar.root" The second mode is selected by -g tparticle --configKeyValues "TParticle.progCmd=" For this latter mode, see also recent commit to `GeneratorHepMC` Above `` specifiy a program to spawn in the background which will write to a specified file (temporary file). Suppose the program is called `eg`, then the following _must_ be possible eg -n NEVENTS -o OUTPUT_FILENAME That is, `eg` _must_ accept the option `-n` to set the number of events to produce, and the option `-o` to set the output file name (a ROOT file). The name of the `TTree` object in the file(s) can be set with --configKeyValues "TParticle.treeName=" (defaults to `T`), and similar for the branch that contains the `TClonesArray` of `TParticle` --configKeyValues "TParticle.branchName=" (defaults to `Particles`). The generator `GeneratorTParticle` _does not_ import any header information into the simulation event record. Some proper convention could be decided upon, e.g., one that tracks the HepMC event record format. --- Generators/CMakeLists.txt | 4 + .../include/Generators/GeneratorTParticle.h | 117 +++++++++++ .../Generators/GeneratorTParticleParam.h | 43 ++++ Generators/src/GeneratorFactory.cxx | 24 ++- Generators/src/GeneratorTParticle.cxx | 189 ++++++++++++++++++ Generators/src/GeneratorTParticleParam.cxx | 19 ++ Generators/src/GeneratorsLinkDef.h | 3 + 7 files changed, 396 insertions(+), 3 deletions(-) create mode 100644 Generators/include/Generators/GeneratorTParticle.h create mode 100644 Generators/include/Generators/GeneratorTParticleParam.h create mode 100644 Generators/src/GeneratorTParticle.cxx create mode 100644 Generators/src/GeneratorTParticleParam.cxx diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 0b0f92955a651..5a5ae04f29f90 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -38,6 +38,8 @@ o2_add_library(Generators src/GenCosmicsParam.cxx src/GeneratorFactory.cxx src/GeneratorGeantinos.cxx + src/GeneratorTParticle.cxx + src/GeneratorTParticleParam.cxx $<$:src/GeneratorPythia6.cxx> $<$:src/GeneratorPythia6Param.cxx> $<$:src/GeneratorPythia8.cxx> @@ -79,6 +81,8 @@ set(headers include/Generators/QEDGenParam.h include/Generators/GenCosmicsParam.h include/Generators/GeneratorGeantinos.h + include/Generators/GeneratorTParticle.h + include/Generators/GeneratorTParticleParam.h ) if (pythia6_FOUND) diff --git a/Generators/include/Generators/GeneratorTParticle.h b/Generators/include/Generators/GeneratorTParticle.h new file mode 100644 index 0000000000000..4c69bd8c27a09 --- /dev/null +++ b/Generators/include/Generators/GeneratorTParticle.h @@ -0,0 +1,117 @@ +// -*- C++ -*- +// Copyright 2023 CERN and copyright holders of ALICE O2. +// +// See https://alice-o2.web.cern.ch/copyright for details of the +// copyright holders. All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General +// Public License v3 (GPL Version 3), copied verbatim in the file +// "COPYING". +// +// In applying this license CERN does not waive the privileges and +// immunities granted to it by virtue of its status as an +// Intergovernmental Organization or submit itself to any +// jurisdiction. +// +/// @author: Christian Holm Christensen +#ifndef ALICEO2_GENERATORTPARTICLE_H_ +#define ALICEO2_GENERATORTPARTICLE_H_ +#include +#include +#include + +// Forward decls +class TChain; +class TParticle; +class TClonesArray; + +namespace o2 +{ + namespace eventgen + { + /// A class that reads in particles of class @c TParticle from a + /// branch in a @c TChain. + /// + /// Optionally, a program that generates such a @c TTree can be + /// spawn, and the @c TParticles written to a file from which this + /// object reads them in. This is done with + /// + /// --configKeyValues "TParticle.progCmd=" + /// + /// which will execute the specified EG program with the given + /// options. The EG program _must_ support the command line options + /// + /// -n NUMBER Number of events to generate + /// -o FILENAME Name of file to write to + /// + /// The tree name and particle branch names can be configured. + /// + /// --configKeyValues "TParticle.treeName=T,TParticle.branchName=P" + /// + /// File(s) to read are also configurable + /// + /// --configKeyValues "TParticle.fileNames=foo.root,bar.root" + /// + class GeneratorTParticle : public Generator + { + public: + /** CTOR */ + GeneratorTParticle() = default; + /** CTOR */ + GeneratorTParticle(const std::string& name) + : Generator(name.c_str(),"ALICEo2 TParticle Generator") + {} + /** DTOR */ + virtual ~GeneratorTParticle(); + + /** Initialize this generator. This will set up the chain. + Optionally, if a command line was specified by @c + TParticle.progCmd then that command line is executed in the + background and events are read from the output file of that + program */ + Bool_t Init() override; + + /** Read in the next entry from the chain. Returns false in + case of errors or no more entries to read. */ + Bool_t generateEvent() override; + + /** Import the read-in particles into the steer particle + stack */ + Bool_t importParticles() override; + + /** Set the names of files to read, separated by commas */ + void setFileNames(const std::string& val); + /** Set the name of the tree in the files. The tree _must_ + reside in the top-level directory of the files. */ + void setTreeName(const std::string& val) { mTreeName = val; } + /** Set the branch name of the branch that holds a @c + TClonesArray of @c TParticle objects */ + void setBranchName(const std::string& val) { mBranchName = val; } + /** Set child program command line to (optionally) execute */ + void setProgCmd(const std::string& val) { mProgCmd = val; } + /** Set the number of events to generate. */ + void setNEvents(unsigned int nev) { mNEvents = nev; } + protected: + std::string mTreeName = "T"; + std::string mBranchName = "Particles"; + std::string mProgCmd = ""; + std::list mFileNames; + unsigned int mNEvents = 0; + unsigned int mEntry = 0; + TChain* mChain; + TClonesArray* mTParticles; + + void waitForData(); + + ClassDefOverride(GeneratorTParticle,1); + }; + } +} +#endif +// +// EOF +// + + + + diff --git a/Generators/include/Generators/GeneratorTParticleParam.h b/Generators/include/Generators/GeneratorTParticleParam.h new file mode 100644 index 0000000000000..d293f9c0e2957 --- /dev/null +++ b/Generators/include/Generators/GeneratorTParticleParam.h @@ -0,0 +1,43 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// +// See https://alice-o2.web.cern.ch/copyright for details of the +// copyright holders. All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General +// Public License v3 (GPL Version 3), copied verbatim in the file +// "COPYING". +// +// In applying this license CERN does not waive the privileges and +// immunities granted to it by virtue of its status as an +// Intergovernmental Organization or submit itself to any +// jurisdiction. +// +// @author: Christian Holm Christensen +#ifndef ALICEO2_EVENTGEN_GENERATORTPARTICLEPARAM_H_ +#define ALICEO2_EVENTGEN_GENERATORTPARTICLEPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" +#include + +namespace o2 +{ + namespace eventgen + { + + /** + a parameter class/struct to keep the settings of the TGenerator + event generator and allow the user to modify them */ + struct GeneratorTParticleParam : + public o2::conf::ConfigurableParamHelper + { + std::string treeName = "T"; + std::string branchName = "Particles"; + std::string fileNames = "tparticle.root"; + std::string progCmd = ""; + O2ParamDef(GeneratorTParticleParam, "TParticle"); + }; + } // end namespace eventgen +} // end namespace o2 + +#endif // ALICEO2_EVENTGEN_GENERATORHEPMCPARAM_H_ diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index ae47ede14f4a3..628ca885bbf0e 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -18,6 +18,8 @@ #include #include #include +#include +#include #ifdef GENERATORS_WITH_PYTHIA6 #include #include @@ -86,6 +88,7 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair o2::O2DatabasePDG::addALICEParticles(TDatabasePDG::Instance()); auto genconfig = conf.getGenerator(); + LOG(info) << "** Generator to use: '" << genconfig << "'"; if (genconfig.compare("boxgen") == 0) { // a simple "box" generator configurable via BoxGunparam auto& boxparam = BoxGunParam::Instance(); @@ -154,18 +157,33 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair if (o2PrimGen) { o2PrimGen->setApplyVertex(false); } - } - LOG(info) << "using external O2 kinematics"; + } LOG(info) << "using external O2 kinematics"; + } else if (genconfig.compare("tparticle") == 0) { + // External ROOT file(s) with tree of TParticle in clones array, + // or external program generating such a file + auto& param = GeneratorTParticleParam::Instance(); + LOG(info) << "Init 'GeneratorTParticle' with the following parameters"; + LOG(info) << param; + auto tgen = new o2::eventgen::GeneratorTParticle(); + tgen->setFileNames(param.fileNames); + tgen->setProgCmd(param.progCmd); + tgen->setTreeName(param.treeName); + tgen->setBranchName(param.branchName); + tgen->setNEvents(conf.getNEvents()); + primGen->AddGenerator(tgen); #ifdef GENERATORS_WITH_HEPMC3 } else if (genconfig.compare("hepmc") == 0) { - // external HepMC file + // external HepMC file, or external program writing HepMC event + // records to standard output. auto& param = GeneratorHepMCParam::Instance(); LOG(info) << "Init \'GeneratorHepMC\' with following parameters"; LOG(info) << param; auto hepmcGen = new o2::eventgen::GeneratorHepMC(); hepmcGen->setFileName(param.fileName); + hepmcGen->setProgCmd(param.progCmd); hepmcGen->setVersion(param.version); hepmcGen->setEventsToSkip(param.eventsToSkip); + hepmcGen->setNEvents(conf.getNEvents()); primGen->AddGenerator(hepmcGen); #endif #ifdef GENERATORS_WITH_PYTHIA6 diff --git a/Generators/src/GeneratorTParticle.cxx b/Generators/src/GeneratorTParticle.cxx new file mode 100644 index 0000000000000..2f4400448a368 --- /dev/null +++ b/Generators/src/GeneratorTParticle.cxx @@ -0,0 +1,189 @@ +// Copyright 2023 CERN and copyright holders of ALICE O2. +// +// See https://alice-o2.web.cern.ch/copyright for details of the +// copyright holders. All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // POSIX only +#include // POISX only +#include + +namespace o2 +{ + namespace eventgen + { + GeneratorTParticle::~GeneratorTParticle() + { + if (mChain) { + TFile* file = mChain->GetCurrentFile(); + if (file) mChain->RecursiveRemove(file); + delete mChain; + } + if (mProgCmd.empty()) return; + + // Get the file we're reading from + std::filesystem::path p(mFileNames.front()); + + // Wait until child process creates the file + if (not std::filesystem::exists(p)) return; + + // Remove temporary file + std::error_code ec; + std::filesystem::remove(p,ec); + } + + void GeneratorTParticle::setFileNames(const std::string& val) + { + std::stringstream s; + std::string f; + while (std::getline(s,f,',')) + mFileNames.push_back(f); + } + + + Bool_t GeneratorTParticle::Init() + { + mChain = new TChain(mTreeName.c_str()); + mTParticles = new TClonesArray("TParticle"); + mChain->SetBranchAddress(mBranchName.c_str(), &mTParticles); + + if (not mProgCmd.empty()) { + // Set filename to be a temporary name + // Should perhaps use + // + // TString base("xxxxxx"); + // auto fp = gSystem->TempFileName(base); + // fclose(fp); + // + std::string filename = std::tmpnam(nullptr); + + // Build command line, Assumes command line parameter + // + // -n NUMBER of events to produce + // -o FILENAME of output file + // + // A script can be wrapped around existing EGs to ensure these + // options are observed. + std::string cmd = + mProgCmd + + " -n " + std::to_string(mNEvents) + + " -o " + filename + " &"; + LOG(info) << "EG command line is \"" << cmd << "\""; + + int ret = std::system(cmd.c_str()); + if (ret != 0) { + LOG(fatal) << "Failed to spawn \"" << cmd << "\""; + return false; + } + + mFileNames.clear(); + mFileNames.push_back(filename); + } + for (auto filename : mFileNames) + mChain->AddFile(filename.c_str()); + + return true; + } + + void GeneratorTParticle::waitForData() + { + if (mProgCmd.empty()) return; // Not from child process + + using namespace std::chrono_literals; + + // Get the file we're reading from + std::filesystem::path p(mFileNames.front()); + + LOG(info) << "Waiting for data on " << p; + + // Wait until child process creates the file + while (not std::filesystem::exists(p)) + std::this_thread::sleep_for(500ms); + + // Wait until we have more data in the file than just the file + // header + while (std::filesystem::file_size(p) <= 256) + std::this_thread::sleep_for(500ms); + + // Give the child process 1 second to post the data to the file + LOG(info) << "Got data in " << p << ", sleeping for a while"; + std::this_thread::sleep_for(1s); + } + + Bool_t GeneratorTParticle::generateEvent() + { + if (mEntry == 0) waitForData(); + + int read = mChain->GetEntry(mEntry); + mEntry++; + + if (read < 0) + LOG(error) << "Failed to read entry " << mEntry << " of chain"; + + if (read <= 0) return false; + + return true; + } + + Bool_t GeneratorTParticle::importParticles() + { + for (auto* object : *mTParticles) { + TParticle* particle = static_cast(object); + auto statusCode = particle->GetStatusCode(); + if (!mcgenstatus::isEncoded(statusCode)) + statusCode = mcgenstatus::MCGenStatusEncoding(statusCode, 0) + .fullEncoding; + + mParticles.emplace_back(particle->GetPdgCode(), + statusCode, + particle->GetFirstMother(), + particle->GetSecondMother(), + particle->GetFirstDaughter(), + particle->GetLastDaughter(), + particle->Px(), + particle->Py(), + particle->Pz(), + particle->Energy(), + particle->Vx(), + particle->Vy(), + particle->Vz(), + particle->T()); + auto& tgt = mParticles[mParticles.size()-1]; + tgt.SetPolarTheta(particle->GetPolarTheta()); + tgt.SetPolarPhi(particle->GetPolarPhi()); + tgt.SetCalcMass(particle->GetCalcMass()); + tgt.SetWeight(particle->GetWeight()); + } + return true; + } + } +} +// +// EOF +// + + + + + + + diff --git a/Generators/src/GeneratorTParticleParam.cxx b/Generators/src/GeneratorTParticleParam.cxx new file mode 100644 index 0000000000000..65289c2c1e48b --- /dev/null +++ b/Generators/src/GeneratorTParticleParam.cxx @@ -0,0 +1,19 @@ +// Copyright 2023 CERN and copyright holders of ALICE O2. +// +// See https://alice-o2.web.cern.ch/copyright for details of the +// copyright holders. All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen + +#include "Generators/GeneratorTParticleParam.h" +O2ParamImpl(o2::eventgen::GeneratorTParticleParam); +// +// EOF +// diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 0d42b2ce505b6..26f270c9a0a39 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -67,5 +67,8 @@ #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::QEDGenParam> + ; #pragma link C++ class o2::eventgen::GenCosmicsParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GenCosmicsParam> + ; +#pragma link C++ class o2::eventgen::GeneratorTParticle +; +#pragma link C++ class o2::eventgen::GeneratorTParticleParam +; +#pragma link C++ class o2::conf::ConfigurableParamHelper +; #endif From 0558c4b18dc035040f5ca5de604a5af53b1d348a Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Tue, 19 Sep 2023 12:50:45 +0000 Subject: [PATCH 05/37] Please consider the following formatting changes --- .../SimulationDataFormat/MCEventHeader.h | 121 ++++--- .../include/Generators/GeneratorHepMC.h | 3 +- .../include/Generators/GeneratorHepMCParam.h | 2 +- .../include/Generators/GeneratorTParticle.h | 152 +++++---- .../Generators/GeneratorTParticleParam.h | 30 +- Generators/src/GeneratorFactory.cxx | 5 +- Generators/src/GeneratorHepMC.cxx | 171 +++++----- Generators/src/GeneratorPythia8.cxx | 53 ++-- Generators/src/GeneratorTParticle.cxx | 294 +++++++++--------- Generators/src/GeneratorsLinkDef.h | 6 +- 10 files changed, 415 insertions(+), 422 deletions(-) diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h index afebbbada470d..f37ce3b345dd8 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h @@ -27,67 +27,66 @@ namespace dataformats class GeneratorHeader; - /** Common keys for information in MC event header */ - struct MCInfoKeys { - /** @{ - @name HepMC3 heavy-ion fields */ - static constexpr const char* impactParameter = "Bimpact"; - static constexpr const char* nPart = "Npart"; - static constexpr const char* nPartProjectile = "Npart_proj"; - static constexpr const char* nPartTarget = "Npart_targ"; - static constexpr const char* nColl = "Ncoll"; - static constexpr const char* nCollHard = "Ncoll_hard"; - static constexpr const char* nCollNNWounded = "NColl_NNw"; - static constexpr const char* nCollNWoundedN = "NColl_NwN"; - static constexpr const char* nCollNWoundedNwounded = "NColl_NwNW"; - static constexpr const char* planeAngle = "eventPsi"; - static constexpr const char* sigmaInelNN = "sigmaInelNN"; - static constexpr const char* centrality = "centrality"; - static constexpr const char* nSpecProjectileProton = "Nspec_proj_p"; - static constexpr const char* nSpecProjectileNeutron = "Nspec_proj_n"; - static constexpr const char* nSpecTargetProton = "Nspec_targ_p"; - static constexpr const char* nSpecTargetNeutron = "Nspec_targ_n"; - /** @} */ - /** @{ - @name HepMC3 PDF information - - In principle a header can have many of these. In that case, - each set should be prefixed with "_" where "" is a - serial number. - */ - static constexpr const char* pdfParton1Id = "pdf_parton_1_id"; - static constexpr const char* pdfParton2Id = "pdf_parton_2_id"; - static constexpr const char* pdfX1 = "pdf_x1"; - static constexpr const char* pdfX2 = "pdf_x2"; - static constexpr const char* pdfScale = "pdf_scale"; - static constexpr const char* pdfXF1 = "pdf_par_x1"; - static constexpr const char* pdfXF2 = "pdf_par_x2"; - static constexpr const char* pdfCode1 = "pdf_lhc_1_id"; - static constexpr const char* pdfCode2 = "pdf_lhc_2_id"; - /** @} */ - /** @{ - @name HepMC3 cross-section information - - In principle we can have one cross section per weight. In that - case, each should be post-fixed by "_" where "" is a - serial number. These should then matcht possible names of - weights. - */ - static constexpr const char* acceptedEvents = "accepted_events"; - static constexpr const char* attemptedEvents = "attempted_events"; - static constexpr const char* xSection = "cross_section"; - static constexpr const char* xSectionError = "cross_section_error"; - /** @} */ - /** @{ - @name Common fields */ - static constexpr const char* generator = "generator"; - static constexpr const char* generatorVersion = "version"; - static constexpr const char* processName = "processName"; - static constexpr const char* processCode = "processCode"; - static constexpr const char* weight = "weight"; - /** @} */ - - }; +/** Common keys for information in MC event header */ +struct MCInfoKeys { + /** @{ +@name HepMC3 heavy-ion fields */ + static constexpr const char* impactParameter = "Bimpact"; + static constexpr const char* nPart = "Npart"; + static constexpr const char* nPartProjectile = "Npart_proj"; + static constexpr const char* nPartTarget = "Npart_targ"; + static constexpr const char* nColl = "Ncoll"; + static constexpr const char* nCollHard = "Ncoll_hard"; + static constexpr const char* nCollNNWounded = "NColl_NNw"; + static constexpr const char* nCollNWoundedN = "NColl_NwN"; + static constexpr const char* nCollNWoundedNwounded = "NColl_NwNW"; + static constexpr const char* planeAngle = "eventPsi"; + static constexpr const char* sigmaInelNN = "sigmaInelNN"; + static constexpr const char* centrality = "centrality"; + static constexpr const char* nSpecProjectileProton = "Nspec_proj_p"; + static constexpr const char* nSpecProjectileNeutron = "Nspec_proj_n"; + static constexpr const char* nSpecTargetProton = "Nspec_targ_p"; + static constexpr const char* nSpecTargetNeutron = "Nspec_targ_n"; + /** @} */ + /** @{ +@name HepMC3 PDF information + +In principle a header can have many of these. In that case, +each set should be prefixed with "_" where "" is a +serial number. + */ + static constexpr const char* pdfParton1Id = "pdf_parton_1_id"; + static constexpr const char* pdfParton2Id = "pdf_parton_2_id"; + static constexpr const char* pdfX1 = "pdf_x1"; + static constexpr const char* pdfX2 = "pdf_x2"; + static constexpr const char* pdfScale = "pdf_scale"; + static constexpr const char* pdfXF1 = "pdf_par_x1"; + static constexpr const char* pdfXF2 = "pdf_par_x2"; + static constexpr const char* pdfCode1 = "pdf_lhc_1_id"; + static constexpr const char* pdfCode2 = "pdf_lhc_2_id"; + /** @} */ + /** @{ +@name HepMC3 cross-section information + +In principle we can have one cross section per weight. In that +case, each should be post-fixed by "_" where "" is a +serial number. These should then matcht possible names of +weights. + */ + static constexpr const char* acceptedEvents = "accepted_events"; + static constexpr const char* attemptedEvents = "attempted_events"; + static constexpr const char* xSection = "cross_section"; + static constexpr const char* xSectionError = "cross_section_error"; + /** @} */ + /** @{ +@name Common fields */ + static constexpr const char* generator = "generator"; + static constexpr const char* generatorVersion = "version"; + static constexpr const char* processName = "processName"; + static constexpr const char* processCode = "processCode"; + static constexpr const char* weight = "weight"; + /** @} */ +}; /*****************************************************************/ /*****************************************************************/ diff --git a/Generators/include/Generators/GeneratorHepMC.h b/Generators/include/Generators/GeneratorHepMC.h index 4244f25be6327..8bcc567dd768b 100644 --- a/Generators/include/Generators/GeneratorHepMC.h +++ b/Generators/include/Generators/GeneratorHepMC.h @@ -65,6 +65,7 @@ class GeneratorHepMC : public Generator void setProgCmd(std::string val) { mProgCmd = val; }; void setEventsToSkip(uint64_t val) { mEventsToSkip = val; }; void setNEvents(unsigned int val) { mNEvents = val; } + protected: /** copy constructor **/ GeneratorHepMC(const GeneratorHepMC&); @@ -80,7 +81,7 @@ class GeneratorHepMC : public Generator /** methods that can be overridded **/ void updateHeader(o2::dataformats::MCEventHeader* eventHeader) override; - + /** HepMC interface **/ std::ifstream mStream; //! std::string mFileName; diff --git a/Generators/include/Generators/GeneratorHepMCParam.h b/Generators/include/Generators/GeneratorHepMCParam.h index 8cfd0a31cdd74..b44841df3cb61 100644 --- a/Generators/include/Generators/GeneratorHepMCParam.h +++ b/Generators/include/Generators/GeneratorHepMCParam.h @@ -31,7 +31,7 @@ namespace eventgen struct GeneratorHepMCParam : public o2::conf::ConfigurableParamHelper { std::string fileName = ""; - std::string progCmd = "";//Program command line to spawn, must write HepMC on stdout + std::string progCmd = ""; // Program command line to spawn, must write HepMC on stdout int version = 2; uint64_t eventsToSkip = 0; O2ParamDef(GeneratorHepMCParam, "HepMC"); diff --git a/Generators/include/Generators/GeneratorTParticle.h b/Generators/include/Generators/GeneratorTParticle.h index 4c69bd8c27a09..1dc87dac4c939 100644 --- a/Generators/include/Generators/GeneratorTParticle.h +++ b/Generators/include/Generators/GeneratorTParticle.h @@ -27,91 +27,89 @@ class TClonesArray; namespace o2 { - namespace eventgen +namespace eventgen +{ +/// A class that reads in particles of class @c TParticle from a +/// branch in a @c TChain. +/// +/// Optionally, a program that generates such a @c TTree can be +/// spawn, and the @c TParticles written to a file from which this +/// object reads them in. This is done with +/// +/// --configKeyValues "TParticle.progCmd=" +/// +/// which will execute the specified EG program with the given +/// options. The EG program _must_ support the command line options +/// +/// -n NUMBER Number of events to generate +/// -o FILENAME Name of file to write to +/// +/// The tree name and particle branch names can be configured. +/// +/// --configKeyValues "TParticle.treeName=T,TParticle.branchName=P" +/// +/// File(s) to read are also configurable +/// +/// --configKeyValues "TParticle.fileNames=foo.root,bar.root" +/// +class GeneratorTParticle : public Generator +{ + public: + /** CTOR */ + GeneratorTParticle() = default; + /** CTOR */ + GeneratorTParticle(const std::string& name) + : Generator(name.c_str(), "ALICEo2 TParticle Generator") { - /// A class that reads in particles of class @c TParticle from a - /// branch in a @c TChain. - /// - /// Optionally, a program that generates such a @c TTree can be - /// spawn, and the @c TParticles written to a file from which this - /// object reads them in. This is done with - /// - /// --configKeyValues "TParticle.progCmd=" - /// - /// which will execute the specified EG program with the given - /// options. The EG program _must_ support the command line options - /// - /// -n NUMBER Number of events to generate - /// -o FILENAME Name of file to write to - /// - /// The tree name and particle branch names can be configured. - /// - /// --configKeyValues "TParticle.treeName=T,TParticle.branchName=P" - /// - /// File(s) to read are also configurable - /// - /// --configKeyValues "TParticle.fileNames=foo.root,bar.root" - /// - class GeneratorTParticle : public Generator - { - public: - /** CTOR */ - GeneratorTParticle() = default; - /** CTOR */ - GeneratorTParticle(const std::string& name) - : Generator(name.c_str(),"ALICEo2 TParticle Generator") - {} - /** DTOR */ - virtual ~GeneratorTParticle(); + } + /** DTOR */ + virtual ~GeneratorTParticle(); - /** Initialize this generator. This will set up the chain. - Optionally, if a command line was specified by @c - TParticle.progCmd then that command line is executed in the - background and events are read from the output file of that - program */ - Bool_t Init() override; + /** Initialize this generator. This will set up the chain. +Optionally, if a command line was specified by @c +TParticle.progCmd then that command line is executed in the +background and events are read from the output file of that +program */ + Bool_t Init() override; - /** Read in the next entry from the chain. Returns false in - case of errors or no more entries to read. */ - Bool_t generateEvent() override; + /** Read in the next entry from the chain. Returns false in +case of errors or no more entries to read. */ + Bool_t generateEvent() override; - /** Import the read-in particles into the steer particle - stack */ - Bool_t importParticles() override; + /** Import the read-in particles into the steer particle +stack */ + Bool_t importParticles() override; - /** Set the names of files to read, separated by commas */ - void setFileNames(const std::string& val); - /** Set the name of the tree in the files. The tree _must_ - reside in the top-level directory of the files. */ - void setTreeName(const std::string& val) { mTreeName = val; } - /** Set the branch name of the branch that holds a @c - TClonesArray of @c TParticle objects */ - void setBranchName(const std::string& val) { mBranchName = val; } - /** Set child program command line to (optionally) execute */ - void setProgCmd(const std::string& val) { mProgCmd = val; } - /** Set the number of events to generate. */ - void setNEvents(unsigned int nev) { mNEvents = nev; } - protected: - std::string mTreeName = "T"; - std::string mBranchName = "Particles"; - std::string mProgCmd = ""; - std::list mFileNames; - unsigned int mNEvents = 0; - unsigned int mEntry = 0; - TChain* mChain; - TClonesArray* mTParticles; + /** Set the names of files to read, separated by commas */ + void setFileNames(const std::string& val); + /** Set the name of the tree in the files. The tree _must_ +reside in the top-level directory of the files. */ + void setTreeName(const std::string& val) { mTreeName = val; } + /** Set the branch name of the branch that holds a @c +TClonesArray of @c TParticle objects */ + void setBranchName(const std::string& val) { mBranchName = val; } + /** Set child program command line to (optionally) execute */ + void setProgCmd(const std::string& val) { mProgCmd = val; } + /** Set the number of events to generate. */ + void setNEvents(unsigned int nev) { mNEvents = nev; } - void waitForData(); + protected: + std::string mTreeName = "T"; + std::string mBranchName = "Particles"; + std::string mProgCmd = ""; + std::list mFileNames; + unsigned int mNEvents = 0; + unsigned int mEntry = 0; + TChain* mChain; + TClonesArray* mTParticles; - ClassDefOverride(GeneratorTParticle,1); - }; - } -} + void waitForData(); + + ClassDefOverride(GeneratorTParticle, 1); +}; +} // namespace eventgen +} // namespace o2 #endif // // EOF // - - - - diff --git a/Generators/include/Generators/GeneratorTParticleParam.h b/Generators/include/Generators/GeneratorTParticleParam.h index d293f9c0e2957..46c003e112f51 100644 --- a/Generators/include/Generators/GeneratorTParticleParam.h +++ b/Generators/include/Generators/GeneratorTParticleParam.h @@ -11,7 +11,7 @@ // immunities granted to it by virtue of its status as an // Intergovernmental Organization or submit itself to any // jurisdiction. -// +// // @author: Christian Holm Christensen #ifndef ALICEO2_EVENTGEN_GENERATORTPARTICLEPARAM_H_ #define ALICEO2_EVENTGEN_GENERATORTPARTICLEPARAM_H_ @@ -22,22 +22,20 @@ namespace o2 { - namespace eventgen - { +namespace eventgen +{ - /** - a parameter class/struct to keep the settings of the TGenerator - event generator and allow the user to modify them */ - struct GeneratorTParticleParam : - public o2::conf::ConfigurableParamHelper - { - std::string treeName = "T"; - std::string branchName = "Particles"; - std::string fileNames = "tparticle.root"; - std::string progCmd = ""; - O2ParamDef(GeneratorTParticleParam, "TParticle"); - }; - } // end namespace eventgen +/** + a parameter class/struct to keep the settings of the TGenerator + event generator and allow the user to modify them */ +struct GeneratorTParticleParam : public o2::conf::ConfigurableParamHelper { + std::string treeName = "T"; + std::string branchName = "Particles"; + std::string fileNames = "tparticle.root"; + std::string progCmd = ""; + O2ParamDef(GeneratorTParticleParam, "TParticle"); +}; +} // end namespace eventgen } // end namespace o2 #endif // ALICEO2_EVENTGEN_GENERATORHEPMCPARAM_H_ diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index 628ca885bbf0e..e572b5594e71e 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -157,10 +157,11 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair if (o2PrimGen) { o2PrimGen->setApplyVertex(false); } - } LOG(info) << "using external O2 kinematics"; + } + LOG(info) << "using external O2 kinematics"; } else if (genconfig.compare("tparticle") == 0) { // External ROOT file(s) with tree of TParticle in clones array, - // or external program generating such a file + // or external program generating such a file auto& param = GeneratorTParticleParam::Instance(); LOG(info) << "Init 'GeneratorTParticle' with the following parameters"; LOG(info) << param; diff --git a/Generators/src/GeneratorHepMC.cxx b/Generators/src/GeneratorHepMC.cxx index 56d0e80248a00..2741f98f57cc9 100644 --- a/Generators/src/GeneratorHepMC.cxx +++ b/Generators/src/GeneratorHepMC.cxx @@ -151,72 +151,71 @@ Bool_t GeneratorHepMC::importParticles() return kTRUE; } - namespace - { - void putAttributeInfo(o2::dataformats::MCEventHeader* eventHeader, - const std::string& name, - const std::shared_ptr& a) - { - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name,p->value()); - } - } - - +namespace +{ +void putAttributeInfo(o2::dataformats::MCEventHeader* eventHeader, + const std::string& name, + const std::shared_ptr& a) +{ + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); + if (auto* p = dynamic_cast(a.get())) + eventHeader->putInfo(name, p->value()); +} +} // namespace + /*****************************************************************/ void GeneratorHepMC::updateHeader(o2::dataformats::MCEventHeader* eventHeader) { /** update header **/ - using Key=o2::dataformats::MCInfoKeys; + using Key = o2::dataformats::MCInfoKeys; eventHeader->putInfo(Key::generator, "hepmc"); eventHeader->putInfo(Key::generatorVersion, HEPMC3_VERSION_CODE); auto xSection = mEvent->cross_section(); - auto pdfInfo = mEvent->pdf_info(); - auto hiInfo = mEvent->heavy_ion(); + auto pdfInfo = mEvent->pdf_info(); + auto hiInfo = mEvent->heavy_ion(); - // Set default cross-section + // Set default cross-section if (xSection) { - eventHeader->putInfo(Key::xSection, xSection->xsec()); + eventHeader->putInfo(Key::xSection, xSection->xsec()); eventHeader->putInfo(Key::xSectionError, xSection->xsec_err()); eventHeader->putInfo(Key::acceptedEvents, - xSection->get_accepted_events()); + xSection->get_accepted_events()); eventHeader->putInfo(Key::attemptedEvents, - xSection->get_attempted_events()); + xSection->get_attempted_events()); } - // Set weights and cross sections + // Set weights and cross sections size_t iw = 0; for (auto w : mEvent->weights()) { - std::string post = (iw > 0 ? "_"+std::to_string(iw) : ""); - eventHeader->putInfo(Key::weight+post, w); + std::string post = (iw > 0 ? "_" + std::to_string(iw) : ""); + eventHeader->putInfo(Key::weight + post, w); if (xSection) { - eventHeader->putInfo(Key::xSection, xSection->xsec(iw)); - eventHeader->putInfo(Key::xSectionError,xSection->xsec_err(iw)); + eventHeader->putInfo(Key::xSection, xSection->xsec(iw)); + eventHeader->putInfo(Key::xSectionError, xSection->xsec_err(iw)); } iw++; } @@ -225,59 +224,59 @@ void GeneratorHepMC::updateHeader(o2::dataformats::MCEventHeader* eventHeader) if (pdfInfo) { eventHeader->putInfo(Key::pdfParton1Id, pdfInfo->parton_id[0]); eventHeader->putInfo(Key::pdfParton2Id, pdfInfo->parton_id[1]); - eventHeader->putInfo(Key::pdfX1, pdfInfo->x[0]); - eventHeader->putInfo(Key::pdfX2, pdfInfo->x[1]); - eventHeader->putInfo(Key::pdfScale, pdfInfo->scale); - eventHeader->putInfo(Key::pdfXF1, pdfInfo->xf[0]); - eventHeader->putInfo(Key::pdfXF2, pdfInfo->xf[1]); - eventHeader->putInfo(Key::pdfCode1, pdfInfo->pdf_id[0]); - eventHeader->putInfo(Key::pdfCode2, pdfInfo->pdf_id[1]); + eventHeader->putInfo(Key::pdfX1, pdfInfo->x[0]); + eventHeader->putInfo(Key::pdfX2, pdfInfo->x[1]); + eventHeader->putInfo(Key::pdfScale, pdfInfo->scale); + eventHeader->putInfo(Key::pdfXF1, pdfInfo->xf[0]); + eventHeader->putInfo(Key::pdfXF2, pdfInfo->xf[1]); + eventHeader->putInfo(Key::pdfCode1, pdfInfo->pdf_id[0]); + eventHeader->putInfo(Key::pdfCode2, pdfInfo->pdf_id[1]); } // Set heavy-ion information if (hiInfo) { - eventHeader->putInfo(Key::impactParameter , - hiInfo->impact_parameter); - eventHeader->putInfo(Key::nPart , - hiInfo->Npart_proj+hiInfo->Npart_targ); - eventHeader->putInfo(Key::nPartProjectile ,hiInfo->Npart_proj); - eventHeader->putInfo(Key::nPartTarget ,hiInfo->Npart_targ); - eventHeader->putInfo(Key::nColl ,hiInfo->Ncoll); - eventHeader->putInfo(Key::nCollHard ,hiInfo->Ncoll_hard); - eventHeader->putInfo(Key::nCollNNWounded , - hiInfo->N_Nwounded_collisions); - eventHeader->putInfo(Key::nCollNWoundedN , - hiInfo->Nwounded_N_collisions); - eventHeader->putInfo(Key::nCollNWoundedNwounded , - hiInfo->Nwounded_Nwounded_collisions); - eventHeader->putInfo(Key::planeAngle , - hiInfo->event_plane_angle); - eventHeader->putInfo(Key::sigmaInelNN , - hiInfo->sigma_inel_NN); - eventHeader->putInfo(Key::centrality ,hiInfo->centrality); - eventHeader->putInfo(Key::nSpecProjectileProton ,hiInfo->Nspec_proj_p); - eventHeader->putInfo(Key::nSpecProjectileNeutron,hiInfo->Nspec_proj_n); - eventHeader->putInfo(Key::nSpecTargetProton ,hiInfo->Nspec_targ_p); - eventHeader->putInfo(Key::nSpecTargetNeutron ,hiInfo->Nspec_targ_n); + eventHeader->putInfo(Key::impactParameter, + hiInfo->impact_parameter); + eventHeader->putInfo(Key::nPart, + hiInfo->Npart_proj + hiInfo->Npart_targ); + eventHeader->putInfo(Key::nPartProjectile, hiInfo->Npart_proj); + eventHeader->putInfo(Key::nPartTarget, hiInfo->Npart_targ); + eventHeader->putInfo(Key::nColl, hiInfo->Ncoll); + eventHeader->putInfo(Key::nCollHard, hiInfo->Ncoll_hard); + eventHeader->putInfo(Key::nCollNNWounded, + hiInfo->N_Nwounded_collisions); + eventHeader->putInfo(Key::nCollNWoundedN, + hiInfo->Nwounded_N_collisions); + eventHeader->putInfo(Key::nCollNWoundedNwounded, + hiInfo->Nwounded_Nwounded_collisions); + eventHeader->putInfo(Key::planeAngle, + hiInfo->event_plane_angle); + eventHeader->putInfo(Key::sigmaInelNN, + hiInfo->sigma_inel_NN); + eventHeader->putInfo(Key::centrality, hiInfo->centrality); + eventHeader->putInfo(Key::nSpecProjectileProton, hiInfo->Nspec_proj_p); + eventHeader->putInfo(Key::nSpecProjectileNeutron, hiInfo->Nspec_proj_n); + eventHeader->putInfo(Key::nSpecTargetProton, hiInfo->Nspec_targ_p); + eventHeader->putInfo(Key::nSpecTargetNeutron, hiInfo->Nspec_targ_n); } for (auto na : mEvent->attributes()) { std::string name = na.first; if (name == "GenPdfInfo" || - name == "GenCrossSection" || - name == "GenHeavyIon") continue; + name == "GenCrossSection" || + name == "GenHeavyIon") + continue; for (auto ia : na.second) { - int no = ia.first; + int no = ia.first; auto at = ia.second; std::string post = (no == 0 ? "" : std::to_string(no)); - - putAttributeInfo(eventHeader, name+post, at); + + putAttributeInfo(eventHeader, name + post, at); } } } - - + /*****************************************************************/ Bool_t GeneratorHepMC::Init() @@ -317,10 +316,10 @@ Bool_t GeneratorHepMC::Init() // TString base("xxxxxx"); // auto fp = gSystem->TempFileName(base); // fclose(fp); - // + // filename = std::tmpnam(nullptr); - // Make a fifo + // Make a fifo int ret = mkfifo(filename.c_str(), 0600); if (ret != 0) { LOG(fatal) << "Failed to make fifo \"" << filename << "\""; @@ -328,7 +327,7 @@ Bool_t GeneratorHepMC::Init() } // Build command line, rediret stdout to our fifo and put - // in the background. + // in the background. std::string cmd = mProgCmd + " -n " + std::to_string(mNEvents) + diff --git a/Generators/src/GeneratorPythia8.cxx b/Generators/src/GeneratorPythia8.cxx index c055bf2718f26..442e93976546f 100644 --- a/Generators/src/GeneratorPythia8.cxx +++ b/Generators/src/GeneratorPythia8.cxx @@ -202,8 +202,8 @@ Bool_t void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) { /** update header **/ - using Key=o2::dataformats::MCInfoKeys; - + using Key = o2::dataformats::MCInfoKeys; + eventHeader->putInfo(Key::generator, "pythia8"); eventHeader->putInfo(Key::generatorVersion, PYTHIA_VERSION_INTEGER); eventHeader->putInfo(Key::processName, mPythia.info.name()); @@ -211,31 +211,31 @@ void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) eventHeader->putInfo(Key::weight, mPythia.info.weight()); auto& info = mPythia.info; - + // Set PDF information - eventHeader->putInfo (Key::pdfParton1Id, info.id1pdf()); - eventHeader->putInfo (Key::pdfParton2Id, info.id2pdf()); - eventHeader->putInfo(Key::pdfX1, info.x1pdf()); - eventHeader->putInfo(Key::pdfX2, info.x2pdf()); - eventHeader->putInfo(Key::pdfScale, info.QFac()); - eventHeader->putInfo(Key::pdfXF1, info.pdf1()); - eventHeader->putInfo(Key::pdfXF2, info.pdf2()); + eventHeader->putInfo(Key::pdfParton1Id, info.id1pdf()); + eventHeader->putInfo(Key::pdfParton2Id, info.id2pdf()); + eventHeader->putInfo(Key::pdfX1, info.x1pdf()); + eventHeader->putInfo(Key::pdfX2, info.x2pdf()); + eventHeader->putInfo(Key::pdfScale, info.QFac()); + eventHeader->putInfo(Key::pdfXF1, info.pdf1()); + eventHeader->putInfo(Key::pdfXF2, info.pdf2()); // Set cross section - eventHeader->putInfo(Key::xSection, info.sigmaGen()*1e9); - eventHeader->putInfo(Key::xSectionError,info.sigmaErr()*1e9); + eventHeader->putInfo(Key::xSection, info.sigmaGen() * 1e9); + eventHeader->putInfo(Key::xSectionError, info.sigmaErr() * 1e9); // Set weights (overrides cross-section for each weight) size_t iw = 0; auto xsecErr = info.weightContainerPtr->getTotalXsecErr(); for (auto w : info.weightContainerPtr->getTotalXsec()) { - std::string post = (iw == 0 ? "" : "_"+std::to_string(iw)); - eventHeader->putInfo(Key::weight+post, info.weightValueByIndex(iw)); - eventHeader->putInfo(Key::xSection+post,w*1e9); - eventHeader->putInfo(Key::xSectionError+post,xsecErr[iw]*1e9); + std::string post = (iw == 0 ? "" : "_" + std::to_string(iw)); + eventHeader->putInfo(Key::weight + post, info.weightValueByIndex(iw)); + eventHeader->putInfo(Key::xSection + post, w * 1e9); + eventHeader->putInfo(Key::xSectionError + post, xsecErr[iw] * 1e9); iw++; } - + #if PYTHIA_VERSION_INTEGER < 8300 auto hiinfo = mPythia.info.hiinfo; #else @@ -274,17 +274,16 @@ void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) eventHeader->putInfo("Nfree_targ_p", nFreeProtonTarg); // --- HepMC3 conforming information --- - // This is how the Pythia authors define Ncoll + // This is how the Pythia authors define Ncoll // eventHeader->putInfo(Key::nColl, // hiinfo->nAbsProj() + hiinfo->nDiffProj() + // hiinfo->nAbsTarg() + hiinfo->nDiffTarg() - // hiiinfo->nCollND() - hiinfo->nCollDD()); eventHeader->putInfo(Key::nPartProjectile, - hiinfo->nAbsProj()+hiinfo->nDiffProj()); + hiinfo->nAbsProj() + hiinfo->nDiffProj()); eventHeader->putInfo(Key::nPartTarget, - hiinfo->nAbsTarg()+hiinfo->nDiffTarg()); + hiinfo->nAbsTarg() + hiinfo->nDiffTarg()); eventHeader->putInfo(Key::nCollHard, hiinfo->nCollNDTot()); - } } @@ -344,9 +343,9 @@ void GeneratorPythia8::getNcoll(const Pythia8::Info& info, int& nColl) #endif // This is how the Pythia authors define Ncoll - nColl = (hiinfo->nAbsProj()+hiinfo->nDiffProj()+ - hiinfo->nAbsTarg()+hiinfo->nDiffTarg()- - hiinfo->nCollND() -hiinfo->nCollDD()); + nColl = (hiinfo->nAbsProj() + hiinfo->nDiffProj() + + hiinfo->nAbsTarg() + hiinfo->nDiffTarg() - + hiinfo->nCollND() - hiinfo->nCollDD()); nColl = 0; if (!hiinfo) { @@ -381,10 +380,10 @@ void GeneratorPythia8::getNpart(const Pythia8::Info& info, int& nPart) #else auto hiinfo = info.hiInfo; #endif - if (hiinfo) + if (hiinfo) nPart = (hiinfo->nAbsProj() + hiinfo->nDiffProj() + - hiinfo->nAbsTarg() + hiinfo->nDiffTarg()); - + hiinfo->nAbsTarg() + hiinfo->nDiffTarg()); + int nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg; getNpart(info, nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg); nPart = nProtonProj + nNeutronProj + nProtonTarg + nNeutronTarg; diff --git a/Generators/src/GeneratorTParticle.cxx b/Generators/src/GeneratorTParticle.cxx index 2f4400448a368..eb84a2bcfbe11 100644 --- a/Generators/src/GeneratorTParticle.cxx +++ b/Generators/src/GeneratorTParticle.cxx @@ -29,161 +29,159 @@ namespace o2 { - namespace eventgen - { - GeneratorTParticle::~GeneratorTParticle() - { - if (mChain) { - TFile* file = mChain->GetCurrentFile(); - if (file) mChain->RecursiveRemove(file); - delete mChain; - } - if (mProgCmd.empty()) return; - - // Get the file we're reading from - std::filesystem::path p(mFileNames.front()); - - // Wait until child process creates the file - if (not std::filesystem::exists(p)) return; - - // Remove temporary file - std::error_code ec; - std::filesystem::remove(p,ec); - } - - void GeneratorTParticle::setFileNames(const std::string& val) - { - std::stringstream s; - std::string f; - while (std::getline(s,f,',')) - mFileNames.push_back(f); - } +namespace eventgen +{ +GeneratorTParticle::~GeneratorTParticle() +{ + if (mChain) { + TFile* file = mChain->GetCurrentFile(); + if (file) + mChain->RecursiveRemove(file); + delete mChain; + } + if (mProgCmd.empty()) + return; + // Get the file we're reading from + std::filesystem::path p(mFileNames.front()); - Bool_t GeneratorTParticle::Init() - { - mChain = new TChain(mTreeName.c_str()); - mTParticles = new TClonesArray("TParticle"); - mChain->SetBranchAddress(mBranchName.c_str(), &mTParticles); - - if (not mProgCmd.empty()) { - // Set filename to be a temporary name - // Should perhaps use - // - // TString base("xxxxxx"); - // auto fp = gSystem->TempFileName(base); - // fclose(fp); - // - std::string filename = std::tmpnam(nullptr); - - // Build command line, Assumes command line parameter - // - // -n NUMBER of events to produce - // -o FILENAME of output file - // - // A script can be wrapped around existing EGs to ensure these - // options are observed. - std::string cmd = - mProgCmd + - " -n " + std::to_string(mNEvents) + - " -o " + filename + " &"; - LOG(info) << "EG command line is \"" << cmd << "\""; - - int ret = std::system(cmd.c_str()); - if (ret != 0) { - LOG(fatal) << "Failed to spawn \"" << cmd << "\""; - return false; - } - - mFileNames.clear(); - mFileNames.push_back(filename); - } - for (auto filename : mFileNames) - mChain->AddFile(filename.c_str()); - - return true; - } + // Wait until child process creates the file + if (not std::filesystem::exists(p)) + return; - void GeneratorTParticle::waitForData() - { - if (mProgCmd.empty()) return; // Not from child process - - using namespace std::chrono_literals; - - // Get the file we're reading from - std::filesystem::path p(mFileNames.front()); - - LOG(info) << "Waiting for data on " << p; - - // Wait until child process creates the file - while (not std::filesystem::exists(p)) - std::this_thread::sleep_for(500ms); - - // Wait until we have more data in the file than just the file - // header - while (std::filesystem::file_size(p) <= 256) - std::this_thread::sleep_for(500ms); - - // Give the child process 1 second to post the data to the file - LOG(info) << "Got data in " << p << ", sleeping for a while"; - std::this_thread::sleep_for(1s); - } - - Bool_t GeneratorTParticle::generateEvent() - { - if (mEntry == 0) waitForData(); - - int read = mChain->GetEntry(mEntry); - mEntry++; - - if (read < 0) - LOG(error) << "Failed to read entry " << mEntry << " of chain"; - - if (read <= 0) return false; - - return true; - } + // Remove temporary file + std::error_code ec; + std::filesystem::remove(p, ec); +} - Bool_t GeneratorTParticle::importParticles() - { - for (auto* object : *mTParticles) { - TParticle* particle = static_cast(object); - auto statusCode = particle->GetStatusCode(); - if (!mcgenstatus::isEncoded(statusCode)) - statusCode = mcgenstatus::MCGenStatusEncoding(statusCode, 0) - .fullEncoding; - - mParticles.emplace_back(particle->GetPdgCode(), - statusCode, - particle->GetFirstMother(), - particle->GetSecondMother(), - particle->GetFirstDaughter(), - particle->GetLastDaughter(), - particle->Px(), - particle->Py(), - particle->Pz(), - particle->Energy(), - particle->Vx(), - particle->Vy(), - particle->Vz(), - particle->T()); - auto& tgt = mParticles[mParticles.size()-1]; - tgt.SetPolarTheta(particle->GetPolarTheta()); - tgt.SetPolarPhi(particle->GetPolarPhi()); - tgt.SetCalcMass(particle->GetCalcMass()); - tgt.SetWeight(particle->GetWeight()); - } - return true; +void GeneratorTParticle::setFileNames(const std::string& val) +{ + std::stringstream s; + std::string f; + while (std::getline(s, f, ',')) + mFileNames.push_back(f); +} + +Bool_t GeneratorTParticle::Init() +{ + mChain = new TChain(mTreeName.c_str()); + mTParticles = new TClonesArray("TParticle"); + mChain->SetBranchAddress(mBranchName.c_str(), &mTParticles); + + if (not mProgCmd.empty()) { + // Set filename to be a temporary name + // Should perhaps use + // + // TString base("xxxxxx"); + // auto fp = gSystem->TempFileName(base); + // fclose(fp); + // + std::string filename = std::tmpnam(nullptr); + + // Build command line, Assumes command line parameter + // + // -n NUMBER of events to produce + // -o FILENAME of output file + // + // A script can be wrapped around existing EGs to ensure these + // options are observed. + std::string cmd = + mProgCmd + + " -n " + std::to_string(mNEvents) + + " -o " + filename + " &"; + LOG(info) << "EG command line is \"" << cmd << "\""; + + int ret = std::system(cmd.c_str()); + if (ret != 0) { + LOG(fatal) << "Failed to spawn \"" << cmd << "\""; + return false; } + + mFileNames.clear(); + mFileNames.push_back(filename); } + for (auto filename : mFileNames) + mChain->AddFile(filename.c_str()); + + return true; } -// -// EOF -// - - +void GeneratorTParticle::waitForData() +{ + if (mProgCmd.empty()) + return; // Not from child process + + using namespace std::chrono_literals; + + // Get the file we're reading from + std::filesystem::path p(mFileNames.front()); + + LOG(info) << "Waiting for data on " << p; + + // Wait until child process creates the file + while (not std::filesystem::exists(p)) + std::this_thread::sleep_for(500ms); + + // Wait until we have more data in the file than just the file + // header + while (std::filesystem::file_size(p) <= 256) + std::this_thread::sleep_for(500ms); + + // Give the child process 1 second to post the data to the file + LOG(info) << "Got data in " << p << ", sleeping for a while"; + std::this_thread::sleep_for(1s); +} + +Bool_t GeneratorTParticle::generateEvent() +{ + if (mEntry == 0) + waitForData(); + + int read = mChain->GetEntry(mEntry); + mEntry++; - + if (read < 0) + LOG(error) << "Failed to read entry " << mEntry << " of chain"; - + if (read <= 0) + return false; + + return true; +} + +Bool_t GeneratorTParticle::importParticles() +{ + for (auto* object : *mTParticles) { + TParticle* particle = static_cast(object); + auto statusCode = particle->GetStatusCode(); + if (!mcgenstatus::isEncoded(statusCode)) + statusCode = mcgenstatus::MCGenStatusEncoding(statusCode, 0) + .fullEncoding; + + mParticles.emplace_back(particle->GetPdgCode(), + statusCode, + particle->GetFirstMother(), + particle->GetSecondMother(), + particle->GetFirstDaughter(), + particle->GetLastDaughter(), + particle->Px(), + particle->Py(), + particle->Pz(), + particle->Energy(), + particle->Vx(), + particle->Vy(), + particle->Vz(), + particle->T()); + auto& tgt = mParticles[mParticles.size() - 1]; + tgt.SetPolarTheta(particle->GetPolarTheta()); + tgt.SetPolarPhi(particle->GetPolarPhi()); + tgt.SetCalcMass(particle->GetCalcMass()); + tgt.SetWeight(particle->GetWeight()); + } + return true; +} +} // namespace eventgen +} // namespace o2 +// +// EOF +// diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 26f270c9a0a39..669b1f37019c1 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -67,8 +67,8 @@ #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::QEDGenParam> + ; #pragma link C++ class o2::eventgen::GenCosmicsParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GenCosmicsParam> + ; -#pragma link C++ class o2::eventgen::GeneratorTParticle +; -#pragma link C++ class o2::eventgen::GeneratorTParticleParam +; -#pragma link C++ class o2::conf::ConfigurableParamHelper +; +#pragma link C++ class o2::eventgen::GeneratorTParticle + ; +#pragma link C++ class o2::eventgen::GeneratorTParticleParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorTParticleParam> + ; #endif From 2e413a322b29d161384dc7b935d9ffe52ac3dcf0 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Tue, 19 Sep 2023 15:10:00 +0200 Subject: [PATCH 06/37] Fixes for copyright stuff - sigh! --- .../include/Generators/GeneratorTParticle.h | 29 +++++++++---------- .../Generators/GeneratorTParticleParam.h | 29 ++++++++++--------- Generators/src/GeneratorTParticle.cxx | 11 ++++--- Generators/src/GeneratorTParticleParam.cxx | 11 ++++--- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/Generators/include/Generators/GeneratorTParticle.h b/Generators/include/Generators/GeneratorTParticle.h index 1dc87dac4c939..dc808c5877fd3 100644 --- a/Generators/include/Generators/GeneratorTParticle.h +++ b/Generators/include/Generators/GeneratorTParticle.h @@ -1,18 +1,14 @@ -// -*- C++ -*- -// Copyright 2023 CERN and copyright holders of ALICE O2. -// -// See https://alice-o2.web.cern.ch/copyright for details of the -// copyright holders. All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General -// Public License v3 (GPL Version 3), copied verbatim in the file -// "COPYING". -// -// In applying this license CERN does not waive the privileges and -// immunities granted to it by virtue of its status as an -// Intergovernmental Organization or submit itself to any -// jurisdiction. -// +// Copyright 2023-2099 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + /// @author: Christian Holm Christensen #ifndef ALICEO2_GENERATORTPARTICLE_H_ #define ALICEO2_GENERATORTPARTICLE_H_ @@ -110,6 +106,9 @@ TClonesArray of @c TParticle objects */ } // namespace eventgen } // namespace o2 #endif +// Local Variables: +// mode: C++ +// End: // // EOF // diff --git a/Generators/include/Generators/GeneratorTParticleParam.h b/Generators/include/Generators/GeneratorTParticleParam.h index 46c003e112f51..6dc3336f97e37 100644 --- a/Generators/include/Generators/GeneratorTParticleParam.h +++ b/Generators/include/Generators/GeneratorTParticleParam.h @@ -1,17 +1,15 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// -// See https://alice-o2.web.cern.ch/copyright for details of the -// copyright holders. All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General -// Public License v3 (GPL Version 3), copied verbatim in the file -// "COPYING". -// -// In applying this license CERN does not waive the privileges and -// immunities granted to it by virtue of its status as an -// Intergovernmental Organization or submit itself to any -// jurisdiction. -// +// Copyright 2023-2099 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + + // @author: Christian Holm Christensen #ifndef ALICEO2_EVENTGEN_GENERATORTPARTICLEPARAM_H_ #define ALICEO2_EVENTGEN_GENERATORTPARTICLEPARAM_H_ @@ -39,3 +37,6 @@ struct GeneratorTParticleParam : public o2::conf::ConfigurableParamHelper Date: Tue, 19 Sep 2023 15:20:38 +0200 Subject: [PATCH 07/37] One more comment --- Generators/src/GeneratorHepMC.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Generators/src/GeneratorHepMC.cxx b/Generators/src/GeneratorHepMC.cxx index 2741f98f57cc9..a088986149715 100644 --- a/Generators/src/GeneratorHepMC.cxx +++ b/Generators/src/GeneratorHepMC.cxx @@ -307,6 +307,15 @@ Bool_t GeneratorHepMC::Init() // line argument `-n NEVENTS` to set the number of events to // produce. // + // Perhaps we should consider a way to set a seed on the EG. It + // could be another configuration parameter. Of course, if the EG + // program accepts a seed option, say `-s SEED`, then one could + // simply pass + // + // -s \$RANDOM + // + // to as part of the command line in `progCmd`. + // // All of this can conviniently be achieved via a wrapper script // around the actual EG program. if (not mProgCmd.empty()) { From f42301116284487f1cb78b23a197d450a375a518 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Tue, 19 Sep 2023 13:23:39 +0000 Subject: [PATCH 08/37] Please consider the following formatting changes --- Generators/include/Generators/GeneratorTParticle.h | 4 ++-- Generators/include/Generators/GeneratorTParticleParam.h | 5 ++--- Generators/src/GeneratorHepMC.cxx | 2 +- Generators/src/GeneratorTParticle.cxx | 4 ++-- Generators/src/GeneratorTParticleParam.cxx | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Generators/include/Generators/GeneratorTParticle.h b/Generators/include/Generators/GeneratorTParticle.h index dc808c5877fd3..8887ab344434f 100644 --- a/Generators/include/Generators/GeneratorTParticle.h +++ b/Generators/include/Generators/GeneratorTParticle.h @@ -1,10 +1,10 @@ // Copyright 2023-2099 CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. -// +// // This software is distributed under the terms of the GNU General Public // License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// +// // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. diff --git a/Generators/include/Generators/GeneratorTParticleParam.h b/Generators/include/Generators/GeneratorTParticleParam.h index 6dc3336f97e37..992c76a9fae3e 100644 --- a/Generators/include/Generators/GeneratorTParticleParam.h +++ b/Generators/include/Generators/GeneratorTParticleParam.h @@ -1,14 +1,13 @@ // Copyright 2023-2099 CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. -// +// // This software is distributed under the terms of the GNU General Public // License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// +// // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. - // @author: Christian Holm Christensen #ifndef ALICEO2_EVENTGEN_GENERATORTPARTICLEPARAM_H_ diff --git a/Generators/src/GeneratorHepMC.cxx b/Generators/src/GeneratorHepMC.cxx index a088986149715..a5fb510ba479f 100644 --- a/Generators/src/GeneratorHepMC.cxx +++ b/Generators/src/GeneratorHepMC.cxx @@ -314,7 +314,7 @@ Bool_t GeneratorHepMC::Init() // // -s \$RANDOM // - // to as part of the command line in `progCmd`. + // to as part of the command line in `progCmd`. // // All of this can conviniently be achieved via a wrapper script // around the actual EG program. diff --git a/Generators/src/GeneratorTParticle.cxx b/Generators/src/GeneratorTParticle.cxx index 7e462d7d49750..d04f0116bfe98 100644 --- a/Generators/src/GeneratorTParticle.cxx +++ b/Generators/src/GeneratorTParticle.cxx @@ -1,10 +1,10 @@ // Copyright 2023-2099 CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. -// +// // This software is distributed under the terms of the GNU General Public // License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// +// // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. diff --git a/Generators/src/GeneratorTParticleParam.cxx b/Generators/src/GeneratorTParticleParam.cxx index 466bd46703c46..abb2d39681a3e 100644 --- a/Generators/src/GeneratorTParticleParam.cxx +++ b/Generators/src/GeneratorTParticleParam.cxx @@ -1,10 +1,10 @@ // Copyright 2023-2099 CERN and copyright holders of ALICE O2. // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. // All rights not expressly granted are reserved. -// +// // This software is distributed under the terms of the GNU General Public // License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// +// // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. From 233e2e0aee7dc7e282b2e8beada74ba1d924d77b Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Tue, 19 Sep 2023 15:32:11 +0200 Subject: [PATCH 09/37] Whitespace --- Generators/src/GeneratorPythia8.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Generators/src/GeneratorPythia8.cxx b/Generators/src/GeneratorPythia8.cxx index 442e93976546f..574bed41773d8 100644 --- a/Generators/src/GeneratorPythia8.cxx +++ b/Generators/src/GeneratorPythia8.cxx @@ -276,9 +276,9 @@ void GeneratorPythia8::updateHeader(o2::dataformats::MCEventHeader* eventHeader) // --- HepMC3 conforming information --- // This is how the Pythia authors define Ncoll // eventHeader->putInfo(Key::nColl, - // hiinfo->nAbsProj() + hiinfo->nDiffProj() + - // hiinfo->nAbsTarg() + hiinfo->nDiffTarg() - - // hiiinfo->nCollND() - hiinfo->nCollDD()); + // hiinfo->nAbsProj() + hiinfo->nDiffProj() + + // hiinfo->nAbsTarg() + hiinfo->nDiffTarg() - + // hiiinfo->nCollND() - hiinfo->nCollDD()); eventHeader->putInfo(Key::nPartProjectile, hiinfo->nAbsProj() + hiinfo->nDiffProj()); eventHeader->putInfo(Key::nPartTarget, From d65a0c96b3b727d2713129139f35709e009ec304 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Tue, 19 Sep 2023 15:38:09 +0200 Subject: [PATCH 10/37] untabify --- Generators/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 5a5ae04f29f90..6e4ebc1c2da37 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -38,8 +38,8 @@ o2_add_library(Generators src/GenCosmicsParam.cxx src/GeneratorFactory.cxx src/GeneratorGeantinos.cxx - src/GeneratorTParticle.cxx - src/GeneratorTParticleParam.cxx + src/GeneratorTParticle.cxx + src/GeneratorTParticleParam.cxx $<$:src/GeneratorPythia6.cxx> $<$:src/GeneratorPythia6Param.cxx> $<$:src/GeneratorPythia8.cxx> From 6f6f2c3eacbd528938bbf38d1c9428f7ad7a2bba Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 11:35:45 +0200 Subject: [PATCH 11/37] Added documentation --- run/SimExamples/HepMC/README.md | 151 ++++++++++++++++ run/SimExamples/HepMC/child.sh | 53 ++++++ run/SimExamples/HepMC/crmc.sh | 7 + run/SimExamples/HepMC/read.sh | 50 ++++++ run/SimExamples/TParticle/MyEG.cc | 128 ++++++++++++++ run/SimExamples/TParticle/README.md | 258 ++++++++++++++++++++++++++++ run/SimExamples/TParticle/child.sh | 59 +++++++ run/SimExamples/TParticle/myeg.sh | 22 +++ run/SimExamples/TParticle/read.sh | 56 ++++++ 9 files changed, 784 insertions(+) create mode 100644 run/SimExamples/HepMC/README.md create mode 100755 run/SimExamples/HepMC/child.sh create mode 100755 run/SimExamples/HepMC/crmc.sh create mode 100755 run/SimExamples/HepMC/read.sh create mode 100644 run/SimExamples/TParticle/MyEG.cc create mode 100644 run/SimExamples/TParticle/README.md create mode 100755 run/SimExamples/TParticle/child.sh create mode 100755 run/SimExamples/TParticle/myeg.sh create mode 100755 run/SimExamples/TParticle/read.sh diff --git a/run/SimExamples/HepMC/README.md b/run/SimExamples/HepMC/README.md new file mode 100644 index 0000000000000..811e4d6f35440 --- /dev/null +++ b/run/SimExamples/HepMC/README.md @@ -0,0 +1,151 @@ + + +Here are pointers on how to use `GeneratorHepMC` selected by the +option `-g hepmc` for `o2-sim`. + +## Reading HepMC files + +The generator `GeneratorHepMC` can read events from a +[HepMC(3)](http://hepmc.web.cern.ch/hepmc/) formatted file. These files +can be produced by a standalone event generator program (EG). +Examples of such programs are + +- [Pythia8](https://pythia.org) +- The [CRMC](https://gitlab.iap.kit.edu/AirShowerPhysics/crmc) suite +- [Herwig](https://herwig.hepforge.org/) +- [SMASH](https://smash-transport.github.io/) +- ... and many others + +Please refer to the documentation of these for more on how to make +event files in the HepMC format. + +To make a simulation reading from the file `events.hepmc`, do + + o2-sim -g hepmc --configKeyValues "HepMC.fileName=events.hepmc" ... + +See also [`read.sh`](read.sh) + +## Reading HepMC events from child process + +`GeneratorHepMC` can not only read HepMC events from a file, but can +also spawn an child EG to produce events. Suppose we have a program +named `eg` which is some EG that writes HepMC event records to the +standard output. Then we can execute a simulation using this external +EG by + + o2-sim -g hepmc --configKeyValues "HepMC.progCmd=eg" + +See also [`child.sh`](child.sh) + +There are some requirements on the program `eg`: + +- It _must_ write the HepMC event structures to standard output + (`/dev/stdout`). +- It may _not_ write other information to standard output. +- It _must_ accept the option `-n n-events` to set the number of + events to produce to `n-events`. + +If a program does not adhere to these requirements, it will often be +simple enough to make a small wrapper script that enforce this. For +example, `crmc` will write a lot of information to standard output. +We can filter that out via a shell script ([`crmc.sh`](crmc.sh)) like + + #!/bin/sh + + crmc $@ -o hepmc3 -f /dev/stdout | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' + +The `sed` command selects lines that begin with `HepMC::`, or one +of single characters `E` (event), `A` (attribute), `U` (units), `W` +(weight), `V` (vertex), or `P` (particle) followed by a space. This +should in most cases be enough to filter out extra stuff written on +standard output. + +The script above also passes any additional command line options on to +`crmc` via `$@`. We can utilise this with `o2-sim` to set options to +the CRMC suite. For example, if we want to simulate p-Pb collisions +using DpmJET, we can do + + o2-sim -g hepmc --configKeyValues "HepMC.progCmd=crmc.sh -m 12 -i2212 -I 1002080820" + + +### Implementation details + +Internally `GeneratorHepMC` + +1. creates a unique temporary file name in the working directory, +2. then creates a FIFO (or named pipe, see + [Wikipedia](https://en.wikipedia.org/wiki/Named_pipe)), +3. builds a command line, e.g., + + eg options > fifo-name & + +4. and executes that command line + +## The future + +The `GeneratorHepMC` (and sister generator `GeneratorTParticle`) will +in the not so distant future be upgraded with new functionality to +more easily customise reading files and executing a child process. In +particular + +- HepMC event structures can be read from any file format supported by + HepMC it self (see + [here](http://hepmc.web.cern.ch/hepmc/group__IO.html) and + [here](http://hepmc.web.cern.ch/hepmc/group__factory.html). + +- New options that can be specified in `--configKeyValues` + + - `HepMC.eventsToSkip=number` a number events to skip at the + beginning of each file read. + + - `FileOrCmd.fileNames=list` a comma separated list of HepMC files + to read + + - `FileOrCmd.cmd=command line` a command line to execute as a + background child process. If this is set (not the empty string), + then `FileOrCmd.fileNames` is ignored. + + - A number of keys that specifies the command line option switch + that the child program accepts for certain things. If any of + these are set to the empty string, then that switch and + corresponding option value is not passed to the child program. + + - `FileOrCmd.outputSwitch=switch` (default `>`) to specify output + file. The default of `>` assumes that the program write HepMC + events, and _only_ those, to standard output. + + - `FileOrCmd.seedSwitch=switch` (default `-s`) to specify the + random number generator seed. The value passed is selected by + the `o2-sim` option `--seed` + + - `FileOrCmd.bMaxSwitch=switch` (default `-b`) to specify the + upper limit on the impact parameters sampled. The value passed + is selected by the `o2-sim` option `--bMax` + + - `FileOrCmd.nEventsSwitch=switch` (default `-n`) to specify the + number of events to generate. The value passed is selected by + the `o2-sim` option `--nEvents` or (`-n`) + + - `FileOrCmd.backgroundSwitch=switch` (default `&`) to specify how + the program is put in the background. Typically this should be + `&`, but a program may itself fork to the background. + +- Some options are no longer available + + - `HepMC.fileName` - use `FileOrCmd.fileNames` + - `HepMC.progCmd` - use `FileOrCmd.cmd` + +The command line build will now be + +> _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ +> _bMaxSwitch_ _bMax_ _outputSwitch_ _output_ _backgroundSwitch_ + +If any of the `Switch` keys are empty, then the corresponding option +is not propagated to the command line. For example, if _bMaxSwitch_ +is empty, then the build command line will be + +> _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ +> _outputSwitch_ _output_ _backgroundSwitch_ + diff --git a/run/SimExamples/HepMC/child.sh b/run/SimExamples/HepMC/child.sh new file mode 100755 index 0000000000000..f1e49b6f7c3a2 --- /dev/null +++ b/run/SimExamples/HepMC/child.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +cmd="./crmc.sh" +seed=$RANDOM +nev=1 +out= + +usage() +{ + cat <<-EOF + Usage: $0 [OPTIONS] + + Options: + + -c,--cmdline COMMAND Command line + -s,--seed SEED Random number seed ($seed) + -n,--nevents EVENTS Number of events ($nev) + -o,--output OUTPUT Output prefix ($out) + -- Rest of command line sent to o2-sim + + COMMAND must be quoted if it contains spaces or other special + characters + + Below follows the help output of o2-sim + + EOF +} + +while test $# -gt 0 ; do + case $1 in + -c|--cmdline) cmd="$2" ; shift ;; + -s|--seed) seed=$2 ; shift ;; + -n|--nevents) nev=$2 ; shift ;; + -o|--output) out=$2 ; shift ;; + -h|--help) usage; o2-sim --help full ; exit 0 ;; + --) shift ; break ;; + *) echo "Unknown option '$1', did you forget '--'?" >/dev/stderr + exit 1 + ;; + esac + shift +done + +if test "x$out" = "x" ; then + out=`echo $cmd | sed 's,^\./,,' | tr '[$/. ]' '_'` +fi +out=`echo "$out" | tr ' ' '_'` + +export VMCWORKDIR=${O2_ROOT}/share +o2-sim -g hepmc --configKeyValues "HepMC.progCmd=$cmd" \ + --outPrefix "$out" --seed $seed --nEvents $nev $@ + + diff --git a/run/SimExamples/HepMC/crmc.sh b/run/SimExamples/HepMC/crmc.sh new file mode 100755 index 0000000000000..347de0446e5fd --- /dev/null +++ b/run/SimExamples/HepMC/crmc.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# This script _may not_ write to standard out, except for the HepMC +# event record. + +crmcParam=$(dirname $(dirname `which crmc`))/etc/crmc.param +exec crmc -c $crmcParam $@ -o hepmc3 -f /dev/stdout | \ + sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' diff --git a/run/SimExamples/HepMC/read.sh b/run/SimExamples/HepMC/read.sh new file mode 100755 index 0000000000000..45779529455d0 --- /dev/null +++ b/run/SimExamples/HepMC/read.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +inp=events.hepmc +seed=$RANDOM +nev=1 +out= + +usage() +{ + cat <<-EOF + Usage: $0 [OPTIONS] + + Options: + + -i,--input FILENAME Input HepMC file ($inp) + -s,--seed SEED Random number seed ($seed) + -n,--nevents EVENTS Number of events ($nev) + -o,--output NAME Ouptut name + -- Rest of command line sent to o2-sim + + Below follows the help output of o2-sim + + EOF +} + +while test $# -gt 0 ; do + case $1 in + -i|--input) inp=$2 ; shift ;; + -s|--seed) seed=$2 ; shift ;; + -n|--nevents) nev=$2 ; shift ;; + -o|--output) out=$2 ; shift ;; + -h|--help) usage; o2-sim --help full ; exit 0 ;; + --) shift ; break ;; + *) echo "Unknown option '$1', did you forget '--'?" >/dev/stderr + exit 1 + ;; + esac + shift +done + +if test "x$out" = "x" ; then + out=`basename $inp .hepmc` +fi +out=`echo "$out" | tr ' ' '_'` + +export VMCWORKDIR=${O2_ROOT}/share +o2-sim -g hepmc --configKeyValues "HepMC.fileName=$inp" \ + --outPrefix "$out" --seed $seed --nEvents $nev $@ + + diff --git a/run/SimExamples/TParticle/MyEG.cc b/run/SimExamples/TParticle/MyEG.cc new file mode 100644 index 0000000000000..a067b4c1051b7 --- /dev/null +++ b/run/SimExamples/TParticle/MyEG.cc @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include + +//-------------------------------------------------------------------- +// Our generator class. Really simple. +class MyGenerator : public TGenerator +{ + public: + Long_t projectilePDG; + Long_t targetPDG; + Double_t sqrts; + MyGenerator() {} + void Initialize(Long_t projectile, + Long_t target, + Double_t sqrts) + { + this->projectilePDG = projectile; + this->targetPDG = target; + this->sqrts = sqrts; + } + void GenerateEvent() + { /* Do something */ + } + TObjArray* ImportParticles(Option_t* option = "") { return 0; } + Int_t ImportParticles(TClonesArray* particles, Option_t* option = "") + { + Int_t nParticles = 10; + Int_t iParticle = 0; + // Make beam particles + new ((*particles)[iParticle++]) TParticle(projectilePDG, 4, -1, -1, + 2, nParticles - 1, + 0, 0, sqrts / 2, + TMath::Sqrt(1 + sqrts * sqrts), + 0, 0, 0, 0); + new ((*particles)[iParticle++]) TParticle(projectilePDG, 4, -1, -1, + 2, nParticles - 1, + 0, 0, -sqrts / 2, + TMath::Sqrt(1 + sqrts * sqrts), + 0, 0, 0, 0); + for (; iParticle < nParticles; iParticle++) + new ((*particles)[iParticle]) + TParticle(211, 1, 0, 1, + -1, -1, + 0.1 * iParticle, + 0.1 * iParticle, + 0.1 * iParticle, + TMath::Sqrt(0.03 * iParticle * iParticle + 0.14 * 0.14), + 0, 0, 0, 0); + + return nParticles; + } +}; +//-------------------------------------------------------------------- +// Our steering class +struct MySteer { + TGenerator* generator; + TFile* file; + TTree* tree; + TClonesArray* particles; + Int_t every; + MySteer(TGenerator* generator, const TString& output, Int_t every) + : generator(generator), + file(TFile::Open(output, "RECREATE")), + tree(new TTree("T", "T")), + particles(new TClonesArray("TParticle")), + every(every) + { + tree->SetDirectory(file); + tree->Branch("Particles", &particles); + } + ~MySteer() + { + close(); + } + void event() + { + particles->Clear(); + generator->GenerateEvent(); + generator->ImportParticles(particles); + tree->Fill(); + } + void sync() + { + // Important so that GeneratorTParticle picks up the events as + // they come. + tree->AutoSave("SaveSelf FlushBaskets Overwrite"); + } + void run(Int_t nev) + { + for (Int_t iev = 0; iev < nev; iev++) { + event(); + + if (every > 0 and (iev % every == 0) and iev != 0) + sync(); + } + } + void close() + { + if (not file) + return; + file->Write(); + file->Close(); + file = nullptr; + } +}; + +//-------------------------------------------------------------------- +// Our steering function +void MyEG(Int_t nev, const TString& out, Int_t seed, Int_t every = 1) +{ + gRandom->SetSeed(seed); + + MyGenerator* eg = new MyGenerator(); + eg->Initialize(2212, 2212, 5200); + + MySteer steer(eg, out, every); + steer.run(nev); +} +// Local Variables: +// mode: C++ +// End: +// +// EOF +// diff --git a/run/SimExamples/TParticle/README.md b/run/SimExamples/TParticle/README.md new file mode 100644 index 0000000000000..45b6bc6eea374 --- /dev/null +++ b/run/SimExamples/TParticle/README.md @@ -0,0 +1,258 @@ + + +Here are pointers on how to use `GeneratorTParticle` selected by the +option `-g tparticle` for `o2-sim`. + +## Reading TParticle files + +The generator `GeneratorTParticle` can read events from a ROOT file +containing a `TTree` with a branch holding a `TClonesArray` of +`TParticle` objects. These files can be produced by a standalone event +generator program (EG). + +To make a simulation reading from the file `particles.root`, do + + o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=particles.root" ... + +See also [`read.sh`](read.sh). Do + + ./read.sh --help + +for a list of options. This expects an input file with a `TTree` +with a single `TBranch` holding a `TClonesArray` of `TParticle` +objects. One such example file can be made with [`myeg.sh`]. Do + + ./myeg.sh --help + +for a list of options. + +### Configurations + +- The name of the `TTree` to read can be set by the configuration key + `GeneratorTParticle.treeName`. The default is `T` +- The name of the `TBranch` holding the `TClonesArray` of `TParticle` + objects can be set by the configuration key + `GeneratorTParticle.branchName`. The default is `Particles` + +For example + + o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=particles.root;GeneratorTParticle.treeName=Events;GeneratorTParticle.branchName=Tracks" ... + +## Reading TParticle events from child process + +`GeneratorTParticle` can not only read events from a file, but can +also spawn an child EG to produce events. Suppose we have a program +named `eg` which is some EG that writes `TParticle` event records to a +file . Then we can execute a simulation using this external +EG by + + o2-sim -g tgenerator --configKeyValues "GeneratorTParticle.progCmd=eg" + +See also [`child.sh`](child.sh). Do + + ./child.sh --help + +for a list of options. + +There are some requirements on the program `eg`: + +- It _must_ accept the option `-n n-events` to set the number of + events to produce to `n-events`. + +- It _must_ accept the option `-o output` to set the output file name. + +If a program does not adhere to these requirements, it will often be +simple enough to make a small wrapper script that enforce this. + +### Configurations + +Same as above. + +### Example EG + +The child-process feature allows us to use almost any EG for which we +have a `TGenerator` interface without compiling it in to O2. Suppose +we have defined the class `MyGenerator` to produce events. + + class MyGenerator : public TGenerator { + public: + MyGenerator(); + void Initialize(Long_t projectile, + Long_t target, + Double_t sqrts); + void GenerateEvent(); + Int_t ImportParticles(TClonesArray* particles,Option_t*option=""); + }; + +and a steering class + + struct MySteer { + TGenerator* generator; + TFile* file; + TTree* tree; + TClonesArray* particle; + Int_t flushEvery; + MySteer(TGenerator* generator, + const TString& output, + Int_t flushEvery) + : generator(generator) + file(TFile::Open(output,"RECREATE")), + tree("T","Particle tree"), + particles(new TClonesArray("TParticle")), + flushEvery(flushEvery) + { + tree->SetDirectory(file); + tree->Branch("Particles",&particles); + } + ~MySteer() { close(); } + void event() { + particles->Clear(); + generator->GenerateEvent(); + generator->ImportParticles(particles); + tree->Fill(); + } + void sync() { + tree->AutoSave("SaveSelf FlushBaskets Overwrite"); + } + void run(Int_t nev) { + for (Int_t iev = 0; iev < nev; iev++) { + event(); + if (flushEvery > 0 and (iev % flushEvery == 0) and iev != 0) + sync(); + } + } + void close() { + if (not file) return; + file->Write(); + file->Close(); + file = nullptr; + } + }; + +Then we could make the script [`MyEG.cc` (complete code)](MyEG.cc) like + + void MyEG(Int_t nev,const TString& out,Int_t every=1) + { + MyGenerator* eg = new MyGenerator(); + eg->Initialize(2212, 2212, 5200); + + MySteer steer(eg, out, every); + steer.run(nev); + } + +and a simple shell-script [`myeg.sh`](myeg.sh) to pass arguments to +the `MyEG.cc` script + + #!/bin/sh + + nev=1 + out=particles.root + + while test $# -gt 0 ; do + case $1 in + -n) nev=$2 ; shift ;; + -o) out=$2 ; shift ;; + *) ;; + esac + shift + done + + root -l MyEG.cc -- $nev \"$out\" + +We can then do + + o2-sim -g tgenerator --configKeyValues "GeneratorTParticle.progCmd=./myeg.sh" + +to produce events with our generator `MyGenerator`. + + +### Implementation details + +Internally `GeneratorTParticle` + +1. creates a unique temporary file name in the working directory, +2. builds a command line, e.g., + + eg options -o temporary-name & + +3. and executes that command line + +## The future + +The `GeneratorTParticle` (and sister generator `GeneratorHepMC`) will +in the not so distant future be upgraded with new functionality to +more easily customise reading files and executing a child process. In +particular + +- New options that can be specified in `--configKeyValues` + + - `GeneratorTParticle.treeName=name` the name of the `TTree` in the + input files. + + - `GeneratorTParticle.branchName=name` the name of the `TBranch` in + the `TTree` that holds the `TClonesArray` of `TParticle` objects. + + - `FileOrCmd.fileNames=list` a comma separated list of HepMC files + to read + + - `FileOrCmd.cmd=command line` a command line to execute as a + background child process. If this is set (not the empty string), + then `FileOrCmd.fileNames` is ignored. + + - A number of keys that specifies the command line option switch + that the child program accepts for certain things. If any of + these are set to the empty string, then that switch and + corresponding option value is not passed to the child program. + + - `FileOrCmd.outputSwitch=switch` (default `>`) to specify output + file. The default of `>` assumes that the program write HepMC + events, and _only_ those, to standard output. + + - `FileOrCmd.seedSwitch=switch` (default `-s`) to specify the + random number generator seed. The value passed is selected by + the `o2-sim` option `--seed` + + - `FileOrCmd.bMaxSwitch=switch` (default `-b`) to specify the + upper limit on the impact parameters sampled. The value passed + is selected by the `o2-sim` option `--bMax` + + - `FileOrCmd.nEventsSwitch=switch` (default `-n`) to specify the + number of events to generate. The value passed is selected by + the `o2-sim` option `--nEvents` or (`-n`) + + - `FileOrCmd.backgroundSwitch=switch` (default `&`) to specify how + the program is put in the background. Typically this should be + `&`, but a program may itself fork to the background. + +- Some options are no longer available + + - `GeneratorTParticle.fileName` - use `FileOrCmd.fileNames` + - `GeneratorTParticle.progCmd` - use `FileOrCmd.cmd` + +The command line build will now be + +> _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ +> _bMaxSwitch_ _bMax_ _outputSwitch_ _output_ _backgroundSwitch_ + +If any of the `Switch` keys are empty or set to `none`, then the +corresponding option is not propagated to the command line. For +example, if _bMaxSwitch_ is empty, then the build command line will be + +> _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ +> _outputSwitch_ _output_ _backgroundSwitch_ + + +### Header information + +The class `GeneratorTParticle` will take a key parameter, say +`headerName` which will indicate a branch that contains header +information. Under that branch, the class will then search for leaves +(`TLeaf`) that correspond to standard header information keys (see +o2::dataformats::MCInfoKeys). If any of those leaves are present, +then the corresponding keys will be set on the generated event header. + +Thus, as long as the generator observes the convention used, we can +also import auxiliary information (impact parameter, Npart, ...) from +the input files in addition to the particle information. diff --git a/run/SimExamples/TParticle/child.sh b/run/SimExamples/TParticle/child.sh new file mode 100755 index 0000000000000..1a4807b72a4c5 --- /dev/null +++ b/run/SimExamples/TParticle/child.sh @@ -0,0 +1,59 @@ +#!/usr/bin/bash + +cmd="./myeg.sh" +seed=$RANDOM +nev=1 +out= +opt= + +usage() +{ + cat <<-EOF + Usage: $0 [OPTIONS] + + Options: + + -c,--cmdline COMMAND Command line + -s,--seed SEED Random number seed ($seed) + -n,--nevents EVENTS Number of events ($nev) + -o,--output OUTPUT Output prefix ($out) + -+,--compile Compile script ($opt) + -- Rest of command line sent to o2-sim + + COMMAND must be quoted if it contains spaces or other special + characters + + Below follows the help output of o2-sim + + EOF +} + +while test $# -gt 0 ; do + case $1 in + -c|--cmdline) cmd="$2" ; shift ;; + -s|--seed) seed=$2 ; shift ;; + -n|--nevents) nev=$2 ; shift ;; + -o|--output) out=$2 ; shift ;; + -+|--compile) opt=" -+";; + -h|--help) usage; o2-sim --help full ; exit 0 ;; + --) shift ; break ;; + *) echo "Unknown option '$1', did you forget '--'?" >/dev/stderr + exit 1 + ;; + esac + shift +done + +if test "x$out" = "x" ; then + out=`echo $cmd | sed 's,^\./,,' | tr '[$/. ]' '_'` +fi +out=`echo "$out" | tr ' ' '_'` + +keys="Generator.progCmd=$cmd $opt" +# keys="FileOrCmd.cmd=$cmd $opt;FileOrCmd.outputSwitch=-o" +set -x +export VMCWORKDIR=${O2_ROOT}/share +o2-sim -g tparticle --configKeyValues "$keys" \ + --outPrefix "$out" --seed $seed --nEvents $nev $@ + + diff --git a/run/SimExamples/TParticle/myeg.sh b/run/SimExamples/TParticle/myeg.sh new file mode 100755 index 0000000000000..5026f285af8cd --- /dev/null +++ b/run/SimExamples/TParticle/myeg.sh @@ -0,0 +1,22 @@ +#!/bin/sh + + +nev=1 +out=particles.root +seed=0 +opt= + +while test $# -gt 0 ; do + case $1 in + -n) nev=$2 ; shift ;; + -o) out=$2 ; shift ;; + -s) seed=$2 ; shift ;; + -b) imp=$2 ; shift ;; + -+) opt=+ ;; + *) ;; + esac + shift +done + +root -q -l MyEG.cc${opt} -- $nev \"$out\" $seed + diff --git a/run/SimExamples/TParticle/read.sh b/run/SimExamples/TParticle/read.sh new file mode 100755 index 0000000000000..3326ffd994761 --- /dev/null +++ b/run/SimExamples/TParticle/read.sh @@ -0,0 +1,56 @@ +#!/usr/bin/bash + +inp=particles.root +seed=$RANDOM +nev=1 +out= + +usage() +{ + cat <<-EOF + Usage: $0 [OPTIONS] + + Options: + + -i,--input FILENAME Input HepMC file ($inp) + -s,--seed SEED Random number seed ($seed) + -n,--nevents EVENTS Number of events ($nev) + -o,--output NAME Ouptut name + -- Rest of command line sent to o2-sim + + The input file FILENAME is assumed to contain a TTree with a + TBranch holding a TClonesArray of TParticle objects. Such a + file can be generated by the script myeg.sh in this directory. + + Below follows the help output of o2-sim + + EOF +} + +while test $# -gt 0 ; do + case $1 in + -i|--input) inp=$2 ; shift ;; + -s|--seed) seed=$2 ; shift ;; + -n|--nevents) nev=$2 ; shift ;; + -o|--output) out=$2 ; shift ;; + -h|--help) usage; o2-sim --help full ; exit 0 ;; + --) shift ; break ;; + *) echo "Unknown option '$1', did you forget '--'?" >/dev/stderr + exit 1 + ;; + esac + shift +done + +if test "x$out" = "x" ; then + out=`basename $inp .root` +fi +out=`echo "$out" | tr ' ' '_'` + +set +e + +# Future FileOrCmd.fileNames=${inp} +export VMCWORKDIR=${O2_ROOT}/share +o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=${inp}" \ + --outPrefix "$out" --seed $seed --nEvents $nev $@ + From 9ccc1b2e71f5bea3850221b8535450bf705cd321 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 11:39:05 +0200 Subject: [PATCH 12/37] Refactoring to HepMC and TParticle Generators The classes `GeneratorHepMC` and `GeneratorTParticle` is refactored to derive from the (second) base class `GeneratorFileOrCmd`. `GeneratorFileOrCmd` provides common infrastructure to specify - File(s) to read events from (ROOT files in case of `GeneratorTParticle`, and HepMC files in case of `GeneratorHepMC`), _or_ - Which commmand to execute and with which options. It also provides infrastructure to make unique temporary names, a FIFO to read from (child program writes to), and so on. These are all configured through configuration keys prefixed by `FileOrCmd.`. Other changes include - `GeneratorHepMC` will open _any_ file that HepMC supports - ASCII, compressed ASCII, HEPEVT, etc. - Through the use of `GeneratorFileOrCmd` the command line option flags for specifying seed (default: `-s`), number of events (default `-n`), largest impact parameter (defautl: `-b`), output (default: `>`), and so on can be configured via configuration key values - `GeneratorHepMC` and `GeneratorTParticle` are passed the `GeneratorFileOrCmdParam` as well as specific `GeneratorHepMCParam` and `GeneratorTParticleParam`, respectively, objects by `GeneratorFactor` and sets the internal parameters accordingly. This hides the specifics of the parameters from `GeneratorFactory`. --- Generators/CMakeLists.txt | 6 + .../include/Generators/GeneratorFileOrCmd.h | 243 ++++++++++++++++++ .../Generators/GeneratorFileOrCmdParam.h | 45 ++++ .../include/Generators/GeneratorHepMC.h | 54 ++-- .../include/Generators/GeneratorHepMCParam.h | 4 +- .../include/Generators/GeneratorTParticle.h | 59 +++-- .../Generators/GeneratorTParticleParam.h | 10 +- Generators/src/GeneratorFactory.cxx | 16 +- Generators/src/GeneratorFileOrCmd.cxx | 207 +++++++++++++++ Generators/src/GeneratorFileOrCmdParam.cxx | 18 ++ Generators/src/GeneratorHepMC.cxx | 218 ++++++++-------- Generators/src/GeneratorTParticle.cxx | 110 +++----- Generators/src/GeneratorsLinkDef.h | 2 + 13 files changed, 746 insertions(+), 246 deletions(-) create mode 100644 Generators/include/Generators/GeneratorFileOrCmd.h create mode 100644 Generators/include/Generators/GeneratorFileOrCmdParam.h create mode 100644 Generators/src/GeneratorFileOrCmd.cxx create mode 100644 Generators/src/GeneratorFileOrCmdParam.cxx diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 6e4ebc1c2da37..dc1e44d5a65dc 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -29,6 +29,8 @@ o2_add_library(Generators src/GeneratorExternalParam.cxx src/GeneratorFromFile.cxx src/GeneratorFromO2KineParam.cxx + src/GeneratorFileOrCmd.cxx + src/GeneratorFileOrCmdParam.cxx src/PrimaryGenerator.cxx src/PrimaryGeneratorParam.cxx src/TriggerExternalParam.cxx @@ -48,6 +50,7 @@ o2_add_library(Generators $<$:src/DecayerPythia8Param.cxx> $<$:src/GeneratorHepMC.cxx> $<$:src/GeneratorHepMCParam.cxx> + $<$:src/AODToHepMC.cxx> PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimConfig O2::CommonUtils O2::DetectorsBase O2::ZDCBase O2::SimulationDataFormat ${pythia6Target} ${pythiaTarget} ${hepmcTarget} FairRoot::Gen @@ -73,6 +76,8 @@ set(headers include/Generators/GeneratorExternalParam.h include/Generators/GeneratorFromFile.h include/Generators/GeneratorFromO2KineParam.h + include/Generators/GeneratorFileOrCmd.h + include/Generators/GeneratorFileOrCmdParam.h include/Generators/PrimaryGenerator.h include/Generators/PrimaryGeneratorParam.h include/Generators/TriggerExternalParam.h @@ -102,6 +107,7 @@ endif() if(HepMC3_FOUND) list(APPEND headers include/Generators/GeneratorHepMC.h) list(APPEND headers include/Generators/GeneratorHepMCParam.h) + list(APPEND headers include/Generators/AODToHepMC.h) endif() o2_target_root_dictionary(Generators HEADERS ${headers}) diff --git a/Generators/include/Generators/GeneratorFileOrCmd.h b/Generators/include/Generators/GeneratorFileOrCmd.h new file mode 100644 index 0000000000000..0c9c618928549 --- /dev/null +++ b/Generators/include/Generators/GeneratorFileOrCmd.h @@ -0,0 +1,243 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen + +#ifndef ALICEO2_EVENTGEN_GENERATORFILEORCMD_H_ +#define ALICEO2_EVENTGEN_GENERATORFILEORCMD_H_ +#include +#include +#include + +namespace o2 +{ +namespace conf +{ +class SimConfig; +} +namespace eventgen +{ + +/** Service class for either reading from a file or executing a + program writing to a specific file */ +struct GeneratorFileOrCmd { + /** + * Configure the generator from parameters and the general + * simulation configuration. This is implemented as a member + * function so as to better facilitate changes. */ + void setup(const GeneratorFileOrCmdParam& param, + const conf::SimConfig& config); + /** + * Set command to execute in bacground rather than reading from + * existing file(s) + * + * @param cmd Command line. Can include options for the program to + * execute, but should not include pipes. + */ + void setCmd(const std::string& cmd) { mCmd = cmd; } + /** + * Set the number of events that a background command should + * generate. This should come from @c SimConfig::getNEents. + * + * @param nev Number of events to generate. This is passed via @c + * mNEventsSwitch to the command line. + */ + void setNEvents(unsigned int nev) { mNEvents = nev; } + /** + * Set the random number seed that a background command should use. + * This should come from @c SimConfig::getStartSeed + * + * @param seed Random number seed. Will be passed to the + * commandline using the @c mSeedSwitch. + */ + void setSeed(unsigned long seed) { mSeed = seed; } + /** + * Set the maximum impact parameter to sample by a background + * command. This should come from @c SimConfig::getBMax() + * + * @param bmax Maximum impact parameter, in fm, to sample. This is + * passed to the command line via the @c mBmaxSwitch. + */ + void setBmax(float bmax) { mBmax = bmax; } + /** + * Set the file names to read from. + * + * @param filenames A comma seperated list of files to read from. + */ + void setFileNames(const std::string& filenames); + /** + * Set the output switch. + * + * @param opt Command line switch (e.g., @c -o) to specify output + * file name. */ + void setOutputSwitch(const std::string& opt) { mOutputSwitch = opt; } + /** + * Set the seed switch. + * + * @param opt Command line switch (e.g., @c -s) to specify the + * random number seed to use when generating events. + */ + void setSeedSwitch(const std::string& opt) { mSeedSwitch = opt; } + /** + * Set the nevents switch. + * + * @param opt Command line switch (e.g., @c -n) to specify the + * number of events to generate. + */ + void setNEventsSwitch(const std::string& opt) { mNEventsSwitch = opt; } + /** + * Set the maximum impact parameter switch. + * + * @param opt Command line switch (e.g., @c -b) to specify the + * maximum impact parameter (in fm) to sample when generating + * events. + */ + void setBmaxSwitch(const std::string& opt) { mBmaxSwitch = opt; } + /** + * Set the background switch. + * + * @param opt Command line switch (e.g., @c &) to detach and send + * the event generator program into the background. + */ + void setBackgroundSwitch(const std::string& opt) { mBackgroundSwitch = opt; } + /** Set the wait time, in miliseconds, when waiting for data */ + void setWait(int miliseconds = 500) { mWait = miliseconds; } + + protected: + /** + * Format a command line using the set command line, option flags, + * and option values. + * + * @return formatted command line. + */ + virtual std::string makeCmdLine() const; + /** + * Execute a command line (presumably formatted by @c makeCmdLine). + * If the command failed to execute, then make it a fatal error. + * + * @param cmd Command line to execute, presumabley formatted by @c + * makeCmdLine. + + * @return true if the background command line was executed, false + * otherwise. + */ + virtual bool executeCmdLine(const std::string& cmd) const; + /** + * Create a temporary file (and close it immediately). On success, + * the list of file names is cleared and the name of the temporary + * file set as the sole element in that list. + * + * @return true if the temporary file name was generated + * successfully. + */ + virtual bool makeTemp(); + /** + * Remove the temporary file if it was set and it exists. + * + * @return true if the temporary file was removed. + */ + virtual bool removeTemp() const; + /** + * Make a fifo at the location of the first element of the list of + * file names (presumably a temporary file as created by + * makeTemp). + * + * @return true if the FIFo was made correctly + */ + virtual bool makeFifo() const; + /** + * Ensure that all files in the list of file names exists. If @e + * any of te file names point to a net resource (e.g., @c alien://or + * @c https://) then this member function should @e not be called + * + * The file names registered are replaced with their canonical path + * equivalents. + * + * @return true if all currently registered file names can be found. + */ + virtual bool ensureFiles(); + /** + * Wait for data to be available in case we're executing a + * background command + */ + virtual void waitForData(const std::string& filename) const; + /** + * Possible command line to execute. The command executed must + * accept the switches defined below. Note if @c mOutputSwitch is + * set to @c ">", then the program @e must write data to standard + * output + */ + std::string mCmd = ""; + /** + * List of file names to read. In case we're executing a command, + * then there will only be one file name in the list + */ + std::list mFileNames; + /** + * Name of temporary file, if it was created. + */ + std::string mTemporary; + /** + * Number of events to generate in case we're executing a command. + * This is passed to the program via the switch @c + * mNEventsSwitch + */ + unsigned int mNEvents = 0; + /** + * Random number seed to use in case we're executing a command. + * This is passed to the program via the switch @c + * mSeedSwitch + */ + unsigned long mSeed = 0; + /** + * Maximum impact parameter to sample in case we're executing a + * command. IF negative, then it is not passed to the command. + * This is passed to the command via the switch @c mBmaxSwitch + */ + float mBmax = -1.f; + /** + * Switch to direct output to specified file. In case of a fifo, + * this should often be @c ">" - i.e., the standard output of the + * program is redirected to the fifo. + */ + std::string mOutputSwitch = ">"; + /** + * The switch specify the random number seed to the program + * executed + */ + std::string mSeedSwitch = "-s"; + /** + * The switch to specify the number of events to generate to the + * program being executed + */ + std::string mNEventsSwitch = "-n"; + /** + * The switch to specify maximum impact parameter to sample by the + * program being executed. + */ + std::string mBmaxSwitch = "-b"; + /** + * The "switch" to put the program being executed in the + * background. + */ + std::string mBackgroundSwitch = "&"; + /** + * Time in miliseconds between each wait for data + */ + int mWait = 500; +}; + +} // namespace eventgen +} // namespace o2 +#endif +// Local Variables: +// mode: C++ +// End: diff --git a/Generators/include/Generators/GeneratorFileOrCmdParam.h b/Generators/include/Generators/GeneratorFileOrCmdParam.h new file mode 100644 index 0000000000000..5d9dd06cb6f6b --- /dev/null +++ b/Generators/include/Generators/GeneratorFileOrCmdParam.h @@ -0,0 +1,45 @@ +// Copyright 2023-2099 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen + +#ifndef ALICEO2_EVENTGEN_GENERATORFILEORCMDPARAM_H_ +#define ALICEO2_EVENTGEN_GENERATORFILEORCMDPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" +#include + +namespace o2 +{ +namespace eventgen +{ + +/** + ** a parameter class/struct to keep the settings of + ** the Fileorcmd event generator and + ** allow the user to modify them + **/ +struct GeneratorFileOrCmdParam : public o2::conf::ConfigurableParamHelper { + std::string fileNames = ""; + std::string cmd = ""; // Program command line to spawn + std::string outputSwitch = ">"; + std::string seedSwitch = "-s"; + std::string bMaxSwitch = "-b"; + std::string nEventsSwitch = "-n"; + std::string backgroundSwitch = "&"; + O2ParamDef(GeneratorFileOrCmdParam, "FileOrCmd"); +}; + +} // end namespace eventgen +} // end namespace o2 + +#endif // ALICEO2_EVENTGEN_GENERATORFILEORCMDPARAM_H_ diff --git a/Generators/include/Generators/GeneratorHepMC.h b/Generators/include/Generators/GeneratorHepMC.h index 8bcc567dd768b..3a11df1fcd6f6 100644 --- a/Generators/include/Generators/GeneratorHepMC.h +++ b/Generators/include/Generators/GeneratorHepMC.h @@ -15,7 +15,8 @@ #define ALICEO2_EVENTGEN_GENERATORHEPMC_H_ #include "Generators/Generator.h" -#include +#include "Generators/GeneratorFileOrCmd.h" +#include "Generators/GeneratorHepMCParam.h" #ifdef GENERATORS_WITH_HEPMC3_DEPRECATED namespace HepMC @@ -35,36 +36,52 @@ class FourVector; namespace o2 { +namespace conf +{ +class SimConfig; +} namespace eventgen { /*****************************************************************/ /*****************************************************************/ -class GeneratorHepMC : public Generator +class GeneratorHepMC : public Generator, public GeneratorFileOrCmd { public: /** default constructor **/ GeneratorHepMC(); /** constructor **/ - GeneratorHepMC(const Char_t* name, const Char_t* title = "ALICEo2 HepMC Generator"); + GeneratorHepMC(const Char_t* name, + const Char_t* title = "ALICEo2 HepMC Generator"); /** destructor **/ ~GeneratorHepMC() override; - /** Initialize the generator if needed **/ + /** Initialize the generator. **/ Bool_t Init() override; - /** methods to override **/ + /** + * Configure the generator from parameters and the general + * simulation configuration. This is implemented as a member + * function so as to better facilitate changes. */ + void setup(const GeneratorFileOrCmdParam& param0, + const GeneratorHepMCParam& param, + const conf::SimConfig& config); + /** + * Generate a single event. The event is read in from the current + * input file. Returns false if a new event could not be read. + **/ Bool_t generateEvent() override; + /** + * Import particles from the last read event into a vector + * TParticle. Returns false if no particles could be exported to + * the vector. + */ Bool_t importParticles() override; /** setters **/ - void setVersion(Int_t val) { mVersion = val; }; - void setFileName(std::string val) { mFileName = val; }; - void setProgCmd(std::string val) { mProgCmd = val; }; void setEventsToSkip(uint64_t val) { mEventsToSkip = val; }; - void setNEvents(unsigned int val) { mNEvents = val; } protected: /** copy constructor **/ @@ -81,21 +98,14 @@ class GeneratorHepMC : public Generator /** methods that can be overridded **/ void updateHeader(o2::dataformats::MCEventHeader* eventHeader) override; + /** Make our reader */ + bool makeReader(); /** HepMC interface **/ - std::ifstream mStream; //! - std::string mFileName; - std::string mProgCmd; - Int_t mVersion; - uint64_t mEventsToSkip; - unsigned int mNEvents; -#ifdef GENERATORS_WITH_HEPMC3_DEPRECATED - HepMC::Reader* mReader; //! - HepMC::GenEvent* mEvent; //! -#else - HepMC3::Reader* mReader; //! - HepMC3::GenEvent* mEvent; //! -#endif + uint64_t mEventsToSkip = 0; + std::shared_ptr mReader; + /** Event structure */ + HepMC3::GenEvent* mEvent = nullptr; ClassDefOverride(GeneratorHepMC, 1); diff --git a/Generators/include/Generators/GeneratorHepMCParam.h b/Generators/include/Generators/GeneratorHepMCParam.h index b44841df3cb61..a3fc9ea81930a 100644 --- a/Generators/include/Generators/GeneratorHepMCParam.h +++ b/Generators/include/Generators/GeneratorHepMCParam.h @@ -30,9 +30,7 @@ namespace eventgen **/ struct GeneratorHepMCParam : public o2::conf::ConfigurableParamHelper { - std::string fileName = ""; - std::string progCmd = ""; // Program command line to spawn, must write HepMC on stdout - int version = 2; + int version = 3; uint64_t eventsToSkip = 0; O2ParamDef(GeneratorHepMCParam, "HepMC"); }; diff --git a/Generators/include/Generators/GeneratorTParticle.h b/Generators/include/Generators/GeneratorTParticle.h index 8887ab344434f..e4ddb5fa1f340 100644 --- a/Generators/include/Generators/GeneratorTParticle.h +++ b/Generators/include/Generators/GeneratorTParticle.h @@ -14,7 +14,8 @@ #define ALICEO2_GENERATORTPARTICLE_H_ #include #include -#include +#include +#include // Forward decls class TChain; @@ -23,6 +24,10 @@ class TClonesArray; namespace o2 { +namespace conf +{ +class SimConfig; +} namespace eventgen { /// A class that reads in particles of class @c TParticle from a @@ -48,11 +53,11 @@ namespace eventgen /// /// --configKeyValues "TParticle.fileNames=foo.root,bar.root" /// -class GeneratorTParticle : public Generator +class GeneratorTParticle : public Generator, public GeneratorFileOrCmd { public: /** CTOR */ - GeneratorTParticle() = default; + GeneratorTParticle(); /** CTOR */ GeneratorTParticle(const std::string& name) : Generator(name.c_str(), "ALICEo2 TParticle Generator") @@ -62,45 +67,45 @@ class GeneratorTParticle : public Generator virtual ~GeneratorTParticle(); /** Initialize this generator. This will set up the chain. -Optionally, if a command line was specified by @c -TParticle.progCmd then that command line is executed in the -background and events are read from the output file of that -program */ + * Optionally, if a command line was specified by @c + * TParticle.progCmd then that command line is executed in the + * background and events are read from the output file of that + * program */ Bool_t Init() override; - /** Read in the next entry from the chain. Returns false in -case of errors or no more entries to read. */ + /** + * Configure the generator from parameters and the general + * simulation configuration. This is implemented as a member + * function so as to better facilitate changes. */ + void setup(const GeneratorFileOrCmdParam& param0, + const GeneratorTParticleParam& param, + const conf::SimConfig& config); + /** Read in the next entry from the chain. Returns false in case of + * errors or no more entries to read. */ Bool_t generateEvent() override; - /** Import the read-in particles into the steer particle -stack */ + /** Import the read-in particles into the steer particle stack */ Bool_t importParticles() override; - /** Set the names of files to read, separated by commas */ - void setFileNames(const std::string& val); - /** Set the name of the tree in the files. The tree _must_ -reside in the top-level directory of the files. */ + /** Set the name of the tree in the files. The tree _must_ reside + * in the top-level directory of the files. */ void setTreeName(const std::string& val) { mTreeName = val; } - /** Set the branch name of the branch that holds a @c -TClonesArray of @c TParticle objects */ + /** Set the branch name of the branch that holds a @c TClonesArray + * of @c TParticle objects */ void setBranchName(const std::string& val) { mBranchName = val; } - /** Set child program command line to (optionally) execute */ - void setProgCmd(const std::string& val) { mProgCmd = val; } - /** Set the number of events to generate. */ - void setNEvents(unsigned int nev) { mNEvents = nev; } protected: + /** Name of the tree to read */ std::string mTreeName = "T"; + /** Name of branch containing a TClonesArray of TParticle */ std::string mBranchName = "Particles"; - std::string mProgCmd = ""; - std::list mFileNames; - unsigned int mNEvents = 0; + /** Current entry */ unsigned int mEntry = 0; - TChain* mChain; + /** Chain of files */ + TChain* mChain = 0; + /** Array to read particles into */ TClonesArray* mTParticles; - void waitForData(); - ClassDefOverride(GeneratorTParticle, 1); }; } // namespace eventgen diff --git a/Generators/include/Generators/GeneratorTParticleParam.h b/Generators/include/Generators/GeneratorTParticleParam.h index 992c76a9fae3e..98059f3b0e1e6 100644 --- a/Generators/include/Generators/GeneratorTParticleParam.h +++ b/Generators/include/Generators/GeneratorTParticleParam.h @@ -16,21 +16,19 @@ #include "CommonUtils/ConfigurableParam.h" #include "CommonUtils/ConfigurableParamHelper.h" #include - namespace o2 { namespace eventgen { /** - a parameter class/struct to keep the settings of the TGenerator - event generator and allow the user to modify them */ + * a parameter class/struct to keep the settings of the TGenerator + * event generator and allow the user to modify them + */ struct GeneratorTParticleParam : public o2::conf::ConfigurableParamHelper { std::string treeName = "T"; std::string branchName = "Particles"; - std::string fileNames = "tparticle.root"; - std::string progCmd = ""; - O2ParamDef(GeneratorTParticleParam, "TParticle"); + O2ParamDef(GeneratorTParticleParam, "GeneratorTParticle"); }; } // end namespace eventgen } // end namespace o2 diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index e572b5594e71e..6780315974c2c 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -162,29 +162,25 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair } else if (genconfig.compare("tparticle") == 0) { // External ROOT file(s) with tree of TParticle in clones array, // or external program generating such a file + auto& param0 = GeneratorFileOrCmdParam::Instance(); auto& param = GeneratorTParticleParam::Instance(); LOG(info) << "Init 'GeneratorTParticle' with the following parameters"; + LOG(info) << param0; LOG(info) << param; auto tgen = new o2::eventgen::GeneratorTParticle(); - tgen->setFileNames(param.fileNames); - tgen->setProgCmd(param.progCmd); - tgen->setTreeName(param.treeName); - tgen->setBranchName(param.branchName); - tgen->setNEvents(conf.getNEvents()); + tgen->setup(param0, param, conf); primGen->AddGenerator(tgen); #ifdef GENERATORS_WITH_HEPMC3 } else if (genconfig.compare("hepmc") == 0) { // external HepMC file, or external program writing HepMC event // records to standard output. + auto& param0 = GeneratorFileOrCmdParam::Instance(); auto& param = GeneratorHepMCParam::Instance(); LOG(info) << "Init \'GeneratorHepMC\' with following parameters"; + LOG(info) << param0; LOG(info) << param; auto hepmcGen = new o2::eventgen::GeneratorHepMC(); - hepmcGen->setFileName(param.fileName); - hepmcGen->setProgCmd(param.progCmd); - hepmcGen->setVersion(param.version); - hepmcGen->setEventsToSkip(param.eventsToSkip); - hepmcGen->setNEvents(conf.getNEvents()); + hepmcGen->setup(param0, param, conf); primGen->AddGenerator(hepmcGen); #endif #ifdef GENERATORS_WITH_PYTHIA6 diff --git a/Generators/src/GeneratorFileOrCmd.cxx b/Generators/src/GeneratorFileOrCmd.cxx new file mode 100644 index 0000000000000..9f879435705f3 --- /dev/null +++ b/Generators/src/GeneratorFileOrCmd.cxx @@ -0,0 +1,207 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author R+Preghenella - August 2017 + +#include "SimulationDataFormat/MCUtils.h" +#include "Generators/GeneratorFileOrCmd.h" +// For fifo's and system call +#include +#include // POSIX only +#include // POISX only +#include +// For filesystem operations +#include +// Waits +#include +// Log messages +#include +#include + +namespace +{ +std::string ltrim(const std::string& s, const std::string& what = "\" ' ") +{ + auto start = s.find_first_not_of(what); + if (start == std::string::npos) + return ""; + + return s.substr(start); +} + +std::string rtrim(const std::string& s, const std::string& what = "\"' ") +{ + auto end = s.find_last_not_of(what); + return s.substr(0, end + 1); +} + +std::string trim(const std::string& s, const std::string& what = "\"' ") +{ + return rtrim(ltrim(s, what), what); +} +} // namespace + +namespace o2 +{ +namespace eventgen +{ +// ----------------------------------------------------------------- +void GeneratorFileOrCmd::setup(const GeneratorFileOrCmdParam& param, + const conf::SimConfig& config) +{ + setFileNames(param.fileNames); + setCmd(param.cmd); + setOutputSwitch(trim(param.outputSwitch)); + setSeedSwitch(trim(param.seedSwitch)); + setBmaxSwitch(trim(param.bMaxSwitch)); + setNEventsSwitch(trim(param.nEventsSwitch)); + setBackgroundSwitch(trim(param.backgroundSwitch)); + setSeed(config.getStartSeed()); + setNEvents(config.getNEvents()); + setBmax(config.getBMax()); +} +// ----------------------------------------------------------------- +void GeneratorFileOrCmd::setFileNames(const std::string& filenames) +{ + std::stringstream s(filenames); + std::string f; + while (std::getline(s, f, ',')) + mFileNames.push_back(f); +} +// ----------------------------------------------------------------- +std::string GeneratorFileOrCmd::makeCmdLine() const +{ + std::string fileName = mFileNames.front(); + std::stringstream s; + s << mCmd << " "; + if (not mSeedSwitch.empty() and mSeedSwitch != "none") + s << mSeedSwitch << " " << mSeed << " "; + if (not mNEventsSwitch.empty() and mNEventsSwitch != "none") + s << mNEventsSwitch << " " << mNEvents << " "; + if (not mBmaxSwitch.empty() and mBmax >= 0 and mBmaxSwitch != "none") + s << mBmaxSwitch.c_str() << " " << mBmax << " "; + + s << mOutputSwitch << " " << fileName << " " + << mBackgroundSwitch; + return s.str(); +} +// ----------------------------------------------------------------- +bool GeneratorFileOrCmd::executeCmdLine(const std::string& cmd) const +{ + LOG(info) << "Command line to execute: \"" << cmd << "\""; + int ret = std::system(cmd.c_str()); + if (ret != 0) { + LOG(fatal) << "Failed to spawn \"" << cmd << "\""; + return false; + } + return true; +} +// ----------------------------------------------------------------- +bool GeneratorFileOrCmd::makeTemp() +{ + mFileNames.clear(); + char buf[] = "generatorFifoXXXXXX"; + auto fp = mkstemp(buf); + if (fp < 0) { + LOG(fatal) << "Failed to make temporary file: " + << std::strerror(errno); + return false; + } + mTemporary = std::string(buf); + mFileNames.push_back(mTemporary); + close(fp); + return true; +} +// ----------------------------------------------------------------- +bool GeneratorFileOrCmd::removeTemp() const +{ + if (mTemporary.empty()) { + LOG(info) << "Temporary file name empty, nothing to remove"; + return false; + } + + // Get the file we're reading from + std::filesystem::path p(mTemporary); + + // Check if the file exists + if (not std::filesystem::exists(p)) { + LOG(info) << "Temporary file " << p << " does not exist"; + return true; + } + + // Remove temporary file + std::error_code ec; + std::filesystem::remove(p, ec); + if (ec) { + LOG(warn) << "When removing " << p << ": " << ec.message(); + } + + // Ignore errors when removing the temporary file + return true; +} +// ----------------------------------------------------------------- +bool GeneratorFileOrCmd::makeFifo() const +{ + // First remove the temporary file if it exists, + // otherwise we may not be able to make the FIFO + removeTemp(); + + std::string fileName = mFileNames.front(); + + int ret = mkfifo(fileName.c_str(), 0600); + if (ret != 0) { + LOG(fatal) << "Failed to make fifo \"" << fileName << "\": " + << std::strerror(errno); + return false; + } + + return true; +} +// ----------------------------------------------------------------- +bool GeneratorFileOrCmd::ensureFiles() +{ + try { + for (auto& f : mFileNames) { + auto c = std::filesystem::canonical(std::filesystem::path(f)); + f = c.c_str(); + } + } catch (std::exception& e) { + LOG(error) << e.what(); + return false; + } + return true; +} +// ----------------------------------------------------------------- +void GeneratorFileOrCmd::waitForData(const std::string& filename) const +{ + using namespace std::chrono_literals; + + // Get the file we're reading from + std::filesystem::path p(filename); + + LOG(debug) << "Waiting for data on " << p; + + // Wait until child process creates the file + while (not std::filesystem::exists(p)) + std::this_thread::sleep_for(mWait * 1ms); + + // Wait until we have more data in the file than just the file + // header + while (std::filesystem::file_size(p) <= 256) + std::this_thread::sleep_for(mWait * 1ms); + + // Give the child process 1 second to post the data to the file + LOG(debug) << "Got data in " << p << ", sleeping for a while"; + std::this_thread::sleep_for(mWait * 2ms); +} + +} /* namespace eventgen */ +} /* namespace o2 */ diff --git a/Generators/src/GeneratorFileOrCmdParam.cxx b/Generators/src/GeneratorFileOrCmdParam.cxx new file mode 100644 index 0000000000000..e452f272c3735 --- /dev/null +++ b/Generators/src/GeneratorFileOrCmdParam.cxx @@ -0,0 +1,18 @@ +// Copyright 2023-2099 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @author Christian Holm Christensen + +#include "Generators/GeneratorFileOrCmdParam.h" +O2ParamImpl(o2::eventgen::GeneratorFileOrCmdParam); +// +// EOF +// diff --git a/Generators/src/GeneratorHepMC.cxx b/Generators/src/GeneratorHepMC.cxx index a5fb510ba479f..89bb4d09bfe33 100644 --- a/Generators/src/GeneratorHepMC.cxx +++ b/Generators/src/GeneratorHepMC.cxx @@ -15,20 +15,14 @@ #include "Generators/GeneratorHepMC.h" #include "Generators/GeneratorHepMCParam.h" #include "SimulationDataFormat/MCEventHeader.h" -#include "HepMC3/ReaderAscii.h" -#include "HepMC3/ReaderAsciiHepMC2.h" +#include "SimConfig/SimConfig.h" +#include "HepMC3/ReaderFactory.h" #include "HepMC3/GenEvent.h" #include "HepMC3/GenParticle.h" #include "HepMC3/GenVertex.h" #include "HepMC3/FourVector.h" #include "HepMC3/Version.h" #include "TParticle.h" -#include "TSystem.h" - -#include -#include // POSIX only -#include // POISX only -#include #include #include "FairPrimaryGenerator.h" @@ -43,19 +37,14 @@ namespace eventgen /*****************************************************************/ GeneratorHepMC::GeneratorHepMC() - : Generator("ALICEo2", "ALICEo2 HepMC Generator"), mStream(), mFileName(), mVersion(3), mReader(nullptr), mEvent(nullptr) + : GeneratorHepMC("ALICEo2", "ALICEo2 HepMC Generator") { - /** default constructor **/ - - mEvent = new HepMC3::GenEvent(); - mInterface = reinterpret_cast(mEvent); - mInterfaceName = "hepmc"; } /*****************************************************************/ GeneratorHepMC::GeneratorHepMC(const Char_t* name, const Char_t* title) - : Generator(name, title), mStream(), mFileName(), mVersion(3), mReader(nullptr), mEvent(nullptr) + : Generator(name, title) { /** constructor **/ @@ -69,37 +58,48 @@ GeneratorHepMC::GeneratorHepMC(const Char_t* name, const Char_t* title) GeneratorHepMC::~GeneratorHepMC() { /** default destructor **/ - - if (mStream.is_open()) { - mStream.close(); - } - if (mReader) { + LOG(info) << "Destructing GeneratorHepMC"; + if (mReader) mReader->close(); - delete mReader; - } - if (mEvent) { + if (mEvent) delete mEvent; - } + removeTemp(); +} + +/*****************************************************************/ +void GeneratorHepMC::setup(const GeneratorFileOrCmdParam& param0, + const GeneratorHepMCParam& param, + const conf::SimConfig& config) +{ + GeneratorFileOrCmd::setup(param0, config); + setEventsToSkip(param.eventsToSkip); } /*****************************************************************/ Bool_t GeneratorHepMC::generateEvent() { + LOG(debug) << "Generating an event"; /** generate event **/ + int tries = 0; + do { + LOG(debug) << " try # " << ++tries; + if (not mReader and not makeReader()) + return false; - /** clear and read event **/ - mEvent->clear(); - mReader->read_event(*mEvent); - if (mReader->failed()) { - LOG(error) << "Failed to read one event from input"; - return kFALSE; - } - /** set units to desired output **/ - mEvent->set_units(HepMC3::Units::GEV, HepMC3::Units::MM); + /** clear and read event **/ + mEvent->clear(); + mReader->read_event(*mEvent); + if (not mReader->failed()) { + /** set units to desired output **/ + mEvent->set_units(HepMC3::Units::GEV, HepMC3::Units::MM); + LOG(debug) << "Read one event " << mEvent->event_number(); + return true; + } + } while (true); - /** success **/ - return kTRUE; + /** failure **/ + return false; } /*****************************************************************/ @@ -229,8 +229,8 @@ void GeneratorHepMC::updateHeader(o2::dataformats::MCEventHeader* eventHeader) eventHeader->putInfo(Key::pdfScale, pdfInfo->scale); eventHeader->putInfo(Key::pdfXF1, pdfInfo->xf[0]); eventHeader->putInfo(Key::pdfXF2, pdfInfo->xf[1]); - eventHeader->putInfo(Key::pdfCode1, pdfInfo->pdf_id[0]); - eventHeader->putInfo(Key::pdfCode2, pdfInfo->pdf_id[1]); + eventHeader->putInfo(Key::pdfCode1, pdfInfo->pdf_id[0]); + eventHeader->putInfo(Key::pdfCode2, pdfInfo->pdf_id[1]); } // Set heavy-ion information @@ -279,6 +279,44 @@ void GeneratorHepMC::updateHeader(o2::dataformats::MCEventHeader* eventHeader) /*****************************************************************/ +bool GeneratorHepMC::makeReader() +{ + // Reset the reader smart pointer + LOG(debug) << "Reseting the reader"; + mReader.reset(); + + // Check that we have any file names left + if (mFileNames.size() < 1) { + LOG(debug) << "No more files to read, return false"; + return false; + } + + // If we have file names left, pop the top of the list (LIFO) + auto filename = mFileNames.front(); + mFileNames.pop_front(); + + LOG(debug) << "Next file to read: \"" << filename << "\" " + << mFileNames.size() << " left"; + + if (not mCmd.empty()) { + // For FIFO reading, we assume straight ASCII output always. + // Unfortunately, the HepMC3::deduce_reader `stat`s the filename + // which isn't supported on a FIFO, so we have to use the reader + // directly. + LOG(info) << "Creating ASCII reader of " << filename; + mReader.reset(new HepMC3::ReaderAscii(filename)); + } else { + LOG(info) << "Deduce a reader of " << filename; + mReader = HepMC3::deduce_reader(filename); + } + + bool ret = bool(mReader) and not mReader->failed(); + LOG(info) << "Reader is " << mReader.get() << " " << ret; + return ret; +} + +/*****************************************************************/ + Bool_t GeneratorHepMC::Init() { /** init **/ @@ -286,8 +324,6 @@ Bool_t GeneratorHepMC::Init() /** init base class **/ Generator::Init(); - std::string filename = gSystem->ExpandPathName(mFileName.c_str()); - // If a EG command line is given, then we make a fifo on a temporary // file, and directs the EG to write to that fifo. We will then set // up the HepMC3 reader to read from that fifo. @@ -303,87 +339,63 @@ Bool_t GeneratorHepMC::Init() // crmc -n 3 -o hepmc3 -c /optsw/inst/etc/crmc.param -f /dev/stdout \ // | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' // - // What's more, the event generator program must accept the command - // line argument `-n NEVENTS` to set the number of events to - // produce. + // What's more, the event generator program _must_ accept the + // following command line argument // - // Perhaps we should consider a way to set a seed on the EG. It - // could be another configuration parameter. Of course, if the EG - // program accepts a seed option, say `-s SEED`, then one could - // simply pass + // `-n NEVENTS` to set the number of events to produce. // - // -s \$RANDOM + // Optionally, the command line should also accept // - // to as part of the command line in `progCmd`. + // `-s SEED` to set the random number seed + // `-b FM` to set the maximum impact parameter to sample + // `-o OUTPUT` to set the output file name // // All of this can conviniently be achieved via a wrapper script // around the actual EG program. - if (not mProgCmd.empty()) { + if (not mCmd.empty()) { // Set filename to be a temporary name - // Should perhaps use - // - // TString base("xxxxxx"); - // auto fp = gSystem->TempFileName(base); - // fclose(fp); - // - filename = std::tmpnam(nullptr); + if (not makeTemp()) + return false; // Make a fifo - int ret = mkfifo(filename.c_str(), 0600); - if (ret != 0) { - LOG(fatal) << "Failed to make fifo \"" << filename << "\""; + if (not makeFifo()) return false; - } // Build command line, rediret stdout to our fifo and put - // in the background. - std::string cmd = - mProgCmd + - " -n " + std::to_string(mNEvents) + - " > " + filename + " &"; - LOG(info) << "EG command line is \"" << cmd << "\""; - - ret = std::system(cmd.c_str()); - if (ret != 0) { + std::string cmd = makeCmdLine(); + LOG(debug) << "EG command line is \"" << cmd << "\""; + + // Execute the command line + if (not executeCmdLine(cmd)) { LOG(fatal) << "Failed to spawn \"" << cmd << "\""; return false; } - } - /** open file **/ - mStream.open(filename); - if (!mStream.is_open()) { - LOG(fatal) << "Cannot open input file: " << filename << std::endl; - return kFALSE; - } - - LOG(info) << "Set up reader to read from \"" << filename << "\"" << std::endl; - /** create reader according to HepMC version **/ - switch (mVersion) { - case 2: - mStream.close(); - mReader = new HepMC3::ReaderAsciiHepMC2(filename); - break; - case 3: - mReader = new HepMC3::ReaderAscii(mStream); - break; - default: - LOG(fatal) << "Unsupported HepMC version: " << mVersion << std::endl; - return kFALSE; - } - - // skip events at the beginning - if (!mReader->failed()) { - LOGF(info, "%i events to skip.", mEventsToSkip); - for (auto ind = 0; ind < mEventsToSkip; ind++) { - if (!generateEvent()) { - LOGF(error, "The file %s only contains %i events!", mFileName, ind); - break; - } - } + } else { + // If no command line was given, ensure that all files are present + // on the system. Note, in principle, HepMC3 can read from remote + // files + // + // root:// XRootD served + // http[s]:// Web served + // gsidcap:// DCap served + // + // These will all be handled in HepMC3 via ROOT's TFile protocol + // and the files are assumed to contain a TTree named + // `hepmc3_tree` and that tree has the branches + // + // `hepmc3_event` with object of type `HepMC3::GenEventData` + // `GenRunInfo` with object of type `HepMC3::GenRunInfoData` + // + // where the last branch is optional. + // + // However, here we will assume system local files. If _any_ of + // the listed files do not exist, then we fail. + if (not ensureFiles()) + return false; } - /** success **/ - return !mReader->failed(); + // Create reader for current (first) file + return true; } /*****************************************************************/ diff --git a/Generators/src/GeneratorTParticle.cxx b/Generators/src/GeneratorTParticle.cxx index d04f0116bfe98..5b3013cce3836 100644 --- a/Generators/src/GeneratorTParticle.cxx +++ b/Generators/src/GeneratorTParticle.cxx @@ -13,23 +13,24 @@ #include #include #include +#include #include #include #include #include #include -#include -#include -#include -#include -#include // POSIX only -#include // POISX only -#include namespace o2 { namespace eventgen { +/*****************************************************************/ +GeneratorTParticle::GeneratorTParticle() +{ + setOutputSwitch("-o"); +} + +/*****************************************************************/ GeneratorTParticle::~GeneratorTParticle() { if (mChain) { @@ -38,110 +39,69 @@ GeneratorTParticle::~GeneratorTParticle() mChain->RecursiveRemove(file); delete mChain; } - if (mProgCmd.empty()) - return; - - // Get the file we're reading from - std::filesystem::path p(mFileNames.front()); - - // Wait until child process creates the file - if (not std::filesystem::exists(p)) + if (mCmd.empty()) return; - // Remove temporary file - std::error_code ec; - std::filesystem::remove(p, ec); + removeTemp(); } - -void GeneratorTParticle::setFileNames(const std::string& val) -{ - std::stringstream s; - std::string f; - while (std::getline(s, f, ',')) - mFileNames.push_back(f); -} - +/*****************************************************************/ Bool_t GeneratorTParticle::Init() { mChain = new TChain(mTreeName.c_str()); mTParticles = new TClonesArray("TParticle"); mChain->SetBranchAddress(mBranchName.c_str(), &mTParticles); - if (not mProgCmd.empty()) { + if (not mCmd.empty()) { // Set filename to be a temporary name - // Should perhaps use - // - // TString base("xxxxxx"); - // auto fp = gSystem->TempFileName(base); - // fclose(fp); - // - std::string filename = std::tmpnam(nullptr); + if (not makeTemp()) + return false; // Build command line, Assumes command line parameter - // - // -n NUMBER of events to produce - // -o FILENAME of output file - // - // A script can be wrapped around existing EGs to ensure these - // options are observed. - std::string cmd = - mProgCmd + - " -n " + std::to_string(mNEvents) + - " -o " + filename + " &"; + std::string cmd = makeCmdLine(); LOG(info) << "EG command line is \"" << cmd << "\""; - int ret = std::system(cmd.c_str()); - if (ret != 0) { + // Execute the background command + if (not executeCmdLine(cmd)) { LOG(fatal) << "Failed to spawn \"" << cmd << "\""; return false; } - - mFileNames.clear(); - mFileNames.push_back(filename); } for (auto filename : mFileNames) mChain->AddFile(filename.c_str()); + // Clear the array of file names + mFileNames.clear(); + return true; } -void GeneratorTParticle::waitForData() +/*****************************************************************/ +void GeneratorTParticle::setup(const GeneratorFileOrCmdParam& param0, + const GeneratorTParticleParam& param, + const conf::SimConfig& config) { - if (mProgCmd.empty()) - return; // Not from child process - - using namespace std::chrono_literals; - - // Get the file we're reading from - std::filesystem::path p(mFileNames.front()); - - LOG(info) << "Waiting for data on " << p; - - // Wait until child process creates the file - while (not std::filesystem::exists(p)) - std::this_thread::sleep_for(500ms); - - // Wait until we have more data in the file than just the file - // header - while (std::filesystem::file_size(p) <= 256) - std::this_thread::sleep_for(500ms); - - // Give the child process 1 second to post the data to the file - LOG(info) << "Got data in " << p << ", sleeping for a while"; - std::this_thread::sleep_for(1s); + GeneratorFileOrCmd::setup(param0, config); + setTreeName(param.treeName); + setBranchName(param.branchName); } +/*****************************************************************/ Bool_t GeneratorTParticle::generateEvent() { - if (mEntry == 0) - waitForData(); + // If this is the first entry, and we're executing a command, then + // wait until the input file exists and actually contain some data. + if (mEntry == 0 and not mCmd.empty()) + waitForData(mTemporary); + // Read in the next entry in the chain int read = mChain->GetEntry(mEntry); mEntry++; + // If we got an error while reading, then give error message if (read < 0) LOG(error) << "Failed to read entry " << mEntry << " of chain"; + // If we had an error or nothing was read back, then return false if (read <= 0) return false; diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 669b1f37019c1..35e77febee172 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -70,5 +70,7 @@ #pragma link C++ class o2::eventgen::GeneratorTParticle + ; #pragma link C++ class o2::eventgen::GeneratorTParticleParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorTParticleParam> + ; +#pragma link C++ class o2::eventgen::GeneratorFileOrCmdParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorFileOrCmdParam> + ; #endif From 05ad595d12e224a5c6259439699cf7b95c4f430f Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 11:49:37 +0200 Subject: [PATCH 13/37] Changed key prefix --- Generators/include/Generators/GeneratorTParticleParam.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generators/include/Generators/GeneratorTParticleParam.h b/Generators/include/Generators/GeneratorTParticleParam.h index 992c76a9fae3e..2acfb2c13c623 100644 --- a/Generators/include/Generators/GeneratorTParticleParam.h +++ b/Generators/include/Generators/GeneratorTParticleParam.h @@ -30,7 +30,7 @@ struct GeneratorTParticleParam : public o2::conf::ConfigurableParamHelper Date: Fri, 6 Oct 2023 11:49:56 +0200 Subject: [PATCH 14/37] Add new sub-dirs --- run/SimExamples/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run/SimExamples/README.md b/run/SimExamples/README.md index 2613f6bb2773c..ae2d15d47316c 100644 --- a/run/SimExamples/README.md +++ b/run/SimExamples/README.md @@ -11,6 +11,7 @@ * \subpage refrunSimExamplesAdaptive_Pythia8 * \subpage refrunSimExamplesAliRoot_Hijing * \subpage refrunSimExamplesAliRoot_AMPT +* \subpage refrunSimExamplesHepMC * \subpage refrunSimExamplesHepMC_STARlight * \subpage refrunSimExamplesJet_Embedding_Pythia8 * \subpage refrunSimExamplesStepMonitoringSimple1 @@ -20,4 +21,5 @@ * \subpage refrunSimExamplesSelective_Transport_pi0 * \subpage refrunSimExamplesCustom_EventInfo * \subpage refrunSimExamplesMCTrackToDPL +* \subpage refrunSimExamplesTParticle /doxy --> From fa6ae4ed9a2068710e15a83b129f8e59242fa91a Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 12:00:04 +0200 Subject: [PATCH 15/37] Undo adding AODToHepMC --- Generators/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index dc1e44d5a65dc..2af6914196e66 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -50,7 +50,6 @@ o2_add_library(Generators $<$:src/DecayerPythia8Param.cxx> $<$:src/GeneratorHepMC.cxx> $<$:src/GeneratorHepMCParam.cxx> - $<$:src/AODToHepMC.cxx> PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimConfig O2::CommonUtils O2::DetectorsBase O2::ZDCBase O2::SimulationDataFormat ${pythia6Target} ${pythiaTarget} ${hepmcTarget} FairRoot::Gen @@ -107,7 +106,6 @@ endif() if(HepMC3_FOUND) list(APPEND headers include/Generators/GeneratorHepMC.h) list(APPEND headers include/Generators/GeneratorHepMCParam.h) - list(APPEND headers include/Generators/AODToHepMC.h) endif() o2_target_root_dictionary(Generators HEADERS ${headers}) From 72b3a9dbe812d1cb26f9aab3d8d8bf44dcbd91fe Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 12:03:24 +0200 Subject: [PATCH 16/37] Undo bad commit - these changes are needed but should be in different MR --- .../ITS/postprocessing/studies/src/AvgClusSize.cxx | 2 +- .../ITSMFT/test/HitAnalysis/src/HitAnalysis.cxx | 1 - Steer/include/Steer/O2RunSim.h | 2 +- Utilities/rANS/benchmarks/bench_ransTPC.cxx | 12 ++---------- run/CMakeLists.txt | 8 -------- 5 files changed, 4 insertions(+), 21 deletions(-) diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/AvgClusSize.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/AvgClusSize.cxx index 6d74c48d0f358..eedb9b2331c8c 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/AvgClusSize.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/AvgClusSize.cxx @@ -266,7 +266,7 @@ void AvgClusSizeStudy::prepareOutput() void AvgClusSizeStudy::setStyle() { - gStyle->SetPalette(kRainBow); + gStyle->SetPalette(kRainbow); std::vector colors = {1, 2, 3, 4, 6, 7, 41, 47}; std::vector markers = {2, 3, 4, 5, 25, 26, 27, 28, 32}; for (int i = 0; i < mAvgClusSizeCEtaVec.size(); i++) { diff --git a/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysis.cxx b/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysis.cxx index 2069ccc8fb423..3085a275d7f25 100644 --- a/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysis.cxx +++ b/Detectors/ITSMFT/test/HitAnalysis/src/HitAnalysis.cxx @@ -20,7 +20,6 @@ #include "HitAnalysis/HitAnalysis.h" #include // for LOG -#include #include // for TH1, TH1D, TH1F #include diff --git a/Steer/include/Steer/O2RunSim.h b/Steer/include/Steer/O2RunSim.h index 19466d3564901..a3b970377314c 100644 --- a/Steer/include/Steer/O2RunSim.h +++ b/Steer/include/Steer/O2RunSim.h @@ -60,7 +60,7 @@ class O2RunSim : public FairRunSim fRootManager->InitSink(); // original FairRunSim follows - FairGeoLoader* loader = new FairGeoLoader(fLoaderName.Data(), "Geo Loader"); + FairGeoLoader* loader = new FairGeoLoader(fLoaderName->Data(), "Geo Loader"); FairGeoInterface* GeoInterFace = loader->getGeoInterface(); GeoInterFace->SetNoOfSets(ListOfModules->GetEntries()); GeoInterFace->setMediaFile(MatFname.Data()); diff --git a/Utilities/rANS/benchmarks/bench_ransTPC.cxx b/Utilities/rANS/benchmarks/bench_ransTPC.cxx index 9c0459c95fc85..daaa106342c15 100644 --- a/Utilities/rANS/benchmarks/bench_ransTPC.cxx +++ b/Utilities/rANS/benchmarks/bench_ransTPC.cxx @@ -378,15 +378,7 @@ int main(int argc, char* argv[]) LOG(info) << "######################################################"; }); writer.EndObject(); - // Not implemented in all version of rapidjson 1.1.0 Seems like - // rapidjson developers does not update version number when making - // API changes - sigh. - // - // writer.Flush(); - // - // We call flush on the output stream instead - // - stream.Flush(); + writer.Flush(); of.close(); // writerFrequencies.EndObject(); @@ -395,4 +387,4 @@ int main(int argc, char* argv[]) // writerRenormed.EndObject(); // writerRenormed.Flush(); // ofRenormed.close(); -}; +}; \ No newline at end of file diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt index 62b804dea58aa..07f23328230dd 100644 --- a/run/CMakeLists.txt +++ b/run/CMakeLists.txt @@ -121,14 +121,6 @@ o2_add_executable(mctracks-to-aod SOURCES o2sim_mctracks_to_aod.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::SimulationDataFormat) -o2_add_executable(mc-to-hepmc - COMPONENT_NAME aod - SOURCES o2aod_mc_to_hepmc.cxx - PUBLIC_LINK_LIBRARIES - O2::Framework - O2::SimulationDataFormat - O2::Generators) - o2_add_dpl_workflow(mctracks-to-aod-simple-task SOURCES SimExamples/McTracksToAOD/mctracks_to_aod_simple_task.cxx PUBLIC_LINK_LIBRARIES O2::Framework From 595d84315bb70297a370293215a8e3132b6746f8 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 13:19:16 +0200 Subject: [PATCH 17/37] Formatting fixes --- run/SimExamples/TParticle/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/run/SimExamples/TParticle/README.md b/run/SimExamples/TParticle/README.md index 45b6bc6eea374..66d9b63a9e951 100644 --- a/run/SimExamples/TParticle/README.md +++ b/run/SimExamples/TParticle/README.md @@ -131,7 +131,7 @@ and a steering class } }; -Then we could make the script [`MyEG.cc` (complete code)](MyEG.cc) like +Then we could make the script [`MyEG.macro` (complete code)](MyEG.macro) like void MyEG(Int_t nev,const TString& out,Int_t every=1) { @@ -143,7 +143,7 @@ Then we could make the script [`MyEG.cc` (complete code)](MyEG.cc) like } and a simple shell-script [`myeg.sh`](myeg.sh) to pass arguments to -the `MyEG.cc` script +the `MyEG.macro` script #!/bin/sh @@ -159,7 +159,7 @@ the `MyEG.cc` script shift done - root -l MyEG.cc -- $nev \"$out\" + root -l MyEG.macro -- $nev \"$out\" We can then do From 4715d37492975b4a1b5f709f656edc3362315ff3 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 13:20:16 +0200 Subject: [PATCH 18/37] Renamed _script_ (not macro) to end in .macro (sigh) --- run/SimExamples/HepMC/README.md | 46 +++++----- run/SimExamples/TParticle/MyEG.macro | 128 +++++++++++++++++++++++++++ run/SimExamples/TParticle/myeg.sh | 2 +- 3 files changed, 149 insertions(+), 27 deletions(-) create mode 100644 run/SimExamples/TParticle/MyEG.macro diff --git a/run/SimExamples/HepMC/README.md b/run/SimExamples/HepMC/README.md index 811e4d6f35440..5783c46d6bb02 100644 --- a/run/SimExamples/HepMC/README.md +++ b/run/SimExamples/HepMC/README.md @@ -5,36 +5,33 @@ Here are pointers on how to use `GeneratorHepMC` selected by the option `-g hepmc` for `o2-sim`. -## Reading HepMC files +## Reading HepMC files The generator `GeneratorHepMC` can read events from a -[HepMC(3)](http://hepmc.web.cern.ch/hepmc/) formatted file. These files -can be produced by a standalone event generator program (EG). -Examples of such programs are +[HepMC(3)](http://hepmc.web.cern.ch/hepmc/) formatted file. These +files can be produced by a standalone event generator program (EG). +Examples of such programs are - [Pythia8](https://pythia.org) -- The [CRMC](https://gitlab.iap.kit.edu/AirShowerPhysics/crmc) suite +- The [CRMC](https://gitlab.iap.kit.edu/AirShowerPhysics/crmc) suite - [Herwig](https://herwig.hepforge.org/) - [SMASH](https://smash-transport.github.io/) -- ... and many others +- ... and many others Please refer to the documentation of these for more on how to make event files in the HepMC format. -To make a simulation reading from the file `events.hepmc`, do - +To make a simulation reading from the file `events.hepmc`, do o2-sim -g hepmc --configKeyValues "HepMC.fileName=events.hepmc" ... See also [`read.sh`](read.sh) -## Reading HepMC events from child process - +## Reading HepMC events from child process `GeneratorHepMC` can not only read HepMC events from a file, but can also spawn an child EG to produce events. Suppose we have a program named `eg` which is some EG that writes HepMC event records to the standard output. Then we can execute a simulation using this external -EG by - +EG by o2-sim -g hepmc --configKeyValues "HepMC.progCmd=eg" See also [`child.sh`](child.sh) @@ -50,10 +47,9 @@ There are some requirements on the program `eg`: If a program does not adhere to these requirements, it will often be simple enough to make a small wrapper script that enforce this. For example, `crmc` will write a lot of information to standard output. -We can filter that out via a shell script ([`crmc.sh`](crmc.sh)) like +We can filter that out via a shell script ([`crmc.sh`](crmc.sh)) like - #!/bin/sh - + #!/bin/sh crmc $@ -o hepmc3 -f /dev/stdout | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' The `sed` command selects lines that begin with `HepMC::`, or one @@ -65,12 +61,12 @@ standard output. The script above also passes any additional command line options on to `crmc` via `$@`. We can utilise this with `o2-sim` to set options to the CRMC suite. For example, if we want to simulate p-Pb collisions -using DpmJET, we can do +using DpmJET, we can do o2-sim -g hepmc --configKeyValues "HepMC.progCmd=crmc.sh -m 12 -i2212 -I 1002080820" -### Implementation details +### Implementation details Internally `GeneratorHepMC` @@ -81,14 +77,14 @@ Internally `GeneratorHepMC` eg options > fifo-name & -4. and executes that command line +4. and executes that command line -## The future +## The future The `GeneratorHepMC` (and sister generator `GeneratorTParticle`) will in the not so distant future be upgraded with new functionality to more easily customise reading files and executing a child process. In -particular +particular - HepMC event structures can be read from any file format supported by HepMC it self (see @@ -101,8 +97,7 @@ particular beginning of each file read. - `FileOrCmd.fileNames=list` a comma separated list of HepMC files - to read - + to read - `FileOrCmd.cmd=command line` a command line to execute as a background child process. If this is set (not the empty string), then `FileOrCmd.fileNames` is ignored. @@ -132,19 +127,18 @@ particular the program is put in the background. Typically this should be `&`, but a program may itself fork to the background. -- Some options are no longer available - +- Some options are no longer available - `HepMC.fileName` - use `FileOrCmd.fileNames` - `HepMC.progCmd` - use `FileOrCmd.cmd` -The command line build will now be +The command line build will now be > _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ > _bMaxSwitch_ _bMax_ _outputSwitch_ _output_ _backgroundSwitch_ If any of the `Switch` keys are empty, then the corresponding option is not propagated to the command line. For example, if _bMaxSwitch_ -is empty, then the build command line will be +is empty, then the build command line will be > _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ > _outputSwitch_ _output_ _backgroundSwitch_ diff --git a/run/SimExamples/TParticle/MyEG.macro b/run/SimExamples/TParticle/MyEG.macro new file mode 100644 index 0000000000000..a067b4c1051b7 --- /dev/null +++ b/run/SimExamples/TParticle/MyEG.macro @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include + +//-------------------------------------------------------------------- +// Our generator class. Really simple. +class MyGenerator : public TGenerator +{ + public: + Long_t projectilePDG; + Long_t targetPDG; + Double_t sqrts; + MyGenerator() {} + void Initialize(Long_t projectile, + Long_t target, + Double_t sqrts) + { + this->projectilePDG = projectile; + this->targetPDG = target; + this->sqrts = sqrts; + } + void GenerateEvent() + { /* Do something */ + } + TObjArray* ImportParticles(Option_t* option = "") { return 0; } + Int_t ImportParticles(TClonesArray* particles, Option_t* option = "") + { + Int_t nParticles = 10; + Int_t iParticle = 0; + // Make beam particles + new ((*particles)[iParticle++]) TParticle(projectilePDG, 4, -1, -1, + 2, nParticles - 1, + 0, 0, sqrts / 2, + TMath::Sqrt(1 + sqrts * sqrts), + 0, 0, 0, 0); + new ((*particles)[iParticle++]) TParticle(projectilePDG, 4, -1, -1, + 2, nParticles - 1, + 0, 0, -sqrts / 2, + TMath::Sqrt(1 + sqrts * sqrts), + 0, 0, 0, 0); + for (; iParticle < nParticles; iParticle++) + new ((*particles)[iParticle]) + TParticle(211, 1, 0, 1, + -1, -1, + 0.1 * iParticle, + 0.1 * iParticle, + 0.1 * iParticle, + TMath::Sqrt(0.03 * iParticle * iParticle + 0.14 * 0.14), + 0, 0, 0, 0); + + return nParticles; + } +}; +//-------------------------------------------------------------------- +// Our steering class +struct MySteer { + TGenerator* generator; + TFile* file; + TTree* tree; + TClonesArray* particles; + Int_t every; + MySteer(TGenerator* generator, const TString& output, Int_t every) + : generator(generator), + file(TFile::Open(output, "RECREATE")), + tree(new TTree("T", "T")), + particles(new TClonesArray("TParticle")), + every(every) + { + tree->SetDirectory(file); + tree->Branch("Particles", &particles); + } + ~MySteer() + { + close(); + } + void event() + { + particles->Clear(); + generator->GenerateEvent(); + generator->ImportParticles(particles); + tree->Fill(); + } + void sync() + { + // Important so that GeneratorTParticle picks up the events as + // they come. + tree->AutoSave("SaveSelf FlushBaskets Overwrite"); + } + void run(Int_t nev) + { + for (Int_t iev = 0; iev < nev; iev++) { + event(); + + if (every > 0 and (iev % every == 0) and iev != 0) + sync(); + } + } + void close() + { + if (not file) + return; + file->Write(); + file->Close(); + file = nullptr; + } +}; + +//-------------------------------------------------------------------- +// Our steering function +void MyEG(Int_t nev, const TString& out, Int_t seed, Int_t every = 1) +{ + gRandom->SetSeed(seed); + + MyGenerator* eg = new MyGenerator(); + eg->Initialize(2212, 2212, 5200); + + MySteer steer(eg, out, every); + steer.run(nev); +} +// Local Variables: +// mode: C++ +// End: +// +// EOF +// diff --git a/run/SimExamples/TParticle/myeg.sh b/run/SimExamples/TParticle/myeg.sh index 5026f285af8cd..28dddc4196e31 100755 --- a/run/SimExamples/TParticle/myeg.sh +++ b/run/SimExamples/TParticle/myeg.sh @@ -18,5 +18,5 @@ while test $# -gt 0 ; do shift done -root -q -l MyEG.cc${opt} -- $nev \"$out\" $seed +root -q -l MyEG.macro${opt} -- $nev \"$out\" $seed From 0434a6ee1493a3772c63439e4a9eff2c4f466de8 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 13:20:40 +0200 Subject: [PATCH 19/37] Renamed _script_ (not macro) to end in .macro (sigh) --- run/SimExamples/TParticle/MyEG.cc | 128 ------------------------------ 1 file changed, 128 deletions(-) delete mode 100644 run/SimExamples/TParticle/MyEG.cc diff --git a/run/SimExamples/TParticle/MyEG.cc b/run/SimExamples/TParticle/MyEG.cc deleted file mode 100644 index a067b4c1051b7..0000000000000 --- a/run/SimExamples/TParticle/MyEG.cc +++ /dev/null @@ -1,128 +0,0 @@ -#include -#include -#include -#include -#include -#include - -//-------------------------------------------------------------------- -// Our generator class. Really simple. -class MyGenerator : public TGenerator -{ - public: - Long_t projectilePDG; - Long_t targetPDG; - Double_t sqrts; - MyGenerator() {} - void Initialize(Long_t projectile, - Long_t target, - Double_t sqrts) - { - this->projectilePDG = projectile; - this->targetPDG = target; - this->sqrts = sqrts; - } - void GenerateEvent() - { /* Do something */ - } - TObjArray* ImportParticles(Option_t* option = "") { return 0; } - Int_t ImportParticles(TClonesArray* particles, Option_t* option = "") - { - Int_t nParticles = 10; - Int_t iParticle = 0; - // Make beam particles - new ((*particles)[iParticle++]) TParticle(projectilePDG, 4, -1, -1, - 2, nParticles - 1, - 0, 0, sqrts / 2, - TMath::Sqrt(1 + sqrts * sqrts), - 0, 0, 0, 0); - new ((*particles)[iParticle++]) TParticle(projectilePDG, 4, -1, -1, - 2, nParticles - 1, - 0, 0, -sqrts / 2, - TMath::Sqrt(1 + sqrts * sqrts), - 0, 0, 0, 0); - for (; iParticle < nParticles; iParticle++) - new ((*particles)[iParticle]) - TParticle(211, 1, 0, 1, - -1, -1, - 0.1 * iParticle, - 0.1 * iParticle, - 0.1 * iParticle, - TMath::Sqrt(0.03 * iParticle * iParticle + 0.14 * 0.14), - 0, 0, 0, 0); - - return nParticles; - } -}; -//-------------------------------------------------------------------- -// Our steering class -struct MySteer { - TGenerator* generator; - TFile* file; - TTree* tree; - TClonesArray* particles; - Int_t every; - MySteer(TGenerator* generator, const TString& output, Int_t every) - : generator(generator), - file(TFile::Open(output, "RECREATE")), - tree(new TTree("T", "T")), - particles(new TClonesArray("TParticle")), - every(every) - { - tree->SetDirectory(file); - tree->Branch("Particles", &particles); - } - ~MySteer() - { - close(); - } - void event() - { - particles->Clear(); - generator->GenerateEvent(); - generator->ImportParticles(particles); - tree->Fill(); - } - void sync() - { - // Important so that GeneratorTParticle picks up the events as - // they come. - tree->AutoSave("SaveSelf FlushBaskets Overwrite"); - } - void run(Int_t nev) - { - for (Int_t iev = 0; iev < nev; iev++) { - event(); - - if (every > 0 and (iev % every == 0) and iev != 0) - sync(); - } - } - void close() - { - if (not file) - return; - file->Write(); - file->Close(); - file = nullptr; - } -}; - -//-------------------------------------------------------------------- -// Our steering function -void MyEG(Int_t nev, const TString& out, Int_t seed, Int_t every = 1) -{ - gRandom->SetSeed(seed); - - MyGenerator* eg = new MyGenerator(); - eg->Initialize(2212, 2212, 5200); - - MySteer steer(eg, out, every); - steer.run(nev); -} -// Local Variables: -// mode: C++ -// End: -// -// EOF -// From e1db4b046eda53d7ea8d16d72f6d32acdd691cdb Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 13:48:16 +0200 Subject: [PATCH 20/37] Fix formatting --- run/SimExamples/HepMC/README.md | 68 +++++++++++++++++---------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/run/SimExamples/HepMC/README.md b/run/SimExamples/HepMC/README.md index 5783c46d6bb02..f6db63a03d28b 100644 --- a/run/SimExamples/HepMC/README.md +++ b/run/SimExamples/HepMC/README.md @@ -3,7 +3,7 @@ /doxy --> Here are pointers on how to use `GeneratorHepMC` selected by the -option `-g hepmc` for `o2-sim`. +option `-g hepmc` for `o2-sim`. ## Reading HepMC files @@ -19,12 +19,12 @@ Examples of such programs are - ... and many others Please refer to the documentation of these for more on how to make -event files in the HepMC format. +event files in the HepMC format. To make a simulation reading from the file `events.hepmc`, do o2-sim -g hepmc --configKeyValues "HepMC.fileName=events.hepmc" ... -See also [`read.sh`](read.sh) +See also [`read.sh`](read.sh). ## Reading HepMC events from child process `GeneratorHepMC` can not only read HepMC events from a file, but can @@ -32,18 +32,19 @@ also spawn an child EG to produce events. Suppose we have a program named `eg` which is some EG that writes HepMC event records to the standard output. Then we can execute a simulation using this external EG by - o2-sim -g hepmc --configKeyValues "HepMC.progCmd=eg" -See also [`child.sh`](child.sh) + o2-sim -g hepmc --configKeyValues "HepMC.progCmd=eg" -There are some requirements on the program `eg`: +See also [`child.sh`](child.sh). + +There are some requirements on the program `eg`: - It _must_ write the HepMC event structures to standard output - (`/dev/stdout`). + (`/dev/stdout`). - It may _not_ write other information to standard output. - It _must_ accept the option `-n n-events` to set the number of - events to produce to `n-events`. - + events to produce to `n-events`. + If a program does not adhere to these requirements, it will often be simple enough to make a small wrapper script that enforce this. For example, `crmc` will write a lot of information to standard output. @@ -56,7 +57,7 @@ The `sed` command selects lines that begin with `HepMC::`, or one of single characters `E` (event), `A` (attribute), `U` (units), `W` (weight), `V` (vertex), or `P` (particle) followed by a space. This should in most cases be enough to filter out extra stuff written on -standard output. +standard output. The script above also passes any additional command line options on to `crmc` via `$@`. We can utilise this with `o2-sim` to set options to @@ -68,15 +69,15 @@ using DpmJET, we can do ### Implementation details -Internally `GeneratorHepMC` +Internally `GeneratorHepMC` 1. creates a unique temporary file name in the working directory, 2. then creates a FIFO (or named pipe, see [Wikipedia](https://en.wikipedia.org/wiki/Named_pipe)), -3. builds a command line, e.g., +3. builds a command line, e.g., + + eg options > fifo-name & - eg options > fifo-name & - 4. and executes that command line ## The future @@ -89,48 +90,49 @@ particular - HepMC event structures can be read from any file format supported by HepMC it self (see [here](http://hepmc.web.cern.ch/hepmc/group__IO.html) and - [here](http://hepmc.web.cern.ch/hepmc/group__factory.html). - -- New options that can be specified in `--configKeyValues` + [here](http://hepmc.web.cern.ch/hepmc/group__factory.html). + +- New options that can be specified in `--configKeyValues` - `HepMC.eventsToSkip=number` a number events to skip at the - beginning of each file read. - + beginning of each file read. + - `FileOrCmd.fileNames=list` a comma separated list of HepMC files - to read + to read. + - `FileOrCmd.cmd=command line` a command line to execute as a background child process. If this is set (not the empty string), - then `FileOrCmd.fileNames` is ignored. - + then `FileOrCmd.fileNames` is ignored. + - A number of keys that specifies the command line option switch that the child program accepts for certain things. If any of these are set to the empty string, then that switch and - corresponding option value is not passed to the child program. - + corresponding option value is not passed to the child program. + - `FileOrCmd.outputSwitch=switch` (default `>`) to specify output file. The default of `>` assumes that the program write HepMC - events, and _only_ those, to standard output. - + events, and _only_ those, to standard output. + - `FileOrCmd.seedSwitch=switch` (default `-s`) to specify the random number generator seed. The value passed is selected by - the `o2-sim` option `--seed` - + the `o2-sim` option `--seed` + - `FileOrCmd.bMaxSwitch=switch` (default `-b`) to specify the upper limit on the impact parameters sampled. The value passed - is selected by the `o2-sim` option `--bMax` - + is selected by the `o2-sim` option `--bMax` + - `FileOrCmd.nEventsSwitch=switch` (default `-n`) to specify the number of events to generate. The value passed is selected by the `o2-sim` option `--nEvents` or (`-n`) - + - `FileOrCmd.backgroundSwitch=switch` (default `&`) to specify how the program is put in the background. Typically this should be `&`, but a program may itself fork to the background. - Some options are no longer available - `HepMC.fileName` - use `FileOrCmd.fileNames` - - `HepMC.progCmd` - use `FileOrCmd.cmd` - + - `HepMC.progCmd` - use `FileOrCmd.cmd` + The command line build will now be > _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ From eb308c0fde09b92de608b7bd9110da34f6ed5428 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 14:52:40 +0200 Subject: [PATCH 21/37] Fix formatting --- run/SimExamples/HepMC/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/run/SimExamples/HepMC/README.md b/run/SimExamples/HepMC/README.md index f6db63a03d28b..54adcd31c990b 100644 --- a/run/SimExamples/HepMC/README.md +++ b/run/SimExamples/HepMC/README.md @@ -22,8 +22,8 @@ Please refer to the documentation of these for more on how to make event files in the HepMC format. To make a simulation reading from the file `events.hepmc`, do - o2-sim -g hepmc --configKeyValues "HepMC.fileName=events.hepmc" ... - + o2-sim -g hepmc --configKeyValues "HepMC.fileName=events.hepmc" ... + See also [`read.sh`](read.sh). ## Reading HepMC events from child process @@ -51,8 +51,8 @@ example, `crmc` will write a lot of information to standard output. We can filter that out via a shell script ([`crmc.sh`](crmc.sh)) like #!/bin/sh - crmc $@ -o hepmc3 -f /dev/stdout | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' - + crmc $@ -o hepmc3 -f /dev/stdout | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' + The `sed` command selects lines that begin with `HepMC::`, or one of single characters `E` (event), `A` (attribute), `U` (units), `W` (weight), `V` (vertex), or `P` (particle) followed by a space. This @@ -65,8 +65,8 @@ the CRMC suite. For example, if we want to simulate p-Pb collisions using DpmJET, we can do o2-sim -g hepmc --configKeyValues "HepMC.progCmd=crmc.sh -m 12 -i2212 -I 1002080820" - - + + ### Implementation details Internally `GeneratorHepMC` From 67e5ba934c990fb1b7b473a408258bf406f380a7 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 14:54:17 +0200 Subject: [PATCH 22/37] Fix formatting --- run/SimExamples/HepMC/child.sh | 46 ++++++++++++++++------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/run/SimExamples/HepMC/child.sh b/run/SimExamples/HepMC/child.sh index f1e49b6f7c3a2..f55c168bd1956 100755 --- a/run/SimExamples/HepMC/child.sh +++ b/run/SimExamples/HepMC/child.sh @@ -7,36 +7,36 @@ out= usage() { - cat <<-EOF - Usage: $0 [OPTIONS] + cat </dev/stderr - exit 1 - ;; + -c|--cmdline) cmd="$2" ; shift ;; + -s|--seed) seed=$2 ; shift ;; + -n|--nevents) nev=$2 ; shift ;; + -o|--output) out=$2 ; shift ;; + -h|--help) usage; o2-sim --help full ; exit 0 ;; + --) shift ; break ;; + *) echo "Unknown option '$1', did you forget '--'?" >/dev/stderr + exit 1 + ;; esac shift done @@ -46,8 +46,6 @@ if test "x$out" = "x" ; then fi out=`echo "$out" | tr ' ' '_'` -export VMCWORKDIR=${O2_ROOT}/share +export VMCWORKDIR=${O2_ROOT}/share o2-sim -g hepmc --configKeyValues "HepMC.progCmd=$cmd" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ - - From 101de152ac25a128f3dc5610098d5f05995e9aed Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 15:03:43 +0200 Subject: [PATCH 23/37] Fix formatting - that checker is ridiculously pedantic about things and makes life so much more difficult than it needs to be for very little gain --- run/SimExamples/HepMC/README.md | 11 +++++---- run/SimExamples/HepMC/read.sh | 42 ++++++++++++++++----------------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/run/SimExamples/HepMC/README.md b/run/SimExamples/HepMC/README.md index 54adcd31c990b..fec93402e9ea2 100644 --- a/run/SimExamples/HepMC/README.md +++ b/run/SimExamples/HepMC/README.md @@ -22,8 +22,9 @@ Please refer to the documentation of these for more on how to make event files in the HepMC format. To make a simulation reading from the file `events.hepmc`, do + o2-sim -g hepmc --configKeyValues "HepMC.fileName=events.hepmc" ... - + See also [`read.sh`](read.sh). ## Reading HepMC events from child process @@ -35,7 +36,7 @@ EG by o2-sim -g hepmc --configKeyValues "HepMC.progCmd=eg" -See also [`child.sh`](child.sh). +See also [`child.sh`](child.sh). There are some requirements on the program `eg`: @@ -52,7 +53,7 @@ We can filter that out via a shell script ([`crmc.sh`](crmc.sh)) like #!/bin/sh crmc $@ -o hepmc3 -f /dev/stdout | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' - + The `sed` command selects lines that begin with `HepMC::`, or one of single characters `E` (event), `A` (attribute), `U` (units), `W` (weight), `V` (vertex), or `P` (particle) followed by a space. This @@ -65,8 +66,8 @@ the CRMC suite. For example, if we want to simulate p-Pb collisions using DpmJET, we can do o2-sim -g hepmc --configKeyValues "HepMC.progCmd=crmc.sh -m 12 -i2212 -I 1002080820" - - + + ### Implementation details Internally `GeneratorHepMC` diff --git a/run/SimExamples/HepMC/read.sh b/run/SimExamples/HepMC/read.sh index 45779529455d0..fdd511820b81b 100755 --- a/run/SimExamples/HepMC/read.sh +++ b/run/SimExamples/HepMC/read.sh @@ -7,33 +7,33 @@ out= usage() { - cat <<-EOF - Usage: $0 [OPTIONS] + cat </dev/stderr - exit 1 - ;; + -i|--input) inp=$2 ; shift ;; + -s|--seed) seed=$2 ; shift ;; + -n|--nevents) nev=$2 ; shift ;; + -o|--output) out=$2 ; shift ;; + -h|--help) usage; o2-sim --help full ; exit 0 ;; + --) shift ; break ;; + *) echo "Unknown option '$1', did you forget '--'?" >/dev/stderr + exit 1 + ;; esac shift done @@ -43,8 +43,6 @@ if test "x$out" = "x" ; then fi out=`echo "$out" | tr ' ' '_'` -export VMCWORKDIR=${O2_ROOT}/share +export VMCWORKDIR=${O2_ROOT}/share o2-sim -g hepmc --configKeyValues "HepMC.fileName=$inp" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ - - From f27aaf8f0b149a8f5d6c15538c350fff815f2dbb Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 15:05:58 +0200 Subject: [PATCH 24/37] Fix formatting --- run/SimExamples/HepMC/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/run/SimExamples/HepMC/README.md b/run/SimExamples/HepMC/README.md index 54adcd31c990b..fec93402e9ea2 100644 --- a/run/SimExamples/HepMC/README.md +++ b/run/SimExamples/HepMC/README.md @@ -22,8 +22,9 @@ Please refer to the documentation of these for more on how to make event files in the HepMC format. To make a simulation reading from the file `events.hepmc`, do + o2-sim -g hepmc --configKeyValues "HepMC.fileName=events.hepmc" ... - + See also [`read.sh`](read.sh). ## Reading HepMC events from child process @@ -35,7 +36,7 @@ EG by o2-sim -g hepmc --configKeyValues "HepMC.progCmd=eg" -See also [`child.sh`](child.sh). +See also [`child.sh`](child.sh). There are some requirements on the program `eg`: @@ -52,7 +53,7 @@ We can filter that out via a shell script ([`crmc.sh`](crmc.sh)) like #!/bin/sh crmc $@ -o hepmc3 -f /dev/stdout | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' - + The `sed` command selects lines that begin with `HepMC::`, or one of single characters `E` (event), `A` (attribute), `U` (units), `W` (weight), `V` (vertex), or `P` (particle) followed by a space. This @@ -65,8 +66,8 @@ the CRMC suite. For example, if we want to simulate p-Pb collisions using DpmJET, we can do o2-sim -g hepmc --configKeyValues "HepMC.progCmd=crmc.sh -m 12 -i2212 -I 1002080820" - - + + ### Implementation details Internally `GeneratorHepMC` From 5b62d47fbb669b70a78a628d82173c332a3e9da7 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 15:12:48 +0200 Subject: [PATCH 25/37] Fix formatting - that checker is ridiculously pedantic about things and makes life so much more difficult than it needs to be for very little gain --- run/SimExamples/HepMC/read.sh | 42 ++--- run/SimExamples/TParticle/README.md | 240 ++++++++++++++-------------- run/SimExamples/TParticle/child.sh | 49 +++--- run/SimExamples/TParticle/myeg.sh | 27 +++- run/SimExamples/TParticle/read.sh | 46 +++--- 5 files changed, 209 insertions(+), 195 deletions(-) diff --git a/run/SimExamples/HepMC/read.sh b/run/SimExamples/HepMC/read.sh index 45779529455d0..485916634cafa 100755 --- a/run/SimExamples/HepMC/read.sh +++ b/run/SimExamples/HepMC/read.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/bash inp=events.hepmc seed=$RANDOM @@ -7,33 +7,33 @@ out= usage() { - cat <<-EOF - Usage: $0 [OPTIONS] + cat </dev/stderr - exit 1 - ;; + -i|--input) inp=$2 ; shift ;; + -s|--seed) seed=$2 ; shift ;; + -n|--nevents) nev=$2 ; shift ;; + -o|--output) out=$2 ; shift ;; + -h|--help) usage; o2-sim --help full ; exit 0 ;; + --) shift ; break ;; + *) echo "Unknown option '$1', did you forget '--'?" >/dev/stderr + exit 1 + ;; esac shift done @@ -43,7 +43,7 @@ if test "x$out" = "x" ; then fi out=`echo "$out" | tr ' ' '_'` -export VMCWORKDIR=${O2_ROOT}/share +export VMCWORKDIR=${O2_ROOT}/share o2-sim -g hepmc --configKeyValues "HepMC.fileName=$inp" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ diff --git a/run/SimExamples/TParticle/README.md b/run/SimExamples/TParticle/README.md index 66d9b63a9e951..b07080d51f044 100644 --- a/run/SimExamples/TParticle/README.md +++ b/run/SimExamples/TParticle/README.md @@ -3,44 +3,44 @@ /doxy --> Here are pointers on how to use `GeneratorTParticle` selected by the -option `-g tparticle` for `o2-sim`. +option `-g tparticle` for `o2-sim`. -## Reading TParticle files +## Reading TParticle files The generator `GeneratorTParticle` can read events from a ROOT file containing a `TTree` with a branch holding a `TClonesArray` of `TParticle` objects. These files can be produced by a standalone event generator program (EG). -To make a simulation reading from the file `particles.root`, do +To make a simulation reading from the file `particles.root`, do - o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=particles.root" ... - -See also [`read.sh`](read.sh). Do + o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=particles.root" ... + +See also [`read.sh`](read.sh). Do + + ./read.sh --help - ./read.sh --help - for a list of options. This expects an input file with a `TTree` with a single `TBranch` holding a `TClonesArray` of `TParticle` -objects. One such example file can be made with [`myeg.sh`]. Do +objects. One such example file can be made with [`myeg.sh`]. Do - ./myeg.sh --help - -for a list of options. + ./myeg.sh --help + +for a list of options. -### Configurations +### Configurations - The name of the `TTree` to read can be set by the configuration key - `GeneratorTParticle.treeName`. The default is `T` + `GeneratorTParticle.treeName`. The default is `T` - The name of the `TBranch` holding the `TClonesArray` of `TParticle` objects can be set by the configuration key - `GeneratorTParticle.branchName`. The default is `Particles` - -For example + `GeneratorTParticle.branchName`. The default is `Particles` - o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=particles.root;GeneratorTParticle.treeName=Events;GeneratorTParticle.branchName=Tracks" ... +For example -## Reading TParticle events from child process + o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=particles.root;GeneratorTParticle.treeName=Events;GeneratorTParticle.branchName=Tracks" ... + +## Reading TParticle events from child process `GeneratorTParticle` can not only read events from a file, but can also spawn an child EG to produce events. Suppose we have a program @@ -48,190 +48,190 @@ named `eg` which is some EG that writes `TParticle` event records to a file . Then we can execute a simulation using this external EG by - o2-sim -g tgenerator --configKeyValues "GeneratorTParticle.progCmd=eg" + o2-sim -g tgenerator --configKeyValues "GeneratorTParticle.progCmd=eg" + +See also [`child.sh`](child.sh). Do -See also [`child.sh`](child.sh). Do + ./child.sh --help - ./child.sh --help - for a list of options. -There are some requirements on the program `eg`: +There are some requirements on the program `eg`: - It _must_ accept the option `-n n-events` to set the number of - events to produce to `n-events`. + events to produce to `n-events`. - It _must_ accept the option `-o output` to set the output file name. If a program does not adhere to these requirements, it will often be simple enough to make a small wrapper script that enforce this. -### Configurations +### Configurations -Same as above. +Same as above. -### Example EG +### Example EG The child-process feature allows us to use almost any EG for which we have a `TGenerator` interface without compiling it in to O2. Suppose -we have defined the class `MyGenerator` to produce events. +we have defined the class `MyGenerator` to produce events. class MyGenerator : public TGenerator { public: MyGenerator(); void Initialize(Long_t projectile, - Long_t target, - Double_t sqrts); + Long_t target, + Double_t sqrts); void GenerateEvent(); Int_t ImportParticles(TClonesArray* particles,Option_t*option=""); }; -and a steering class - - struct MySteer { - TGenerator* generator; - TFile* file; - TTree* tree; - TClonesArray* particle; - Int_t flushEvery; - MySteer(TGenerator* generator, - const TString& output, - Int_t flushEvery) - : generator(generator) - file(TFile::Open(output,"RECREATE")), - tree("T","Particle tree"), - particles(new TClonesArray("TParticle")), - flushEvery(flushEvery) - { - tree->SetDirectory(file); - tree->Branch("Particles",&particles); +and a steering class + + struct MySteer { + TGenerator* generator; + TFile* file; + TTree* tree; + TClonesArray* particle; + Int_t flushEvery; + MySteer(TGenerator* generator, + const TString& output, + Int_t flushEvery) + : generator(generator) + file(TFile::Open(output,"RECREATE")), + tree("T","Particle tree"), + particles(new TClonesArray("TParticle")), + flushEvery(flushEvery) + { + tree->SetDirectory(file); + tree->Branch("Particles",&particles); + } + ~MySteer() { close(); } + void event() { + particles->Clear(); + generator->GenerateEvent(); + generator->ImportParticles(particles); + tree->Fill(); + } + void sync() { + tree->AutoSave("SaveSelf FlushBaskets Overwrite"); } - ~MySteer() { close(); } - void event() { - particles->Clear(); - generator->GenerateEvent(); - generator->ImportParticles(particles); - tree->Fill(); - } - void sync() { - tree->AutoSave("SaveSelf FlushBaskets Overwrite"); - } - void run(Int_t nev) { - for (Int_t iev = 0; iev < nev; iev++) { - event(); - if (flushEvery > 0 and (iev % flushEvery == 0) and iev != 0) - sync(); - } - } - void close() { - if (not file) return; - file->Write(); - file->Close(); - file = nullptr; - } - }; - + void run(Int_t nev) { + for (Int_t iev = 0; iev < nev; iev++) { + event(); + if (flushEvery > 0 and (iev % flushEvery == 0) and iev != 0) + sync(); + } + } + void close() { + if (not file) return; + file->Write(); + file->Close(); + file = nullptr; + } + }; + Then we could make the script [`MyEG.macro` (complete code)](MyEG.macro) like void MyEG(Int_t nev,const TString& out,Int_t every=1) { MyGenerator* eg = new MyGenerator(); eg->Initialize(2212, 2212, 5200); - - MySteer steer(eg, out, every); - steer.run(nev); + + MySteer steer(eg, out, every); + steer.run(nev); } - + and a simple shell-script [`myeg.sh`](myeg.sh) to pass arguments to the `MyEG.macro` script #!/bin/sh - + nev=1 out=particles.root - + while test $# -gt 0 ; do case $1 in - -n) nev=$2 ; shift ;; - -o) out=$2 ; shift ;; - *) ;; + -n) nev=$2 ; shift ;; + -o) out=$2 ; shift ;; + *) ;; esac shift done - + root -l MyEG.macro -- $nev \"$out\" -We can then do +We can then do - o2-sim -g tgenerator --configKeyValues "GeneratorTParticle.progCmd=./myeg.sh" + o2-sim -g tgenerator --configKeyValues "GeneratorTParticle.progCmd=./myeg.sh" -to produce events with our generator `MyGenerator`. +to produce events with our generator `MyGenerator`. - -### Implementation details -Internally `GeneratorTParticle` +### Implementation details + +Internally `GeneratorTParticle` 1. creates a unique temporary file name in the working directory, -2. builds a command line, e.g., +2. builds a command line, e.g., + + eg options -o temporary-name & - eg options -o temporary-name & - -3. and executes that command line +3. and executes that command line -## The future +## The future The `GeneratorTParticle` (and sister generator `GeneratorHepMC`) will in the not so distant future be upgraded with new functionality to more easily customise reading files and executing a child process. In particular -- New options that can be specified in `--configKeyValues` +- New options that can be specified in `--configKeyValues` - `GeneratorTParticle.treeName=name` the name of the `TTree` in the - input files. - + input files. + - `GeneratorTParticle.branchName=name` the name of the `TBranch` in the `TTree` that holds the `TClonesArray` of `TParticle` objects. - + - `FileOrCmd.fileNames=list` a comma separated list of HepMC files - to read - + to read + - `FileOrCmd.cmd=command line` a command line to execute as a background child process. If this is set (not the empty string), - then `FileOrCmd.fileNames` is ignored. - + then `FileOrCmd.fileNames` is ignored. + - A number of keys that specifies the command line option switch that the child program accepts for certain things. If any of these are set to the empty string, then that switch and - corresponding option value is not passed to the child program. - + corresponding option value is not passed to the child program. + - `FileOrCmd.outputSwitch=switch` (default `>`) to specify output file. The default of `>` assumes that the program write HepMC - events, and _only_ those, to standard output. - + events, and _only_ those, to standard output. + - `FileOrCmd.seedSwitch=switch` (default `-s`) to specify the random number generator seed. The value passed is selected by - the `o2-sim` option `--seed` - + the `o2-sim` option `--seed` + - `FileOrCmd.bMaxSwitch=switch` (default `-b`) to specify the upper limit on the impact parameters sampled. The value passed - is selected by the `o2-sim` option `--bMax` - + is selected by the `o2-sim` option `--bMax` + - `FileOrCmd.nEventsSwitch=switch` (default `-n`) to specify the number of events to generate. The value passed is selected by the `o2-sim` option `--nEvents` or (`-n`) - + - `FileOrCmd.backgroundSwitch=switch` (default `&`) to specify how the program is put in the background. Typically this should be `&`, but a program may itself fork to the background. -- Some options are no longer available +- Some options are no longer available - `GeneratorTParticle.fileName` - use `FileOrCmd.fileNames` - - `GeneratorTParticle.progCmd` - use `FileOrCmd.cmd` - -The command line build will now be + - `GeneratorTParticle.progCmd` - use `FileOrCmd.cmd` + +The command line build will now be > _commandLine_ _nEventsSwitch_ _nEvents_ _seedSwitch_ _seed_ > _bMaxSwitch_ _bMax_ _outputSwitch_ _output_ _backgroundSwitch_ @@ -244,15 +244,15 @@ example, if _bMaxSwitch_ is empty, then the build command line will be > _outputSwitch_ _output_ _backgroundSwitch_ -### Header information +### Header information The class `GeneratorTParticle` will take a key parameter, say `headerName` which will indicate a branch that contains header information. Under that branch, the class will then search for leaves (`TLeaf`) that correspond to standard header information keys (see o2::dataformats::MCInfoKeys). If any of those leaves are present, -then the corresponding keys will be set on the generated event header. +then the corresponding keys will be set on the generated event header. Thus, as long as the generator observes the convention used, we can also import auxiliary information (impact parameter, Npart, ...) from -the input files in addition to the particle information. +the input files in addition to the particle information. diff --git a/run/SimExamples/TParticle/child.sh b/run/SimExamples/TParticle/child.sh index 1a4807b72a4c5..802ebe4a3689a 100755 --- a/run/SimExamples/TParticle/child.sh +++ b/run/SimExamples/TParticle/child.sh @@ -8,38 +8,38 @@ opt= usage() { - cat <<-EOF - Usage: $0 [OPTIONS] + cat </dev/stderr - exit 1 - ;; + -c|--cmdline) cmd="$2" ; shift ;; + -s|--seed) seed=$2 ; shift ;; + -n|--nevents) nev=$2 ; shift ;; + -o|--output) out=$2 ; shift ;; + -+|--compile) opt=" -+";; + -h|--help) usage; o2-sim --help full ; exit 0 ;; + --) shift ; break ;; + *) echo "Unknown option '$1', did you forget '--'?" >/dev/stderr + exit 1 + ;; esac shift done @@ -52,8 +52,7 @@ out=`echo "$out" | tr ' ' '_'` keys="Generator.progCmd=$cmd $opt" # keys="FileOrCmd.cmd=$cmd $opt;FileOrCmd.outputSwitch=-o" set -x -export VMCWORKDIR=${O2_ROOT}/share +export VMCWORKDIR=${O2_ROOT}/share o2-sim -g tparticle --configKeyValues "$keys" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ - diff --git a/run/SimExamples/TParticle/myeg.sh b/run/SimExamples/TParticle/myeg.sh index 28dddc4196e31..4e76c8a8a02d8 100755 --- a/run/SimExamples/TParticle/myeg.sh +++ b/run/SimExamples/TParticle/myeg.sh @@ -6,14 +6,29 @@ out=particles.root seed=0 opt= +usage() +{ + cat </dev/stderr - exit 1 - ;; + -i|--input) inp=$2 ; shift ;; + -s|--seed) seed=$2 ; shift ;; + -n|--nevents) nev=$2 ; shift ;; + -o|--output) out=$2 ; shift ;; + -h|--help) usage; o2-sim --help full ; exit 0 ;; + --) shift ; break ;; + *) echo "Unknown option '$1', did you forget '--'?" >/dev/stderr + exit 1 + ;; esac shift done @@ -50,7 +50,7 @@ out=`echo "$out" | tr ' ' '_'` set +e # Future FileOrCmd.fileNames=${inp} -export VMCWORKDIR=${O2_ROOT}/share +export VMCWORKDIR=${O2_ROOT}/share o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=${inp}" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ From 43ea6d441cd7e209431dc1a88c573927d2a2cfa5 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 15:18:20 +0200 Subject: [PATCH 26/37] Stupid annoying formatting checker - it is really f**cking ridiculous that it is so pedantic that you cannot have two blank lines at the end of a simple shell script - this is studpid and _very_ counter productive. Please please _please_ change the policy on this --- run/CMakeLists.txt | 8 ++++++++ run/SimExamples/HepMC/child.sh | 2 +- run/SimExamples/HepMC/read.sh | 1 - 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt index 07f23328230dd..90248c9b8da93 100644 --- a/run/CMakeLists.txt +++ b/run/CMakeLists.txt @@ -121,6 +121,14 @@ o2_add_executable(mctracks-to-aod SOURCES o2sim_mctracks_to_aod.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::SimulationDataFormat) +o2_add_executable(mc-to-hepmc + COMPONENT_NAME aod + SOURCES o2aod_mc_to_hepmc.cxx + PUBLIC_LINK_LIBRARIES + O2::Framework + O2::SimulationDataFormat + O2::Generators) + o2_add_dpl_workflow(mctracks-to-aod-simple-task SOURCES SimExamples/McTracksToAOD/mctracks_to_aod_simple_task.cxx PUBLIC_LINK_LIBRARIES O2::Framework diff --git a/run/SimExamples/HepMC/child.sh b/run/SimExamples/HepMC/child.sh index f55c168bd1956..3a4f9ba3e40c7 100755 --- a/run/SimExamples/HepMC/child.sh +++ b/run/SimExamples/HepMC/child.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/bash cmd="./crmc.sh" seed=$RANDOM diff --git a/run/SimExamples/HepMC/read.sh b/run/SimExamples/HepMC/read.sh index 485916634cafa..6cd7b8f30c436 100755 --- a/run/SimExamples/HepMC/read.sh +++ b/run/SimExamples/HepMC/read.sh @@ -46,5 +46,4 @@ out=`echo "$out" | tr ' ' '_'` export VMCWORKDIR=${O2_ROOT}/share o2-sim -g hepmc --configKeyValues "HepMC.fileName=$inp" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ - From 73c7490c8ddb74d20e8e81b141fd4c118f2c0018 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 15:27:34 +0200 Subject: [PATCH 27/37] Undo last faulty commit and fix formatting This is exactly what happens when you make the stupid arse, over zealous code checkers. I get frustrated and out of sheer oversight, commit some stuff that shouldn't be committed and then I have to go back and fixt it again. That is so annoying, counter-productive, and down right silly. This could all be avoided if the code checker did _reasonable_ checks. Who cares if there's an extra blank line in a shell script, or other such annoying things. In fact, if it is so important, then git hooks that _automatically_ fixes these issues should be enstated instead of relying on the developers to do this f**ked up things over and over again. Please, please, _please_ fix this. --- run/CMakeLists.txt | 8 -------- run/SimExamples/HepMC/read.sh | 1 - 2 files changed, 9 deletions(-) diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt index 90248c9b8da93..07f23328230dd 100644 --- a/run/CMakeLists.txt +++ b/run/CMakeLists.txt @@ -121,14 +121,6 @@ o2_add_executable(mctracks-to-aod SOURCES o2sim_mctracks_to_aod.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::SimulationDataFormat) -o2_add_executable(mc-to-hepmc - COMPONENT_NAME aod - SOURCES o2aod_mc_to_hepmc.cxx - PUBLIC_LINK_LIBRARIES - O2::Framework - O2::SimulationDataFormat - O2::Generators) - o2_add_dpl_workflow(mctracks-to-aod-simple-task SOURCES SimExamples/McTracksToAOD/mctracks_to_aod_simple_task.cxx PUBLIC_LINK_LIBRARIES O2::Framework diff --git a/run/SimExamples/HepMC/read.sh b/run/SimExamples/HepMC/read.sh index 6cd7b8f30c436..96f0415fa13ac 100755 --- a/run/SimExamples/HepMC/read.sh +++ b/run/SimExamples/HepMC/read.sh @@ -46,4 +46,3 @@ out=`echo "$out" | tr ' ' '_'` export VMCWORKDIR=${O2_ROOT}/share o2-sim -g hepmc --configKeyValues "HepMC.fileName=$inp" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ - From 4040aaf0a2094f8f1e73491cd006aabdfa02a646 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 15:42:01 +0200 Subject: [PATCH 28/37] Fix whitespace - these changes is so messed up --- Generators/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 2af6914196e66..f8551a9e5e8ba 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -29,8 +29,8 @@ o2_add_library(Generators src/GeneratorExternalParam.cxx src/GeneratorFromFile.cxx src/GeneratorFromO2KineParam.cxx - src/GeneratorFileOrCmd.cxx - src/GeneratorFileOrCmdParam.cxx + src/GeneratorFileOrCmd.cxx + src/GeneratorFileOrCmdParam.cxx src/PrimaryGenerator.cxx src/PrimaryGeneratorParam.cxx src/TriggerExternalParam.cxx From 9e90dd584fa813acf954bea13add18e98eb88fb1 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 17:35:43 +0200 Subject: [PATCH 29/37] Update run/SimExamples/HepMC/child.sh Co-authored-by: Giulio Eulisse <10544+ktf@users.noreply.github.com> --- run/SimExamples/HepMC/child.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run/SimExamples/HepMC/child.sh b/run/SimExamples/HepMC/child.sh index 3a4f9ba3e40c7..38461786266d2 100755 --- a/run/SimExamples/HepMC/child.sh +++ b/run/SimExamples/HepMC/child.sh @@ -1,4 +1,4 @@ -#!/usr/bin/bash +#!/usr/bin/env bash cmd="./crmc.sh" seed=$RANDOM From fba7f8c01aa8a36e6a190a5fa6dbbbb671fdce36 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:57:22 +0200 Subject: [PATCH 30/37] Update Generators/src/GeneratorFileOrCmd.cxx --- Generators/src/GeneratorFileOrCmd.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/Generators/src/GeneratorFileOrCmd.cxx b/Generators/src/GeneratorFileOrCmd.cxx index 9f879435705f3..53071ffa94efe 100644 --- a/Generators/src/GeneratorFileOrCmd.cxx +++ b/Generators/src/GeneratorFileOrCmd.cxx @@ -9,7 +9,6 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \author R+Preghenella - August 2017 #include "SimulationDataFormat/MCUtils.h" #include "Generators/GeneratorFileOrCmd.h" From 634f5f96627635252ffe46a738aec46f43b46445 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Mon, 9 Oct 2023 14:00:46 +0200 Subject: [PATCH 31/37] Fix test case and other similar fixes - The test case `o2sim-hepmc` fixed to use proper config key - `GeneratorHepMC` will give error if old config key used - `GeneratorHepMC` will give warning if version key is set - the code deduces the version on its own now. - Added superflous `{...}` around single statement `if`, `while`, ... - boy those checks are silly and counter productive. --- .../include/Generators/GeneratorHepMCParam.h | 3 +- Generators/src/GeneratorFileOrCmd.cxx | 22 +++-- Generators/src/GeneratorHepMC.cxx | 90 ++++++++++++------- Generators/src/GeneratorTParticle.cxx | 24 +++-- run/CMakeLists.txt | 2 +- 5 files changed, 92 insertions(+), 49 deletions(-) diff --git a/Generators/include/Generators/GeneratorHepMCParam.h b/Generators/include/Generators/GeneratorHepMCParam.h index a3fc9ea81930a..5df4013489f95 100644 --- a/Generators/include/Generators/GeneratorHepMCParam.h +++ b/Generators/include/Generators/GeneratorHepMCParam.h @@ -30,8 +30,9 @@ namespace eventgen **/ struct GeneratorHepMCParam : public o2::conf::ConfigurableParamHelper { - int version = 3; + int version = 0; uint64_t eventsToSkip = 0; + std::string fileName = ""; O2ParamDef(GeneratorHepMCParam, "HepMC"); }; diff --git a/Generators/src/GeneratorFileOrCmd.cxx b/Generators/src/GeneratorFileOrCmd.cxx index 53071ffa94efe..9ff45bcd9c867 100644 --- a/Generators/src/GeneratorFileOrCmd.cxx +++ b/Generators/src/GeneratorFileOrCmd.cxx @@ -9,6 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// @author Christian Holm Christensen #include "SimulationDataFormat/MCUtils.h" #include "Generators/GeneratorFileOrCmd.h" @@ -30,8 +31,9 @@ namespace std::string ltrim(const std::string& s, const std::string& what = "\" ' ") { auto start = s.find_first_not_of(what); - if (start == std::string::npos) + if (start == std::string::npos) { return ""; + } return s.substr(start); } @@ -72,8 +74,9 @@ void GeneratorFileOrCmd::setFileNames(const std::string& filenames) { std::stringstream s(filenames); std::string f; - while (std::getline(s, f, ',')) + while (std::getline(s, f, ',')) { mFileNames.push_back(f); + } } // ----------------------------------------------------------------- std::string GeneratorFileOrCmd::makeCmdLine() const @@ -81,12 +84,15 @@ std::string GeneratorFileOrCmd::makeCmdLine() const std::string fileName = mFileNames.front(); std::stringstream s; s << mCmd << " "; - if (not mSeedSwitch.empty() and mSeedSwitch != "none") + if (not mSeedSwitch.empty() and mSeedSwitch != "none") { s << mSeedSwitch << " " << mSeed << " "; - if (not mNEventsSwitch.empty() and mNEventsSwitch != "none") + } + if (not mNEventsSwitch.empty() and mNEventsSwitch != "none") { s << mNEventsSwitch << " " << mNEvents << " "; - if (not mBmaxSwitch.empty() and mBmax >= 0 and mBmaxSwitch != "none") + } + if (not mBmaxSwitch.empty() and mBmax >= 0 and mBmaxSwitch != "none") { s << mBmaxSwitch.c_str() << " " << mBmax << " "; + } s << mOutputSwitch << " " << fileName << " " << mBackgroundSwitch; @@ -189,13 +195,15 @@ void GeneratorFileOrCmd::waitForData(const std::string& filename) const LOG(debug) << "Waiting for data on " << p; // Wait until child process creates the file - while (not std::filesystem::exists(p)) + while (not std::filesystem::exists(p)) { std::this_thread::sleep_for(mWait * 1ms); + } // Wait until we have more data in the file than just the file // header - while (std::filesystem::file_size(p) <= 256) + while (std::filesystem::file_size(p) <= 256) { std::this_thread::sleep_for(mWait * 1ms); + } // Give the child process 1 second to post the data to the file LOG(debug) << "Got data in " << p << ", sleeping for a while"; diff --git a/Generators/src/GeneratorHepMC.cxx b/Generators/src/GeneratorHepMC.cxx index 89bb4d09bfe33..e02b84436f5b6 100644 --- a/Generators/src/GeneratorHepMC.cxx +++ b/Generators/src/GeneratorHepMC.cxx @@ -59,10 +59,12 @@ GeneratorHepMC::~GeneratorHepMC() { /** default destructor **/ LOG(info) << "Destructing GeneratorHepMC"; - if (mReader) + if (mReader) { mReader->close(); - if (mEvent) + } + if (mEvent) { delete mEvent; + } removeTemp(); } @@ -71,12 +73,18 @@ void GeneratorHepMC::setup(const GeneratorFileOrCmdParam& param0, const GeneratorHepMCParam& param, const conf::SimConfig& config) { + if (not param.fileName.empty()) { + LOG(fatal) << "The use of the key \"HepMC.fileName\" is " + << "no longer supported, use \"FileOrCmd.fileNames\" instead"; + } + if (param.version != 0) + LOG(warn) << "The key \"HepMC.version\" is no longer used. The " + << "version of the input files are automatically deduced."; GeneratorFileOrCmd::setup(param0, config); setEventsToSkip(param.eventsToSkip); } /*****************************************************************/ - Bool_t GeneratorHepMC::generateEvent() { LOG(debug) << "Generating an event"; @@ -84,8 +92,9 @@ Bool_t GeneratorHepMC::generateEvent() int tries = 0; do { LOG(debug) << " try # " << ++tries; - if (not mReader and not makeReader()) + if (not mReader and not makeReader()) { return false; + } /** clear and read event **/ mEvent->clear(); @@ -153,34 +162,47 @@ Bool_t GeneratorHepMC::importParticles() namespace { +template +bool putAttributeInfoImpl(o2::dataformats::MCEventHeader* eventHeader, + const std::string& name, + const std::shared_ptr& a) +{ + if (auto* p = dynamic_cast(a.get())) { + eventHeader->putInfo(name, p->value()); + return true; + } + return false; +} + void putAttributeInfo(o2::dataformats::MCEventHeader* eventHeader, const std::string& name, const std::shared_ptr& a) { - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); - if (auto* p = dynamic_cast(a.get())) - eventHeader->putInfo(name, p->value()); + using IntAttribute=HepMC3::IntAttribute; + using LongAttribute=HepMC3::LongAttribute; + using FloatAttribute=HepMC3::FloatAttribute; + using DoubleAttribute=HepMC3::DoubleAttribute; + using StringAttribute=HepMC3::StringAttribute; + using CharAttribute=HepMC3::CharAttribute; + using LongLongAttribute=HepMC3::LongLongAttribute; + using LongDoubleAttribute=HepMC3::LongDoubleAttribute; + using UIntAttribute=HepMC3::UIntAttribute; + using ULongAttribute=HepMC3::ULongAttribute; + using ULongLongAttribute=HepMC3::ULongLongAttribute; + using BoolAttribute=HepMC3::BoolAttribute; + + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; + if (putAttributeInfoImpl(eventHeader, name, a)) return; } } // namespace @@ -264,8 +286,9 @@ void GeneratorHepMC::updateHeader(o2::dataformats::MCEventHeader* eventHeader) std::string name = na.first; if (name == "GenPdfInfo" || name == "GenCrossSection" || - name == "GenHeavyIon") + name == "GenHeavyIon") { continue; + } for (auto ia : na.second) { int no = ia.first; @@ -354,12 +377,14 @@ Bool_t GeneratorHepMC::Init() // around the actual EG program. if (not mCmd.empty()) { // Set filename to be a temporary name - if (not makeTemp()) + if (not makeTemp()) { return false; + } // Make a fifo - if (not makeFifo()) + if (not makeFifo()) { return false; + } // Build command line, rediret stdout to our fifo and put std::string cmd = makeCmdLine(); @@ -390,8 +415,9 @@ Bool_t GeneratorHepMC::Init() // // However, here we will assume system local files. If _any_ of // the listed files do not exist, then we fail. - if (not ensureFiles()) + if (not ensureFiles()) { return false; + } } // Create reader for current (first) file diff --git a/Generators/src/GeneratorTParticle.cxx b/Generators/src/GeneratorTParticle.cxx index 5b3013cce3836..ab68f7f39b1bf 100644 --- a/Generators/src/GeneratorTParticle.cxx +++ b/Generators/src/GeneratorTParticle.cxx @@ -35,12 +35,14 @@ GeneratorTParticle::~GeneratorTParticle() { if (mChain) { TFile* file = mChain->GetCurrentFile(); - if (file) + if (file) { mChain->RecursiveRemove(file); + } delete mChain; } - if (mCmd.empty()) + if (mCmd.empty()) { return; + } removeTemp(); } @@ -53,8 +55,9 @@ Bool_t GeneratorTParticle::Init() if (not mCmd.empty()) { // Set filename to be a temporary name - if (not makeTemp()) + if (not makeTemp()) { return false; + } // Build command line, Assumes command line parameter std::string cmd = makeCmdLine(); @@ -66,8 +69,9 @@ Bool_t GeneratorTParticle::Init() return false; } } - for (auto filename : mFileNames) + for (auto filename : mFileNames) { mChain->AddFile(filename.c_str()); + } // Clear the array of file names mFileNames.clear(); @@ -90,20 +94,23 @@ Bool_t GeneratorTParticle::generateEvent() { // If this is the first entry, and we're executing a command, then // wait until the input file exists and actually contain some data. - if (mEntry == 0 and not mCmd.empty()) + if (mEntry == 0 and not mCmd.empty()) { waitForData(mTemporary); + } // Read in the next entry in the chain int read = mChain->GetEntry(mEntry); mEntry++; // If we got an error while reading, then give error message - if (read < 0) + if (read < 0) { LOG(error) << "Failed to read entry " << mEntry << " of chain"; + } // If we had an error or nothing was read back, then return false - if (read <= 0) + if (read <= 0) { return false; + } return true; } @@ -113,9 +120,10 @@ Bool_t GeneratorTParticle::importParticles() for (auto* object : *mTParticles) { TParticle* particle = static_cast(object); auto statusCode = particle->GetStatusCode(); - if (!mcgenstatus::isEncoded(statusCode)) + if (!mcgenstatus::isEncoded(statusCode)) { statusCode = mcgenstatus::MCGenStatusEncoding(statusCode, 0) .fullEncoding; + } mParticles.emplace_back(particle->GetPdgCode(), statusCode, diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt index 07f23328230dd..b0825639dda01 100644 --- a/run/CMakeLists.txt +++ b/run/CMakeLists.txt @@ -271,7 +271,7 @@ o2_add_test_command(NAME o2sim_hepmc -g hepmc --configKeyValues -"HepMC.fileName=${CMAKE_SOURCE_DIR}/Generators/share/data/pythia.hepmc;HepMC.version=2;align-geom.mDetectors=none" +"FileOrCmd.fileNames=${CMAKE_SOURCE_DIR}/Generators/share/data/pythia.hepmc;HepMC.version=2;align-geom.mDetectors=none" -o o2simhepmc LABELS long sim hepmc3 From bd03ecde27da5298cbb712b16d4fb1ed4ad7f84f Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Mon, 9 Oct 2023 14:46:42 +0200 Subject: [PATCH 32/37] Formatting fixes and bring docs into Sync --- Generators/src/GeneratorHepMC.cxx | 74 ++++++++++++------- run/SimExamples/HepMC/README.md | 110 ++++++++++++++++------------ run/SimExamples/HepMC/child.sh | 2 +- run/SimExamples/HepMC/read.sh | 4 +- run/SimExamples/TParticle/README.md | 104 ++++++++++++++------------ run/SimExamples/TParticle/child.sh | 7 +- run/SimExamples/TParticle/read.sh | 8 +- 7 files changed, 177 insertions(+), 132 deletions(-) diff --git a/Generators/src/GeneratorHepMC.cxx b/Generators/src/GeneratorHepMC.cxx index e02b84436f5b6..9107b1f770469 100644 --- a/Generators/src/GeneratorHepMC.cxx +++ b/Generators/src/GeneratorHepMC.cxx @@ -178,31 +178,55 @@ void putAttributeInfo(o2::dataformats::MCEventHeader* eventHeader, const std::string& name, const std::shared_ptr& a) { - using IntAttribute=HepMC3::IntAttribute; - using LongAttribute=HepMC3::LongAttribute; - using FloatAttribute=HepMC3::FloatAttribute; - using DoubleAttribute=HepMC3::DoubleAttribute; - using StringAttribute=HepMC3::StringAttribute; - using CharAttribute=HepMC3::CharAttribute; - using LongLongAttribute=HepMC3::LongLongAttribute; - using LongDoubleAttribute=HepMC3::LongDoubleAttribute; - using UIntAttribute=HepMC3::UIntAttribute; - using ULongAttribute=HepMC3::ULongAttribute; - using ULongLongAttribute=HepMC3::ULongLongAttribute; - using BoolAttribute=HepMC3::BoolAttribute; - - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; - if (putAttributeInfoImpl(eventHeader, name, a)) return; + using IntAttribute = HepMC3::IntAttribute; + using LongAttribute = HepMC3::LongAttribute; + using FloatAttribute = HepMC3::FloatAttribute; + using DoubleAttribute = HepMC3::DoubleAttribute; + using StringAttribute = HepMC3::StringAttribute; + using CharAttribute = HepMC3::CharAttribute; + using LongLongAttribute = HepMC3::LongLongAttribute; + using LongDoubleAttribute = HepMC3::LongDoubleAttribute; + using UIntAttribute = HepMC3::UIntAttribute; + using ULongAttribute = HepMC3::ULongAttribute; + using ULongLongAttribute = HepMC3::ULongLongAttribute; + using BoolAttribute = HepMC3::BoolAttribute; + + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } + if (putAttributeInfoImpl(eventHeader, name, a)) { + return; + } } } // namespace diff --git a/run/SimExamples/HepMC/README.md b/run/SimExamples/HepMC/README.md index fec93402e9ea2..b3c57dc937b21 100644 --- a/run/SimExamples/HepMC/README.md +++ b/run/SimExamples/HepMC/README.md @@ -5,6 +5,11 @@ Here are pointers on how to use `GeneratorHepMC` selected by the option `-g hepmc` for `o2-sim`. +HepMC event structures can be read from any file format supported by +HepMC it self (see +[here](http://hepmc.web.cern.ch/hepmc/group__IO.html) and +[here](http://hepmc.web.cern.ch/hepmc/group__factory.html). + ## Reading HepMC files The generator `GeneratorHepMC` can read events from a @@ -23,7 +28,7 @@ event files in the HepMC format. To make a simulation reading from the file `events.hepmc`, do - o2-sim -g hepmc --configKeyValues "HepMC.fileName=events.hepmc" ... + o2-sim -g hepmc --configKeyValues "FileOrCmd.fileNames=events.hepmc" ... See also [`read.sh`](read.sh). @@ -34,17 +39,34 @@ named `eg` which is some EG that writes HepMC event records to the standard output. Then we can execute a simulation using this external EG by - o2-sim -g hepmc --configKeyValues "HepMC.progCmd=eg" + o2-sim -g hepmc --configKeyValues "FileOrCmd.cmd=eg" See also [`child.sh`](child.sh). There are some requirements on the program `eg`: -- It _must_ write the HepMC event structures to standard output - (`/dev/stdout`). -- It may _not_ write other information to standard output. -- It _must_ accept the option `-n n-events` to set the number of - events to produce to `n-events`. +- The EG program _must_ be able to write the HepMC event structures to + a specified file. The option passed to the program is specified via + the key `FileOrCmd.outputSwitch`. This defaults to `>` which means + the EG program is assumed to write the HepMC event structures to + standard output, _and_ that nothing else is printed on standard + output. +- It _must_ accept an option to set the number of events to generate. + This is controlled by the configuration key + `FileOrCmd.nEventsSwitch` and defaults to `-n`. Thus, the EG + application should accept `-n 10` to mean that it should generate + `10` events, for example. +- The EG application should accept a command line switch to set the + random number generator seed. This option is specified via the + configuration key `FileOrCmd.seedSwitch` and defaults to `-s`. + Thus, the EG application must accept `-s 123456` to mean to set the + random number seed to `123456` for example. +- The EG application should accept a command line switch to set the + maximum impact parameter (in Fermi-metre) sampled. This is set via + the configuration key `FileOrCmd.bMaxSwithc` and defaults to `-b`. + Thus, the EG application should take the command line argument `-b + 10` to mean that it should only generate events with an impact + parameter between 0fm and 10fm. If a program does not adhere to these requirements, it will often be simple enough to make a small wrapper script that enforce this. For @@ -65,7 +87,7 @@ The script above also passes any additional command line options on to the CRMC suite. For example, if we want to simulate p-Pb collisions using DpmJET, we can do - o2-sim -g hepmc --configKeyValues "HepMC.progCmd=crmc.sh -m 12 -i2212 -I 1002080820" + o2-sim -g hepmc --configKeyValues "FileOrCmd.cmd=crmc.sh -m 12 -i2212 -I 1002080820" ### Implementation details @@ -81,58 +103,52 @@ Internally `GeneratorHepMC` 4. and executes that command line -## The future - -The `GeneratorHepMC` (and sister generator `GeneratorTParticle`) will -in the not so distant future be upgraded with new functionality to -more easily customise reading files and executing a child process. In -particular +## The configuration keys -- HepMC event structures can be read from any file format supported by - HepMC it self (see - [here](http://hepmc.web.cern.ch/hepmc/group__IO.html) and - [here](http://hepmc.web.cern.ch/hepmc/group__factory.html). +The `GeneratorHepMC` (and sister generator `GeneratorTParticle`) +allows customisation of the execution via configuration keys passed +via `--configKeyValues` -- New options that can be specified in `--configKeyValues` +- `HepMC.eventsToSkip=number` a number events to skip at the + beginning of each file read. - - `HepMC.eventsToSkip=number` a number events to skip at the - beginning of each file read. +- `FileOrCmd.fileNames=list` a comma separated list of HepMC files + to read. - - `FileOrCmd.fileNames=list` a comma separated list of HepMC files - to read. +- `FileOrCmd.cmd=command line` a command line to execute as a + background child process. If this is set (not the empty string), + then `FileOrCmd.fileNames` is ignored. - - `FileOrCmd.cmd=command line` a command line to execute as a - background child process. If this is set (not the empty string), - then `FileOrCmd.fileNames` is ignored. +- A number of keys that specifies the command line option switch + that the child program accepts for certain things. If any of + these are set to the empty string, then that switch and + corresponding option value is not passed to the child program. - - A number of keys that specifies the command line option switch - that the child program accepts for certain things. If any of - these are set to the empty string, then that switch and - corresponding option value is not passed to the child program. + - `FileOrCmd.outputSwitch=switch` (default `>`) to specify output + file. The default of `>` assumes that the program write HepMC + events, and _only_ those, to standard output. - - `FileOrCmd.outputSwitch=switch` (default `>`) to specify output - file. The default of `>` assumes that the program write HepMC - events, and _only_ those, to standard output. + - `FileOrCmd.seedSwitch=switch` (default `-s`) to specify the + random number generator seed. The value passed is selected by + the `o2-sim` option `--seed` - - `FileOrCmd.seedSwitch=switch` (default `-s`) to specify the - random number generator seed. The value passed is selected by - the `o2-sim` option `--seed` + - `FileOrCmd.bMaxSwitch=switch` (default `-b`) to specify the + upper limit on the impact parameters sampled. The value passed + is selected by the `o2-sim` option `--bMax` - - `FileOrCmd.bMaxSwitch=switch` (default `-b`) to specify the - upper limit on the impact parameters sampled. The value passed - is selected by the `o2-sim` option `--bMax` + - `FileOrCmd.nEventsSwitch=switch` (default `-n`) to specify the + number of events to generate. The value passed is selected by + the `o2-sim` option `--nEvents` or (`-n`) - - `FileOrCmd.nEventsSwitch=switch` (default `-n`) to specify the - number of events to generate. The value passed is selected by - the `o2-sim` option `--nEvents` or (`-n`) - - - `FileOrCmd.backgroundSwitch=switch` (default `&`) to specify how - the program is put in the background. Typically this should be - `&`, but a program may itself fork to the background. + - `FileOrCmd.backgroundSwitch=switch` (default `&`) to specify how + the program is put in the background. Typically this should be + `&`, but a program may itself fork to the background. - Some options are no longer available + - `HepMC.fileName` - use `FileOrCmd.fileNames` - - `HepMC.progCmd` - use `FileOrCmd.cmd` + - `HepMC.version` - now the code itself figures out which format + version the input file is in. The command line build will now be diff --git a/run/SimExamples/HepMC/child.sh b/run/SimExamples/HepMC/child.sh index 38461786266d2..9c7b2ec142f1c 100755 --- a/run/SimExamples/HepMC/child.sh +++ b/run/SimExamples/HepMC/child.sh @@ -47,5 +47,5 @@ fi out=`echo "$out" | tr ' ' '_'` export VMCWORKDIR=${O2_ROOT}/share -o2-sim -g hepmc --configKeyValues "HepMC.progCmd=$cmd" \ +o2-sim -g hepmc --configKeyValues "FileOrCmd.cmd=$cmd" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ diff --git a/run/SimExamples/HepMC/read.sh b/run/SimExamples/HepMC/read.sh index 96f0415fa13ac..6c0d0d2f5c95f 100755 --- a/run/SimExamples/HepMC/read.sh +++ b/run/SimExamples/HepMC/read.sh @@ -1,4 +1,4 @@ -#!/usr/bin/bash +#!/usr/bin/env bash inp=events.hepmc seed=$RANDOM @@ -44,5 +44,5 @@ fi out=`echo "$out" | tr ' ' '_'` export VMCWORKDIR=${O2_ROOT}/share -o2-sim -g hepmc --configKeyValues "HepMC.fileName=$inp" \ +o2-sim -g hepmc --configKeyValues "FileOrCmd.fileNames=$inp" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ diff --git a/run/SimExamples/TParticle/README.md b/run/SimExamples/TParticle/README.md index b07080d51f044..4dadc8ce06965 100644 --- a/run/SimExamples/TParticle/README.md +++ b/run/SimExamples/TParticle/README.md @@ -14,7 +14,7 @@ generator program (EG). To make a simulation reading from the file `particles.root`, do - o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=particles.root" ... + o2-sim -g tparticle --configKeyValues "FileOrCmd.fileNames=particles.root" ... See also [`read.sh`](read.sh). Do @@ -38,7 +38,7 @@ for a list of options. For example - o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=particles.root;GeneratorTParticle.treeName=Events;GeneratorTParticle.branchName=Tracks" ... + o2-sim -g tparticle --configKeyValues "FileOrCmd.fileNames=particles.root;GeneratorTParticle.treeName=Events;GeneratorTParticle.branchName=Tracks" ... ## Reading TParticle events from child process @@ -48,7 +48,7 @@ named `eg` which is some EG that writes `TParticle` event records to a file . Then we can execute a simulation using this external EG by - o2-sim -g tgenerator --configKeyValues "GeneratorTParticle.progCmd=eg" + o2-sim -g tgenerator --configKeyValues "FileOrCmd.cmd=eg" See also [`child.sh`](child.sh). Do @@ -58,10 +58,25 @@ for a list of options. There are some requirements on the program `eg`: -- It _must_ accept the option `-n n-events` to set the number of - events to produce to `n-events`. - -- It _must_ accept the option `-o output` to set the output file name. +- The EG program _must_ be able to write the HepMC event structures to + a specified file. The option passed to the program is specified via + the key `FileOrCmd.outputSwitch`. This defaults to `-o`. +- It _must_ accept an option to set the number of events to generate. + This is controlled by the configuration key + `FileOrCmd.nEventsSwitch` and defaults to `-n`. Thus, the EG + application should accept `-n 10` to mean that it should generate + `10` events, for example. +- The EG application should accept a command line switch to set the + random number generator seed. This option is specified via the + configuration key `FileOrCmd.seedSwitch` and defaults to `-s`. + Thus, the EG application must accept `-s 123456` to mean to set the + random number seed to `123456` for example. +- The EG application should accept a command line switch to set the + maximum impact parameter (in Fermi-metre) sampled. This is set via + the configuration key `FileOrCmd.bMaxSwithc` and defaults to `-b`. + Thus, the EG application should take the command line argument `-b + 10` to mean that it should only generate events with an impact + parameter between 0fm and 10fm. If a program does not adhere to these requirements, it will often be simple enough to make a small wrapper script that enforce this. @@ -163,7 +178,7 @@ the `MyEG.macro` script We can then do - o2-sim -g tgenerator --configKeyValues "GeneratorTParticle.progCmd=./myeg.sh" + o2-sim -g tgenerator --configKeyValues "FileOrCmd.cmd=./myeg.sh" to produce events with our generator `MyGenerator`. @@ -181,55 +196,46 @@ Internally `GeneratorTParticle` ## The future -The `GeneratorTParticle` (and sister generator `GeneratorHepMC`) will -in the not so distant future be upgraded with new functionality to -more easily customise reading files and executing a child process. In -particular - -- New options that can be specified in `--configKeyValues` - - - `GeneratorTParticle.treeName=name` the name of the `TTree` in the - input files. +The `GeneratorTParticle` (and sister generator `GeneratorHepMC`) is +configured through configuration keys set via `--configKeyValues` - - `GeneratorTParticle.branchName=name` the name of the `TBranch` in - the `TTree` that holds the `TClonesArray` of `TParticle` objects. +- `GeneratorTParticle.treeName=name` the name of the `TTree` in the + input files. - - `FileOrCmd.fileNames=list` a comma separated list of HepMC files - to read +- `GeneratorTParticle.branchName=name` the name of the `TBranch` in + the `TTree` that holds the `TClonesArray` of `TParticle` objects. - - `FileOrCmd.cmd=command line` a command line to execute as a - background child process. If this is set (not the empty string), - then `FileOrCmd.fileNames` is ignored. +- `FileOrCmd.fileNames=list` a comma separated list of HepMC files to + read - - A number of keys that specifies the command line option switch - that the child program accepts for certain things. If any of - these are set to the empty string, then that switch and - corresponding option value is not passed to the child program. +- `FileOrCmd.cmd=command line` a command line to execute as a + background child process. If this is set (not the empty string), + then `FileOrCmd.fileNames` is ignored. - - `FileOrCmd.outputSwitch=switch` (default `>`) to specify output - file. The default of `>` assumes that the program write HepMC - events, and _only_ those, to standard output. +- A number of keys that specifies the command line option switch that + the child program accepts for certain things. If any of these are + set to the empty string or special value `none`, then that switch + and corresponding option value is not passed to the child program. - - `FileOrCmd.seedSwitch=switch` (default `-s`) to specify the - random number generator seed. The value passed is selected by - the `o2-sim` option `--seed` + - `FileOrCmd.outputSwitch=switch` (default `>`) to specify output + file. The default of `>` assumes that the program write events, + and _only_ those, to standard output. - - `FileOrCmd.bMaxSwitch=switch` (default `-b`) to specify the - upper limit on the impact parameters sampled. The value passed - is selected by the `o2-sim` option `--bMax` + - `FileOrCmd.seedSwitch=switch` (default `-s`) to specify the + random number generator seed. The value passed is selected by + the `o2-sim` option `--seed`. - - `FileOrCmd.nEventsSwitch=switch` (default `-n`) to specify the - number of events to generate. The value passed is selected by - the `o2-sim` option `--nEvents` or (`-n`) + - `FileOrCmd.bMaxSwitch=switch` (default `-b`) to specify the + upper limit on the impact parameters sampled. The value passed + is selected by the `o2-sim` option `--bMax`. - - `FileOrCmd.backgroundSwitch=switch` (default `&`) to specify how - the program is put in the background. Typically this should be - `&`, but a program may itself fork to the background. + - `FileOrCmd.nEventsSwitch=switch` (default `-n`) to specify the + number of events to generate. The value passed is selected by + the `o2-sim` option `--nEvents` or (`-n`). -- Some options are no longer available - - - `GeneratorTParticle.fileName` - use `FileOrCmd.fileNames` - - `GeneratorTParticle.progCmd` - use `FileOrCmd.cmd` + - `FileOrCmd.backgroundSwitch=switch` (default `&`) to specify how + the program is put in the background. Typically this should be + `&`, but a program may itself fork to the background. The command line build will now be @@ -244,13 +250,15 @@ example, if _bMaxSwitch_ is empty, then the build command line will be > _outputSwitch_ _output_ _backgroundSwitch_ +## TODO + ### Header information The class `GeneratorTParticle` will take a key parameter, say `headerName` which will indicate a branch that contains header information. Under that branch, the class will then search for leaves (`TLeaf`) that correspond to standard header information keys (see -o2::dataformats::MCInfoKeys). If any of those leaves are present, +`o2::dataformats::MCInfoKeys`). If any of those leaves are present, then the corresponding keys will be set on the generated event header. Thus, as long as the generator observes the convention used, we can diff --git a/run/SimExamples/TParticle/child.sh b/run/SimExamples/TParticle/child.sh index 802ebe4a3689a..210459adea17c 100755 --- a/run/SimExamples/TParticle/child.sh +++ b/run/SimExamples/TParticle/child.sh @@ -1,4 +1,4 @@ -#!/usr/bin/bash +#!/usr/bin/env bash cmd="./myeg.sh" seed=$RANDOM @@ -49,10 +49,9 @@ if test "x$out" = "x" ; then fi out=`echo "$out" | tr ' ' '_'` -keys="Generator.progCmd=$cmd $opt" -# keys="FileOrCmd.cmd=$cmd $opt;FileOrCmd.outputSwitch=-o" set -x export VMCWORKDIR=${O2_ROOT}/share -o2-sim -g tparticle --configKeyValues "$keys" \ +o2-sim -g tparticle \ + --configKeyValues "FileOrCmd.cmd=$cmd $opt;FileOrCmd.outputSwitch=-o" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ diff --git a/run/SimExamples/TParticle/read.sh b/run/SimExamples/TParticle/read.sh index a9b4b8efa91b1..244865f2bfa9c 100755 --- a/run/SimExamples/TParticle/read.sh +++ b/run/SimExamples/TParticle/read.sh @@ -1,4 +1,4 @@ -#!/usr/bin/bash +#!/usr/bin/env bash inp=particles.root seed=$RANDOM @@ -47,10 +47,8 @@ if test "x$out" = "x" ; then fi out=`echo "$out" | tr ' ' '_'` -set +e - -# Future FileOrCmd.fileNames=${inp} +set -e export VMCWORKDIR=${O2_ROOT}/share -o2-sim -g tparticle --configKeyValues "GeneratorTParticle.fileName=${inp}" \ +o2-sim -g tparticle --configKeyValues "FileOrCmd.fileNames=${inp}" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ From f714d3ad2445aff1d16addfff9adf8ccfc0303ba Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Mon, 9 Oct 2023 14:50:17 +0200 Subject: [PATCH 33/37] Fixed example for new keys --- run/SimExamples/HepMC_STARlight/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run/SimExamples/HepMC_STARlight/run.sh b/run/SimExamples/HepMC_STARlight/run.sh index b75cee52b7117..e83df51000707 100755 --- a/run/SimExamples/HepMC_STARlight/run.sh +++ b/run/SimExamples/HepMC_STARlight/run.sh @@ -15,4 +15,4 @@ env -i HOME="$HOME" USER="$USER" PATH="/bin:/usr/bin:/usr/local/bin" \ # PART b) NEV=1000 o2-sim -j 20 -n ${NEV} -g hepmc -m PIPE ITS -o sim \ - --configKeyValues "HepMC.fileName=starlight.hepmc;HepMC.version=2;Diamond.position[2]=0.1;Diamond.width[2]=0.05" + --configKeyValues "FileOrCmd.fileNames=starlight.hepmc;Diamond.position[2]=0.1;Diamond.width[2]=0.05" From a8ded64391052c67205391e2ff139a74e72752ce Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Mon, 9 Oct 2023 14:59:11 +0200 Subject: [PATCH 34/37] Fix whitespace - not even my edit --- run/SimExamples/HepMC_STARlight/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run/SimExamples/HepMC_STARlight/run.sh b/run/SimExamples/HepMC_STARlight/run.sh index e83df51000707..c6fc63a8fb7b3 100755 --- a/run/SimExamples/HepMC_STARlight/run.sh +++ b/run/SimExamples/HepMC_STARlight/run.sh @@ -10,7 +10,7 @@ set -x # PART a) env -i HOME="$HOME" USER="$USER" PATH="/bin:/usr/bin:/usr/local/bin" \ - ALIBUILD_WORK_DIR="$ALIBUILD_WORK_DIR" ./run-starlight.sh + ALIBUILD_WORK_DIR="$ALIBUILD_WORK_DIR" ./run-starlight.sh # PART b) NEV=1000 From 52a953fbaa5063c4d40550708ca844dafde7d859 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Sat, 14 Oct 2023 15:01:28 +0200 Subject: [PATCH 35/37] Back-ward compatibility and Namespace change - `GeneratorHepMC` accepts the old `HepMC.fileName` configuration option (with a deprecation warning) - `HepMC.version` is honoured when spawning a child process. That is, if it is set to 2, then use compatibility reader `HepMC3::ReaderAsciiVersion2`, otherwise use the version 3 reader. If option is given with file names, then give warning that it is not used. - Configuration namespace `FileOrCmd` is renamed to `GeneratorFileOrCmd` - Documentation has been updated to reflect these changes --- .../Generators/GeneratorFileOrCmdParam.h | 2 +- .../include/Generators/GeneratorHepMC.h | 1 + Generators/src/GeneratorHepMC.cxx | 28 ++++-- run/SimExamples/HepMC/README.md | 99 ++++++++++--------- run/SimExamples/HepMC/child.sh | 4 +- run/SimExamples/HepMC/read.sh | 2 +- run/SimExamples/HepMC_STARlight/run.sh | 2 +- run/SimExamples/TParticle/README.md | 75 +++++++------- run/SimExamples/TParticle/child.sh | 2 +- run/SimExamples/TParticle/read.sh | 2 +- 10 files changed, 119 insertions(+), 98 deletions(-) diff --git a/Generators/include/Generators/GeneratorFileOrCmdParam.h b/Generators/include/Generators/GeneratorFileOrCmdParam.h index 5d9dd06cb6f6b..fe6dfa3a80722 100644 --- a/Generators/include/Generators/GeneratorFileOrCmdParam.h +++ b/Generators/include/Generators/GeneratorFileOrCmdParam.h @@ -36,7 +36,7 @@ struct GeneratorFileOrCmdParam : public o2::conf::ConfigurableParamHelper mReader; /** Event structure */ HepMC3::GenEvent* mEvent = nullptr; diff --git a/Generators/src/GeneratorHepMC.cxx b/Generators/src/GeneratorHepMC.cxx index 9107b1f770469..3fec13ae490d2 100644 --- a/Generators/src/GeneratorHepMC.cxx +++ b/Generators/src/GeneratorHepMC.cxx @@ -74,14 +74,23 @@ void GeneratorHepMC::setup(const GeneratorFileOrCmdParam& param0, const conf::SimConfig& config) { if (not param.fileName.empty()) { - LOG(fatal) << "The use of the key \"HepMC.fileName\" is " - << "no longer supported, use \"FileOrCmd.fileNames\" instead"; + LOG(warn) << "The use of the key \"HepMC.fileName\" is " + << "deprecated, use \"GeneratorFileOrCmd.fileNames\" instead"; } - if (param.version != 0) - LOG(warn) << "The key \"HepMC.version\" is no longer used. The " - << "version of the input files are automatically deduced."; + GeneratorFileOrCmd::setup(param0, config); + if (not param.fileName.empty()) { + setFileNames(param.fileName); + } + + mVersion = param.version; setEventsToSkip(param.eventsToSkip); + + if (param.version != 0 and mCmd.empty()) { + LOG(warn) << "The key \"HepMC.version\" is no longer used when " + << "reading from files. The format version of the input files " + << "are automatically deduced."; + } } /*****************************************************************/ @@ -349,9 +358,14 @@ bool GeneratorHepMC::makeReader() // For FIFO reading, we assume straight ASCII output always. // Unfortunately, the HepMC3::deduce_reader `stat`s the filename // which isn't supported on a FIFO, so we have to use the reader - // directly. + // directly. Here, we allow for version 2 formats if the user + // specifies that LOG(info) << "Creating ASCII reader of " << filename; - mReader.reset(new HepMC3::ReaderAscii(filename)); + if (mVersion == 2) { + mReader.reset(new HepMC3::ReaderAsciiHepMC2(filename)); + } else { + mReader.reset(new HepMC3::ReaderAscii(filename)); + } } else { LOG(info) << "Deduce a reader of " << filename; mReader = HepMC3::deduce_reader(filename); diff --git a/run/SimExamples/HepMC/README.md b/run/SimExamples/HepMC/README.md index b3c57dc937b21..0369ee9d90bdd 100644 --- a/run/SimExamples/HepMC/README.md +++ b/run/SimExamples/HepMC/README.md @@ -28,18 +28,19 @@ event files in the HepMC format. To make a simulation reading from the file `events.hepmc`, do - o2-sim -g hepmc --configKeyValues "FileOrCmd.fileNames=events.hepmc" ... + o2-sim -g hepmc --configKeyValues "GeneratorFileOrCmd.fileNames=events.hepmc" ... See also [`read.sh`](read.sh). ## Reading HepMC events from child process + `GeneratorHepMC` can not only read HepMC events from a file, but can also spawn an child EG to produce events. Suppose we have a program named `eg` which is some EG that writes HepMC event records to the standard output. Then we can execute a simulation using this external EG by - o2-sim -g hepmc --configKeyValues "FileOrCmd.cmd=eg" + o2-sim -g hepmc --configKeyValues "GeneratorFileOrCmd.cmd=eg" See also [`child.sh`](child.sh). @@ -47,26 +48,26 @@ There are some requirements on the program `eg`: - The EG program _must_ be able to write the HepMC event structures to a specified file. The option passed to the program is specified via - the key `FileOrCmd.outputSwitch`. This defaults to `>` which means - the EG program is assumed to write the HepMC event structures to - standard output, _and_ that nothing else is printed on standard - output. + the key `GeneratorFileOrCmd.outputSwitch`. This defaults to `>` + which means the EG program is assumed to write the HepMC event + structures to standard output, _and_ that nothing else is printed on + standard output. - It _must_ accept an option to set the number of events to generate. This is controlled by the configuration key - `FileOrCmd.nEventsSwitch` and defaults to `-n`. Thus, the EG - application should accept `-n 10` to mean that it should generate + `GeneratorFileOrCmd.nEventsSwitch` and defaults to `-n`. Thus, the + EG application should accept `-n 10` to mean that it should generate `10` events, for example. - The EG application should accept a command line switch to set the - random number generator seed. This option is specified via the - configuration key `FileOrCmd.seedSwitch` and defaults to `-s`. - Thus, the EG application must accept `-s 123456` to mean to set the - random number seed to `123456` for example. + random number generator seed. This option is specified via the + configuration key `GeneratorFileOrCmd.seedSwitch` and defaults to + `-s`. Thus, the EG application must accept `-s 123456` to mean to + set the random number seed to `123456` for example. - The EG application should accept a command line switch to set the maximum impact parameter (in Fermi-metre) sampled. This is set via - the configuration key `FileOrCmd.bMaxSwithc` and defaults to `-b`. - Thus, the EG application should take the command line argument `-b - 10` to mean that it should only generate events with an impact - parameter between 0fm and 10fm. + the configuration key `GeneratorFileOrCmd.bMaxSwithc` and defaults + to `-b`. Thus, the EG application should take the command line + argument `-b 10` to mean that it should only generate events with an + impact parameter between 0fm and 10fm. If a program does not adhere to these requirements, it will often be simple enough to make a small wrapper script that enforce this. For @@ -76,8 +77,8 @@ We can filter that out via a shell script ([`crmc.sh`](crmc.sh)) like #!/bin/sh crmc $@ -o hepmc3 -f /dev/stdout | sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' -The `sed` command selects lines that begin with `HepMC::`, or one -of single characters `E` (event), `A` (attribute), `U` (units), `W` +The `sed` command selects lines that begin with `HepMC::`, or one of +single characters `E` (event), `A` (attribute), `U` (units), `W` (weight), `V` (vertex), or `P` (particle) followed by a space. This should in most cases be enough to filter out extra stuff written on standard output. @@ -87,7 +88,7 @@ The script above also passes any additional command line options on to the CRMC suite. For example, if we want to simulate p-Pb collisions using DpmJET, we can do - o2-sim -g hepmc --configKeyValues "FileOrCmd.cmd=crmc.sh -m 12 -i2212 -I 1002080820" + o2-sim -g hepmc --configKeyValues "GeneratorFileOrCmd.cmd=crmc.sh -m 12 -i2212 -I 1002080820" ### Implementation details @@ -109,46 +110,50 @@ The `GeneratorHepMC` (and sister generator `GeneratorTParticle`) allows customisation of the execution via configuration keys passed via `--configKeyValues` -- `HepMC.eventsToSkip=number` a number events to skip at the - beginning of each file read. +- `HepMC.eventsToSkip=number` a number events to skip at the beginning + of each file read. + +- `HepMC.version` - when reading the events from files, this option is + no longer needed. The code itself figures out which format version + the input file is in. If executing a child process through + `GeneratorFileOrCmd.cmd` and the EG writes out HepMC2 format, then + this _must_ be set to `2`. Otherwise, HepMC3 is assumed. -- `FileOrCmd.fileNames=list` a comma separated list of HepMC files - to read. +- `GeneratorFileOrCmd.fileNames=list` a comma separated list of HepMC + files to read. -- `FileOrCmd.cmd=command line` a command line to execute as a +- `GeneratorFileOrCmd.cmd=command line` a command line to execute as a background child process. If this is set (not the empty string), - then `FileOrCmd.fileNames` is ignored. + then `GeneratorFileOrCmd.fileNames` is ignored. -- A number of keys that specifies the command line option switch - that the child program accepts for certain things. If any of - these are set to the empty string, then that switch and - corresponding option value is not passed to the child program. +- A number of keys that specifies the command line option switch that + the child program accepts for certain things. If any of these are + set to the empty string, then that switch and corresponding option + value is not passed to the child program. - - `FileOrCmd.outputSwitch=switch` (default `>`) to specify output - file. The default of `>` assumes that the program write HepMC - events, and _only_ those, to standard output. + - `GeneratorFileOrCmd.outputSwitch=switch` (default `>`) to specify + output file. The default of `>` assumes that the program write + HepMC events, and _only_ those, to standard output. - - `FileOrCmd.seedSwitch=switch` (default `-s`) to specify the - random number generator seed. The value passed is selected by + - `GeneratorFileOrCmd.seedSwitch=switch` (default `-s`) to specify + the random number generator seed. The value passed is selected by the `o2-sim` option `--seed` - - `FileOrCmd.bMaxSwitch=switch` (default `-b`) to specify the - upper limit on the impact parameters sampled. The value passed - is selected by the `o2-sim` option `--bMax` + - `GeneratorFileOrCmd.bMaxSwitch=switch` (default `-b`) to specify + the upper limit on the impact parameters sampled. The value + passed is selected by the `o2-sim` option `--bMax` - - `FileOrCmd.nEventsSwitch=switch` (default `-n`) to specify the - number of events to generate. The value passed is selected by - the `o2-sim` option `--nEvents` or (`-n`) + - `GeneratorFileOrCmd.nEventsSwitch=switch` (default `-n`) to + specify the number of events to generate. The value passed is + selected by the `o2-sim` option `--nEvents` or (`-n`) - - `FileOrCmd.backgroundSwitch=switch` (default `&`) to specify how - the program is put in the background. Typically this should be - `&`, but a program may itself fork to the background. + - `GeneratorFileOrCmd.backgroundSwitch=switch` (default `&`) to + specify how the program is put in the background. Typically this + should be `&`, but a program may itself fork to the background. -- Some options are no longer available +- Some options are deprecated - - `HepMC.fileName` - use `FileOrCmd.fileNames` - - `HepMC.version` - now the code itself figures out which format - version the input file is in. + - `HepMC.fileName` - use `GeneratorFileOrCmd.fileNames` The command line build will now be diff --git a/run/SimExamples/HepMC/child.sh b/run/SimExamples/HepMC/child.sh index 9c7b2ec142f1c..89b563ec8d550 100755 --- a/run/SimExamples/HepMC/child.sh +++ b/run/SimExamples/HepMC/child.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash cmd="./crmc.sh" +more="GeneratorFileOrCmd.bMaxSwitch=none" seed=$RANDOM nev=1 out= @@ -13,6 +14,7 @@ Usage: $0 [OPTIONS] Options: -c,--cmdline COMMAND Command line + -m,--more CONFIG More configurations ($more) -s,--seed SEED Random number seed ($seed) -n,--nevents EVENTS Number of events ($nev) -o,--output OUTPUT Output prefix ($out) @@ -47,5 +49,5 @@ fi out=`echo "$out" | tr ' ' '_'` export VMCWORKDIR=${O2_ROOT}/share -o2-sim -g hepmc --configKeyValues "FileOrCmd.cmd=$cmd" \ +o2-sim -g hepmc --configKeyValues "GeneratorFileOrCmd.cmd=$cmd;${more}" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ diff --git a/run/SimExamples/HepMC/read.sh b/run/SimExamples/HepMC/read.sh index 6c0d0d2f5c95f..e64f5561a775c 100755 --- a/run/SimExamples/HepMC/read.sh +++ b/run/SimExamples/HepMC/read.sh @@ -44,5 +44,5 @@ fi out=`echo "$out" | tr ' ' '_'` export VMCWORKDIR=${O2_ROOT}/share -o2-sim -g hepmc --configKeyValues "FileOrCmd.fileNames=$inp" \ +o2-sim -g hepmc --configKeyValues "GeneratorFileOrCmd.fileNames=$inp" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ diff --git a/run/SimExamples/HepMC_STARlight/run.sh b/run/SimExamples/HepMC_STARlight/run.sh index c6fc63a8fb7b3..3eb5b91f24a6d 100755 --- a/run/SimExamples/HepMC_STARlight/run.sh +++ b/run/SimExamples/HepMC_STARlight/run.sh @@ -15,4 +15,4 @@ env -i HOME="$HOME" USER="$USER" PATH="/bin:/usr/bin:/usr/local/bin" \ # PART b) NEV=1000 o2-sim -j 20 -n ${NEV} -g hepmc -m PIPE ITS -o sim \ - --configKeyValues "FileOrCmd.fileNames=starlight.hepmc;Diamond.position[2]=0.1;Diamond.width[2]=0.05" + --configKeyValues "GeneratorFileOrCmd.fileNames=starlight.hepmc;Diamond.position[2]=0.1;Diamond.width[2]=0.05" diff --git a/run/SimExamples/TParticle/README.md b/run/SimExamples/TParticle/README.md index 4dadc8ce06965..c9df40665d829 100644 --- a/run/SimExamples/TParticle/README.md +++ b/run/SimExamples/TParticle/README.md @@ -14,15 +14,15 @@ generator program (EG). To make a simulation reading from the file `particles.root`, do - o2-sim -g tparticle --configKeyValues "FileOrCmd.fileNames=particles.root" ... + o2-sim -g tparticle --configKeyValues "GeneratorFileOrCmd.fileNames=particles.root" ... See also [`read.sh`](read.sh). Do ./read.sh --help -for a list of options. This expects an input file with a `TTree` -with a single `TBranch` holding a `TClonesArray` of `TParticle` -objects. One such example file can be made with [`myeg.sh`]. Do +for a list of options. This expects an input file with a `TTree` with +a single `TBranch` holding a `TClonesArray` of `TParticle` objects. +One such example file can be made with [`myeg.sh`]. Do ./myeg.sh --help @@ -38,17 +38,16 @@ for a list of options. For example - o2-sim -g tparticle --configKeyValues "FileOrCmd.fileNames=particles.root;GeneratorTParticle.treeName=Events;GeneratorTParticle.branchName=Tracks" ... + o2-sim -g tparticle --configKeyValues "GeneratorFileOrCmd.fileNames=particles.root;GeneratorTParticle.treeName=Events;GeneratorTParticle.branchName=Tracks" ... ## Reading TParticle events from child process `GeneratorTParticle` can not only read events from a file, but can also spawn an child EG to produce events. Suppose we have a program named `eg` which is some EG that writes `TParticle` event records to a -file . Then we can execute a simulation using this external -EG by +file . Then we can execute a simulation using this external EG by - o2-sim -g tgenerator --configKeyValues "FileOrCmd.cmd=eg" + o2-sim -g tgenerator --configKeyValues "GeneratorFileOrCmd.cmd=eg" See also [`child.sh`](child.sh). Do @@ -60,23 +59,23 @@ There are some requirements on the program `eg`: - The EG program _must_ be able to write the HepMC event structures to a specified file. The option passed to the program is specified via - the key `FileOrCmd.outputSwitch`. This defaults to `-o`. + the key `GeneratorFileOrCmd.outputSwitch`. This defaults to `-o`. - It _must_ accept an option to set the number of events to generate. This is controlled by the configuration key - `FileOrCmd.nEventsSwitch` and defaults to `-n`. Thus, the EG - application should accept `-n 10` to mean that it should generate + `GeneratorFileOrCmd.nEventsSwitch` and defaults to `-n`. Thus, the + EG application should accept `-n 10` to mean that it should generate `10` events, for example. - The EG application should accept a command line switch to set the - random number generator seed. This option is specified via the - configuration key `FileOrCmd.seedSwitch` and defaults to `-s`. - Thus, the EG application must accept `-s 123456` to mean to set the - random number seed to `123456` for example. + random number generator seed. This option is specified via the + configuration key `GeneratorFileOrCmd.seedSwitch` and defaults to + `-s`. Thus, the EG application must accept `-s 123456` to mean to + set the random number seed to `123456` for example. - The EG application should accept a command line switch to set the maximum impact parameter (in Fermi-metre) sampled. This is set via - the configuration key `FileOrCmd.bMaxSwithc` and defaults to `-b`. - Thus, the EG application should take the command line argument `-b - 10` to mean that it should only generate events with an impact - parameter between 0fm and 10fm. + the configuration key `GeneratorFileOrCmd.bMaxSwithc` and defaults + to `-b`. Thus, the EG application should take the command line + argument `-b 10` to mean that it should only generate events with an + impact parameter between 0fm and 10fm. If a program does not adhere to these requirements, it will often be simple enough to make a small wrapper script that enforce this. @@ -178,7 +177,7 @@ the `MyEG.macro` script We can then do - o2-sim -g tgenerator --configKeyValues "FileOrCmd.cmd=./myeg.sh" + o2-sim -g tgenerator --configKeyValues "GeneratorFileOrCmd.cmd=./myeg.sh" to produce events with our generator `MyGenerator`. @@ -205,37 +204,37 @@ configured through configuration keys set via `--configKeyValues` - `GeneratorTParticle.branchName=name` the name of the `TBranch` in the `TTree` that holds the `TClonesArray` of `TParticle` objects. -- `FileOrCmd.fileNames=list` a comma separated list of HepMC files to - read +- `GeneratorFileOrCmd.fileNames=list` a comma separated list of HepMC + files to read -- `FileOrCmd.cmd=command line` a command line to execute as a +- `GeneratorFileOrCmd.cmd=command line` a command line to execute as a background child process. If this is set (not the empty string), - then `FileOrCmd.fileNames` is ignored. + then `GeneratorFileOrCmd.fileNames` is ignored. - A number of keys that specifies the command line option switch that the child program accepts for certain things. If any of these are set to the empty string or special value `none`, then that switch and corresponding option value is not passed to the child program. - - `FileOrCmd.outputSwitch=switch` (default `>`) to specify output - file. The default of `>` assumes that the program write events, - and _only_ those, to standard output. + - `GeneratorFileOrCmd.outputSwitch=switch` (default `>`) to specify + output file. The default of `>` assumes that the program write + events, and _only_ those, to standard output. - - `FileOrCmd.seedSwitch=switch` (default `-s`) to specify the - random number generator seed. The value passed is selected by + - `GeneratorFileOrCmd.seedSwitch=switch` (default `-s`) to specify + the random number generator seed. The value passed is selected by the `o2-sim` option `--seed`. - - `FileOrCmd.bMaxSwitch=switch` (default `-b`) to specify the - upper limit on the impact parameters sampled. The value passed - is selected by the `o2-sim` option `--bMax`. + - `GeneratorFileOrCmd.bMaxSwitch=switch` (default `-b`) to specify + the upper limit on the impact parameters sampled. The value + passed is selected by the `o2-sim` option `--bMax`. - - `FileOrCmd.nEventsSwitch=switch` (default `-n`) to specify the - number of events to generate. The value passed is selected by - the `o2-sim` option `--nEvents` or (`-n`). + - `GeneratorFileOrCmd.nEventsSwitch=switch` (default `-n`) to + specify the number of events to generate. The value passed is + selected by the `o2-sim` option `--nEvents` or (`-n`). - - `FileOrCmd.backgroundSwitch=switch` (default `&`) to specify how - the program is put in the background. Typically this should be - `&`, but a program may itself fork to the background. + - `GeneratorFileOrCmd.backgroundSwitch=switch` (default `&`) to + specify how the program is put in the background. Typically this + should be `&`, but a program may itself fork to the background. The command line build will now be diff --git a/run/SimExamples/TParticle/child.sh b/run/SimExamples/TParticle/child.sh index 210459adea17c..ae188024808d0 100755 --- a/run/SimExamples/TParticle/child.sh +++ b/run/SimExamples/TParticle/child.sh @@ -52,6 +52,6 @@ out=`echo "$out" | tr ' ' '_'` set -x export VMCWORKDIR=${O2_ROOT}/share o2-sim -g tparticle \ - --configKeyValues "FileOrCmd.cmd=$cmd $opt;FileOrCmd.outputSwitch=-o" \ + --configKeyValues "GeneratorFileOrCmd.cmd=$cmd $opt;GeneratorFileOrCmd.outputSwitch=-o" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ diff --git a/run/SimExamples/TParticle/read.sh b/run/SimExamples/TParticle/read.sh index 244865f2bfa9c..0376bb15dc6b0 100755 --- a/run/SimExamples/TParticle/read.sh +++ b/run/SimExamples/TParticle/read.sh @@ -49,6 +49,6 @@ out=`echo "$out" | tr ' ' '_'` set -e export VMCWORKDIR=${O2_ROOT}/share -o2-sim -g tparticle --configKeyValues "FileOrCmd.fileNames=${inp}" \ +o2-sim -g tparticle --configKeyValues "GeneratorFileOrCmd.fileNames=${inp}" \ --outPrefix "$out" --seed $seed --nEvents $nev $@ From 353068e7b8c8894cf921cc7f66f71246c1977974 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Mon, 16 Oct 2023 07:05:31 +0200 Subject: [PATCH 36/37] Fix for test - Forgot to change key for test in `run/CMakeLists.txt` - `crmc.sh` uses `-o hepmc` instead of `-o hepmc3` to accomodate older installation of CRMC with `aliBuild`. --- run/CMakeLists.txt | 2 +- run/SimExamples/HepMC/crmc.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt index b0825639dda01..f9b0f5e220ea6 100644 --- a/run/CMakeLists.txt +++ b/run/CMakeLists.txt @@ -271,7 +271,7 @@ o2_add_test_command(NAME o2sim_hepmc -g hepmc --configKeyValues -"FileOrCmd.fileNames=${CMAKE_SOURCE_DIR}/Generators/share/data/pythia.hepmc;HepMC.version=2;align-geom.mDetectors=none" +"GeneratorFileOrCmd.fileNames=${CMAKE_SOURCE_DIR}/Generators/share/data/pythia.hepmc;HepMC.version=2;align-geom.mDetectors=none" -o o2simhepmc LABELS long sim hepmc3 diff --git a/run/SimExamples/HepMC/crmc.sh b/run/SimExamples/HepMC/crmc.sh index 347de0446e5fd..1c2d2f7827dbc 100755 --- a/run/SimExamples/HepMC/crmc.sh +++ b/run/SimExamples/HepMC/crmc.sh @@ -3,5 +3,5 @@ # event record. crmcParam=$(dirname $(dirname `which crmc`))/etc/crmc.param -exec crmc -c $crmcParam $@ -o hepmc3 -f /dev/stdout | \ +exec crmc -c $crmcParam $@ -o hepmc -f /dev/stdout | \ sed -n 's/^\(HepMC::\|[EAUWVP] \)/\1/p' From 209b4539626bef59ff3646489240845a21236a24 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Thu, 19 Oct 2023 08:06:38 +0200 Subject: [PATCH 37/37] Fix braces --- Generators/src/GeneratorPythia8.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Generators/src/GeneratorPythia8.cxx b/Generators/src/GeneratorPythia8.cxx index 574bed41773d8..7038647ee4ba0 100644 --- a/Generators/src/GeneratorPythia8.cxx +++ b/Generators/src/GeneratorPythia8.cxx @@ -380,9 +380,10 @@ void GeneratorPythia8::getNpart(const Pythia8::Info& info, int& nPart) #else auto hiinfo = info.hiInfo; #endif - if (hiinfo) + if (hiinfo) { nPart = (hiinfo->nAbsProj() + hiinfo->nDiffProj() + hiinfo->nAbsTarg() + hiinfo->nDiffTarg()); + } int nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg; getNpart(info, nProtonProj, nNeutronProj, nProtonTarg, nNeutronTarg);