diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/NameConf.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/NameConf.h index b903c673490a1..c089c1008efba 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/NameConf.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/NameConf.h @@ -49,7 +49,7 @@ class NameConf return o2::utils::concat_string(prefix, "_", DIGITS_STRING, d.getName(), ".root"); } - // Filename to store kinematics + TrackRefs + // Filename to store general run parameters (GRP) static std::string getGRPFileName(const std::string_view prefix = STANDARDSIMPREFIX) { return o2::utils::concat_string(prefix, "_", GRP_STRING, ".root"); @@ -61,6 +61,12 @@ class NameConf return o2::utils::concat_string(prefix, "_", KINE_STRING, ".root"); } + // Filename to store kinematics + TrackRefs + static std::string getMCHeadersFileName(const std::string_view prefix = STANDARDSIMPREFIX) + { + return o2::utils::concat_string(prefix, "_", MCHEADER_STRING, ".root"); + } + // Filename to store final MC configuration file static std::string getMCConfigFileName(const std::string_view prefix = STANDARDSIMPREFIX) { @@ -104,6 +110,7 @@ class NameConf static constexpr std::string_view DIGITS_STRING = "Digits"; // hardcoded static constexpr std::string_view GRP_STRING = "grp"; // hardcoded static constexpr std::string_view KINE_STRING = "Kine"; // hardcoded + static constexpr std::string_view MCHEADER_STRING = "MCHeader"; // hardcoded static constexpr std::string_view GEOM_FILE_STRING = "geometry"; static constexpr std::string_view CUT_FILE_STRING = "proc-cut"; static constexpr std::string_view CONFIG_STRING = "configuration"; diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h index 863220e5f10bb..f2889c9bca134 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h @@ -85,6 +85,9 @@ class MCEventHeader : public FairMCEventHeader MCEventStats& getMCEventStats() { return mEventStats; } + /// create a standalone ROOT file/tree with only the MCHeader branch + static void extractFileFromKinematics(std::string_view kinefilename, std::string_view targetfilename); + protected: std::string mEmbeddingFileName; Int_t mEmbeddingEventIndex = 0; diff --git a/DataFormats/simulation/src/MCEventHeader.cxx b/DataFormats/simulation/src/MCEventHeader.cxx index 0d32dc18d019c..6b43cc9c86afd 100644 --- a/DataFormats/simulation/src/MCEventHeader.cxx +++ b/DataFormats/simulation/src/MCEventHeader.cxx @@ -12,6 +12,8 @@ #include "SimulationDataFormat/MCEventHeader.h" #include "FairRootManager.h" +#include +#include namespace o2 { @@ -32,6 +34,32 @@ void MCEventHeader::Reset() mEmbeddingEventIndex = 0; } +void MCEventHeader::extractFileFromKinematics(std::string_view kinefilename, std::string_view targetfilename) +{ + auto oldfile = TFile::Open(kinefilename.data()); + auto kinetree = (TTree*)oldfile->Get("o2sim"); + // deactivate all branches + kinetree->SetBranchStatus("*", 0); + // activate the header branch + kinetree->SetBranchStatus("MCEventHeader*", 1); + // create a new file + a clone of old tree header. Do not copy events + auto newfile = TFile::Open(targetfilename.data(), "RECREATE"); + auto newtree = kinetree->CloneTree(0); + // here we copy the branches + newtree->CopyEntries(kinetree, kinetree->GetEntries()); + newtree->SetEntries(kinetree->GetEntries()); + // flush to disk + newtree->Write(); + newfile->Close(); + delete newfile; + + // clean + if (oldfile) { + oldfile->Close(); + delete oldfile; + } +} + /*****************************************************************/ /*****************************************************************/ diff --git a/macro/migrateSimFiles.C b/macro/migrateSimFiles.C index cf0ff9650d0d6..243fc0965d88c 100644 --- a/macro/migrateSimFiles.C +++ b/macro/migrateSimFiles.C @@ -75,6 +75,11 @@ void migrateSimFiles(const char* filebase = "o2sim") auto kinematicsfile = o2::base::NameConf::getMCKinematicsFileName(filebase); copyBranch(originalfilename.c_str(), kinematicsfile.c_str(), o2::detectors::SimTraits::KINEMATICSBRANCHES); + // split off additional MCHeaders file + std::vector headerbranches = {"MCEventHeader"}; + auto headersfile = o2::base::NameConf::getMCHeadersFileName(filebase); + copyBranch(originalfilename.c_str(), headersfile.c_str(), headerbranches); + // loop over all possible detectors for (auto detid = o2::detectors::DetID::First; detid <= o2::detectors::DetID::Last; ++detid) { if (!grp->isDetReadOut(detid)) { diff --git a/run/o2sim_parallel.cxx b/run/o2sim_parallel.cxx index 670704e51dc73..1862a0e69fec3 100644 --- a/run/o2sim_parallel.cxx +++ b/run/o2sim_parallel.cxx @@ -29,6 +29,7 @@ #include "Framework/FreePortFinder.h" #include #include "DetectorsCommonDataFormats/NameConf.h" +#include "SimulationDataFormat/MCEventHeader.h" #include "rapidjson/document.h" #include "rapidjson/writer.h" @@ -458,6 +459,18 @@ int main(int argc, char* argv[]) // (mainly useful for continuous integration / automated testing suite) auto returncode = checkresult(); if (returncode == 0) { + // Extract a single file for MCEventHeaders + // This file will be small and can quickly unblock start of signal transport (in embedding). + // This is useful when we cache background events on the GRID. The headers file can be copied quickly + // and the rest of kinematics + Hits may follow asyncronously since they are only needed at much + // later stages (digitization). + + auto& conf = o2::conf::SimConfig::Instance(); + // easy check: see if we have number of entries in output tree == number of events asked + std::string kinefilename = o2::base::NameConf::getMCKinematicsFileName(conf.getOutPrefix().c_str()); + std::string headerfilename = o2::base::NameConf::getMCHeadersFileName(conf.getOutPrefix().c_str()); + o2::dataformats::MCEventHeader::extractFileFromKinematics(kinefilename, headerfilename); + LOG(INFO) << "SIMULATION RETURNED SUCCESFULLY"; }