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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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 05ad595d12e224a5c6259439699cf7b95c4f430f Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 11:49:37 +0200 Subject: [PATCH 12/23] 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 13/23] 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 595d84315bb70297a370293215a8e3132b6746f8 Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 13:19:16 +0200 Subject: [PATCH 14/23] 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 15/23] 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 16/23] 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 17/23] 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 18/23] 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 19/23] 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 f27aaf8f0b149a8f5d6c15538c350fff815f2dbb Mon Sep 17 00:00:00 2001 From: Christian Holm Christensen Date: Fri, 6 Oct 2023 15:05:58 +0200 Subject: [PATCH 20/23] 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 21/23] 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 22/23] 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 23/23] 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 $@ -