From 14999546b701876374c45ed07306c2be15d568e3 Mon Sep 17 00:00:00 2001 From: vsitaraman Date: Fri, 31 Jul 2026 14:05:18 -0400 Subject: [PATCH] modified: Armory/HistPlotter.h modified: TrackRecon.C made changes to account for frequent crashes due to the number of histograms. New changes allow for flsuhing of data to histograms every n events modified: run_27Al.sh --- Armory/HistPlotter.h | 396 +++++++++++++++++++++++++------------------ TrackRecon.C | 44 ++++- run_27Al.sh | 2 +- 3 files changed, 279 insertions(+), 163 deletions(-) diff --git a/Armory/HistPlotter.h b/Armory/HistPlotter.h index 10fa9c5..51b3285 100644 --- a/Armory/HistPlotter.h +++ b/Armory/HistPlotter.h @@ -20,147 +20,182 @@ #include #include -class HistPlotter { +class HistPlotter +{ private: - long long barrier_count, barrier_limit; //meant to keep track of how often to call FillN() on histograms - enum {TFILE, TMEMFILE} filetype; - std::map oMap; //!< Maps std::string to all TH1, TH2 objects in the class - std::unordered_map cutsMap; //!< Maps std::string to TCutG objects held by the class - std::set folderList; //!< List of all folder names used to nest objects - std::unordered_map foldersForObjects; //!< Map that returns the folder corresponding to the object whose pointer is specified - TFile *ofile=nullptr; //!< TFile pointer for the output file - TMemFile *omfile=nullptr; //!< TFile pointer for the output memfile + long long barrier_count, barrier_limit; // meant to keep track of how often to call FillN() on histograms + enum + { + TFILE, + TMEMFILE + } filetype; + std::map oMap; //!< Maps std::string to all TH1, TH2 objects in the class + std::unordered_map cutsMap; //!< Maps std::string to TCutG objects held by the class + std::set folderList; //!< List of all folder names used to nest objects + std::unordered_map foldersForObjects; //!< Map that returns the folder corresponding to the object whose pointer is specified + TFile *ofile = nullptr; //!< TFile pointer for the output file + TMemFile *omfile = nullptr; //!< TFile pointer for the output memfile - //Caches to permit FillN() calls + // Caches to permit FillN() calls std::map> onedimcache; std::map, std::vector>> twodimcache; inline void FillN_All_Histograms(); + public: HistPlotter(std::string outfile, std::string type); inline void FlushToDisk(int integral); //!< Writes all objects to file before closing, nesting objects in folders as is found necessary - inline void PrintObjects(); //!< Dump objects to std::cout for inspection - inline void ReadCuts(std::string); - inline TCutG* FindCut(std::string cut) { - return static_cast(cutsMap.at(cut)); + inline void PrintObjects(); //!< Dump objects to std::cout for inspection + inline void ReadCuts(std::string); + inline TCutG *FindCut(std::string cut) + { + return static_cast(cutsMap.at(cut)); } inline void set_barrier_limit(long long limit) { barrier_limit = limit; } - inline void barrier_increment() { + inline void barrier_increment() + { barrier_count++; - if(barrier_count == barrier_limit) { + if (barrier_count == barrier_limit) + { FillN_All_Histograms(); - barrier_count=0; + barrier_count = 0; } } + + inline void force_flush_caches() + { + FillN_All_Histograms(); + barrier_count = 0; + } /*! \fn void FindCut() - \brief - - Searches for a cut by name 'cut' in the internal list of cuts 'cutsMap'. Ugly fails (via unresolved at()) if such a cut isn't found. + \brief + - Searches for a cut by name 'cut' in the internal list of cuts 'cutsMap'. Ugly fails (via unresolved at()) if such a cut isn't found. \param filename - name of the plainxtext file containing the cut file locations and identifiers \return Pointer to the TCutG object that matches the name. Very useful to use this as plotter.FindCut("protonbarrelpid")->IsInside(deltaE, E) for instance. */ - inline void SetNewTitle(std::string name, std::string title) { - auto result = oMap.find(name); //result is an iterator - if(result==oMap.end()) return; //no warnings, could be changed in future + inline void SetNewTitle(std::string name, std::string title) + { + auto result = oMap.find(name); // result is an iterator + if (result == oMap.end()) + return; // no warnings, could be changed in future else - static_cast(oMap.at(name))->SetTitle(title.c_str()); // set new title - } + static_cast(oMap.at(name))->SetTitle(title.c_str()); // set new title + } - //Smart functions that create a new histogram if it doesn't exist. - inline void FillGraph(const std::string &name, float valuex, float valuey, float errx=0, float erry=0); - inline void Fill1D(const std::string& name,int nbinsx, float xlow, float xhigh, float value); - inline void Fill2D(const std::string& name,int nbinsx, float xlow, float xhigh - ,int nbinsy, float ylow, float yhigh, float valuex, float valuey); - inline void Fill1D(const std::string& name,int nbinsx, float xlow, float xhigh, float value, const std::string& folder); - inline void Fill2D(const std::string& name,int nbinsx, float xlow, float xhigh - ,int nbinsy, float ylow, float yhigh, float valuex, float valuey, const std::string& folder); - //TObject* findObject(std::string key); + // Smart functions that create a new histogram if it doesn't exist. + inline void FillGraph(const std::string &name, float valuex, float valuey, float errx = 0, float erry = 0); + inline void Fill1D(const std::string &name, int nbinsx, float xlow, float xhigh, float value); + inline void Fill2D(const std::string &name, int nbinsx, float xlow, float xhigh, int nbinsy, float ylow, float yhigh, float valuex, float valuey); + inline void Fill1D(const std::string &name, int nbinsx, float xlow, float xhigh, float value, const std::string &folder); + inline void Fill2D(const std::string &name, int nbinsx, float xlow, float xhigh, int nbinsy, float ylow, float yhigh, float valuex, float valuey, const std::string &folder); + // TObject* findObject(std::string key); }; -HistPlotter::HistPlotter(std::string outfile, std::string type="") { +HistPlotter::HistPlotter(std::string outfile, std::string type = "") +{ /*! \brief Constructor. Opens a TFile instance with the specified filename \param outfile : std::string that holds the desired output ROOT filename \return None */ - if(type=="" || type == "TFILE") { - ofile = new TFile(outfile.c_str(),"recreate"); - filetype = TFILE; - } else if(type =="TMEMFILE") { - omfile = new TMemFile(outfile.c_str(),"recreate"); - filetype=TMEMFILE; - } else { - std::cout << "Unknown type "<< type << " specified for HistPlotter (use \"TFILE\" or \"TMEMFILE\"), using default \"TFILE\" " << std::endl; - ofile = new TFile(outfile.c_str(),"recreate"); + if (type == "" || type == "TFILE") + { + ofile = new TFile(outfile.c_str(), "recreate"); filetype = TFILE; } - barrier_count=0; - barrier_limit=1000; + else if (type == "TMEMFILE") + { + omfile = new TMemFile(outfile.c_str(), "recreate"); + filetype = TMEMFILE; + } + else + { + std::cout << "Unknown type " << type << " specified for HistPlotter (use \"TFILE\" or \"TMEMFILE\"), using default \"TFILE\" " << std::endl; + ofile = new TFile(outfile.c_str(), "recreate"); + filetype = TFILE; + } + barrier_count = 0; + barrier_limit = 1000; } -void HistPlotter::FillN_All_Histograms() { - for(auto it=oMap.begin(); it!=oMap.end(); it++ ) { - //it->first is std::string 'name', it->second is the TObject - if(it->second->InheritsFrom("TH1F")) { - //FillN(size, array-of-doubles, array-of-weights); //we set array-of-weights to (1,1,1,.. (size) - static_cast(it->second)->FillN(onedimcache[it->first].size(), //size - onedimcache[it->first].data(), //array - std::vector(onedimcache[it->first].size(),1.0).data()); //weight of ones +void HistPlotter::FillN_All_Histograms() +{ + for (auto it = oMap.begin(); it != oMap.end(); it++) + { + // it->first is std::string 'name', it->second is the TObject + if (it->second->InheritsFrom("TH1F")) + { + // FillN(size, array-of-doubles, array-of-weights); //we set array-of-weights to (1,1,1,.. (size) + static_cast(it->second)->FillN(onedimcache[it->first].size(), // size + onedimcache[it->first].data(), // array + std::vector(onedimcache[it->first].size(), 1.0).data()); // weight of ones onedimcache[it->first].clear(); - } else if(it->second->InheritsFrom("TH2F")) { - //FillN(size, array-of-doubles, array-of-weights); //we set array-of-weights to (1,1,1,.. (size)) - static_cast(it->second)->FillN(twodimcache[it->first].first.size(), //size - twodimcache[it->first].first.data(), //x array - twodimcache[it->first].second.data(), //y array - std::vector(twodimcache[it->first].first.size(),1.0).data()); //weight of ones - twodimcache[it->first].first.clear(); - twodimcache[it->first].second.clear(); + } + else if (it->second->InheritsFrom("TH2F")) + { + // FillN(size, array-of-doubles, array-of-weights); //we set array-of-weights to (1,1,1,.. (size)) + static_cast(it->second)->FillN(twodimcache[it->first].first.size(), // size + twodimcache[it->first].first.data(), // x array + twodimcache[it->first].second.data(), // y array + std::vector(twodimcache[it->first].first.size(), 1.0).data()); // weight of ones + twodimcache[it->first].first.clear(); + twodimcache[it->first].second.clear(); } } std::cout << "." << std::endl; } -void HistPlotter::FlushToDisk(int min_integral=0) { +void HistPlotter::FlushToDisk(int min_integral = 0) +{ /*! \fn void FlushToDisk() \brief Function that can be used at any point to exit smoothly by saving all ROOT objects in memory to the output file before closing it. Obeys the binding of histograms to separate folders, if so specified. \return No return -- void */ - if(filetype==TMEMFILE && omfile) { + if (filetype == TMEMFILE && omfile) + { std::cout << "Not flushing a TMemfile .. exiting .." << std::endl; delete omfile; return; } - if(ofile->IsZombie() || !ofile) { + if (ofile->IsZombie() || !ofile) + { std::cerr << "Output file is zombie, finishing up without writing to disk!" << std::endl; return; } FillN_All_Histograms(); - for(auto it=oMap.begin(); it!=oMap.end(); it++ ) { - //omap maps: name(first) to object address(second). - // foldersForObjects maps: object address(first) to foldername(second) - auto result = foldersForObjects.find(it->second); //returns pair if found - if(result!=foldersForObjects.end()) { //we try to create folder if needed and cd to it - ofile->mkdir(result->second.c_str(),"",kTRUE); // args: name, title, returnExistingDirectory + for (auto it = oMap.begin(); it != oMap.end(); it++) + { + // omap maps: name(first) to object address(second). + // foldersForObjects maps: object address(first) to foldername(second) + auto result = foldersForObjects.find(it->second); // returns pair if found + if (result != foldersForObjects.end()) + { // we try to create folder if needed and cd to it + ofile->mkdir(result->second.c_str(), "", kTRUE); // args: name, title, returnExistingDirectory ofile->cd(result->second.c_str()); - } else { - ofile->cd(); //toplevel for all default histograms. Default setting } - if(((TH1F*)it->second)->Integral()>min_integral) - it->second->Write(); + else + { + ofile->cd(); // toplevel for all default histograms. Default setting + } + if (((TH1F *)it->second)->Integral() > min_integral) + it->second->Write(); } - //Create a directory for all cuts, and save all cuts in them - ofile->mkdir("gCUTS","",kTRUE); + // Create a directory for all cuts, and save all cuts in them + ofile->mkdir("gCUTS", "", kTRUE); ofile->cd("gCUTS"); - for(auto it=cutsMap.begin(); it!=cutsMap.end(); it++) { - (static_cast(it->second))->SetName(it->first.c_str()); + for (auto it = cutsMap.begin(); it != cutsMap.end(); it++) + { + (static_cast(it->second))->SetName(it->first.c_str()); it->second->Write(); } ofile->Close(); std::cout << "Wrote " << oMap.size() << " histograms to TFile " << std::string(ofile->GetName()) << std::endl; } -void HistPlotter::FillGraph(const std::string& name, float valuex, float valuey, float errx, float erry) { +void HistPlotter::FillGraph(const std::string &name, float valuex, float valuey, float errx, float erry) +{ /*! \fn void FillGraph() \brief - Creates a TGraphError in memory with name 'name' if it doesn't exist, and fills it with valuex, valuey @@ -173,13 +208,15 @@ void HistPlotter::FillGraph(const std::string& name, float valuex, float valuey, \param erry The y error \return No return void */ - auto result = oMap.find(name); - if(result==oMap.end()) { + auto result = oMap.find(name); + if (result == oMap.end()) + { TGraphErrors *tempG = new TGraphErrors(); tempG->SetName(name.c_str()); - oMap.insert(std::make_pair(name,static_cast(tempG))); + oMap.insert(std::make_pair(name, static_cast(tempG))); } - if(!oMap.at(name)->InheritsFrom("TGraphErrors")) { + if (!oMap.at(name)->InheritsFrom("TGraphErrors")) + { std::cerr << "Object " << name << " refers to something other than a TGraph*, not filling it hence!" << std::endl; std::cerr << "Abort.." << std::endl; FlushToDisk(); @@ -188,9 +225,10 @@ void HistPlotter::FillGraph(const std::string& name, float valuex, float valuey, // static_cast(oMap.at(name))->AddPointError(valuex,valuey,errx,erry); } -void HistPlotter::Fill1D(const std::string& name, int nbinsx, float xlow, float xhigh, float value) { +void HistPlotter::Fill1D(const std::string &name, int nbinsx, float xlow, float xhigh, float value) +{ /*! \fn void Fill1D() - \brief + \brief - Creates a TH1F in memory with name 'name' if it doesn't exist, and fills it with valuex, valuey - Writes present state to disk and fails with return value -1 if the name clashes with another object that's not of type TH1* @@ -201,30 +239,35 @@ void HistPlotter::Fill1D(const std::string& name, int nbinsx, float xlow, float \param value The bin corresponding to value in (nbinsx, xlow, xhigh) is incremented by 1 \return No return void */ - auto result = oMap.find(name); //result is an iterator - if(result==oMap.end()) { - TH1F* temp1D = new TH1F(name.c_str(), name.c_str(), nbinsx, xlow, xhigh); - oMap.insert(std::make_pair(name,static_cast(temp1D))); + auto result = oMap.find(name); // result is an iterator + if (result == oMap.end()) + { + TH1F *temp1D = new TH1F(name.c_str(), name.c_str(), nbinsx, xlow, xhigh); + oMap.insert(std::make_pair(name, static_cast(temp1D))); onedimcache.insert(std::make_pair(name, std::vector())); onedimcache[name].reserve(16384); - } else if(foldersForObjects.find(oMap.at(name))!=foldersForObjects.end()) { //shouldn't have a folder associated with it - std::cerr << "Object " << name << " already registered at " << foldersForObjects[oMap[name]] << ", choose a different name for the histogram to be stored in toplevel .." << std::endl; + } + else if (foldersForObjects.find(oMap.at(name)) != foldersForObjects.end()) + { // shouldn't have a folder associated with it + std::cerr << "Object " << name << " already registered at " << foldersForObjects[oMap[name]] << ", choose a different name for the histogram to be stored in toplevel .." << std::endl; } - //Check if the string 'name' maps to a 1D hist. If there's any other object by this name raise issue - if(!oMap.at(name)->InheritsFrom("TH1F")) { + // Check if the string 'name' maps to a 1D hist. If there's any other object by this name raise issue + if (!oMap.at(name)->InheritsFrom("TH1F")) + { std::cerr << "Object " << name << " refers to something other than a TH1*, not filling it hence!" << std::endl; std::cerr << "Abort.." << std::endl; FlushToDisk(); exit(-1); } onedimcache[name].emplace_back(value); - //static_cast(oMap.at(name))->Fill(value); + // static_cast(oMap.at(name))->Fill(value); } -void HistPlotter::Fill1D(const std::string& name, int nbinsx, float xlow, float xhigh, float value, const std::string& foldername) { +void HistPlotter::Fill1D(const std::string &name, int nbinsx, float xlow, float xhigh, float value, const std::string &foldername) +{ /*! \fn void Fill1D() - \brief + \brief - Creates a TH1F in memory with name 'name' if it doesn't exist, and fills it with valuex, valuey - Writes present state to disk and fails with return value -1 if the name clashes with another object that's not of type TH1* - Remembers the foldername this particular histogram maps to, if provided. If not, defaults to toplevel. @@ -238,41 +281,51 @@ void HistPlotter::Fill1D(const std::string& name, int nbinsx, float xlow, float \return No return -- void */ - auto result = oMap.find(name); //result is an iterator - if(result==oMap.end()) { - TH1F* temp1D = new TH1F(name.c_str(), name.c_str(), nbinsx, xlow, xhigh); - oMap.insert(std::make_pair(name,static_cast(temp1D))); + auto result = oMap.find(name); // result is an iterator + if (result == oMap.end()) + { + TH1F *temp1D = new TH1F(name.c_str(), name.c_str(), nbinsx, xlow, xhigh); + oMap.insert(std::make_pair(name, static_cast(temp1D))); onedimcache.insert(std::make_pair(name, std::vector())); onedimcache[name].reserve(16384); - if(foldername!="") { - if(folderList.find(foldername)==folderList.end()) { + if (foldername != "") + { + if (folderList.find(foldername) == folderList.end()) + { folderList.insert(foldername); } - foldersForObjects.insert(std::make_pair(static_cast(temp1D),foldername)); - } - } else { - //object is present in map, but we enforce unique names - //it must already have a folder attached to it - if(foldersForObjects.find(oMap.at(name))==foldersForObjects.end()) { - std::cerr << "Object " << name << " already registered at toplevel, choose a different name for the histogram to be stored in " << foldername << " folder .." << std::endl; - } else if(foldersForObjects[oMap[name]]!=foldername) { - std::cerr << "Object " << name << " already registered at " << foldersForObjects[oMap[name]] << ", choose a different name for the histogram to be stored in " << foldername << " folder .." << std::endl; + foldersForObjects.insert(std::make_pair(static_cast(temp1D), foldername)); } } - //Check if the string 'name' maps to a 1D hist. If there's any other object by this name raise issue - if(!oMap.at(name)->InheritsFrom("TH1F")) { + else + { + // object is present in map, but we enforce unique names + // it must already have a folder attached to it + if (foldersForObjects.find(oMap.at(name)) == foldersForObjects.end()) + { + std::cerr << "Object " << name << " already registered at toplevel, choose a different name for the histogram to be stored in " << foldername << " folder .." << std::endl; + } + else if (foldersForObjects[oMap[name]] != foldername) + { + std::cerr << "Object " << name << " already registered at " << foldersForObjects[oMap[name]] << ", choose a different name for the histogram to be stored in " << foldername << " folder .." << std::endl; + } + } + // Check if the string 'name' maps to a 1D hist. If there's any other object by this name raise issue + if (!oMap.at(name)->InheritsFrom("TH1F")) + { std::cerr << "Object " << name << " refers to something other than a TH1*, not filling it hence!" << std::endl; std::cerr << "Abort.." << std::endl; FlushToDisk(); exit(-1); } onedimcache[name].emplace_back(value); - //static_cast(oMap.at(name))->Fill(value); + // static_cast(oMap.at(name))->Fill(value); } -void HistPlotter::Fill2D(const std::string& name, int nbinsx, float xlow, float xhigh, int nbinsy, float ylow, float yhigh, float valuex, float valuey) { +void HistPlotter::Fill2D(const std::string &name, int nbinsx, float xlow, float xhigh, int nbinsy, float ylow, float yhigh, float valuex, float valuey) +{ /*! \fn void Fill2D() - \brief + \brief - Creates a TH2F in memory with name 'name' if it doesn't exist, and fills it with valuex, valuey - Writes present state to disk and fails with return value -1 if the name clashes with another object that's not of type TH2* \param name name of the TH1F histogram @@ -287,19 +340,23 @@ void HistPlotter::Fill2D(const std::string& name, int nbinsx, float xlow, float \return No return -- void */ - auto result = oMap.find(name); //result is an iterator - if(result==oMap.end()) { - TH2F* temp2D = new TH2F(name.c_str(), name.c_str(), nbinsx, xlow, xhigh, nbinsy, ylow, yhigh); - oMap.insert(std::make_pair(name,static_cast(temp2D))); - twodimcache.insert(std::make_pair(name, std::make_pair(std::vector(),std::vector()))); + auto result = oMap.find(name); // result is an iterator + if (result == oMap.end()) + { + TH2F *temp2D = new TH2F(name.c_str(), name.c_str(), nbinsx, xlow, xhigh, nbinsy, ylow, yhigh); + oMap.insert(std::make_pair(name, static_cast(temp2D))); + twodimcache.insert(std::make_pair(name, std::make_pair(std::vector(), std::vector()))); twodimcache[name].first.reserve(16384); twodimcache[name].second.reserve(16384); - } else if(foldersForObjects.find(oMap.at(name))!=foldersForObjects.end()) { //shouldn't have a folder associated with it - std::cerr << "Object " << name << " already registered at " << foldersForObjects[oMap[name]] << ", choose a different name for the histogram to be stored in toplevel .." << std::endl; + } + else if (foldersForObjects.find(oMap.at(name)) != foldersForObjects.end()) + { // shouldn't have a folder associated with it + std::cerr << "Object " << name << " already registered at " << foldersForObjects[oMap[name]] << ", choose a different name for the histogram to be stored in toplevel .." << std::endl; } - //Check if the string 'name' maps to a 1D hist. If there's any other object by this name raise issue - if(!oMap.at(name)->InheritsFrom("TH2F")) { + // Check if the string 'name' maps to a 1D hist. If there's any other object by this name raise issue + if (!oMap.at(name)->InheritsFrom("TH2F")) + { std::cerr << "Object " << name << " refers to something other than a TH2*, not filling it hence!" << std::endl; std::cerr << "Abort.." << std::endl; FlushToDisk(); @@ -307,12 +364,13 @@ void HistPlotter::Fill2D(const std::string& name, int nbinsx, float xlow, float } twodimcache[name].first.emplace_back(valuex); twodimcache[name].second.emplace_back(valuey); - //static_cast(oMap.at(name))->Fill(valuex,valuey); + // static_cast(oMap.at(name))->Fill(valuex,valuey); } -void HistPlotter::Fill2D(const std::string& name, int nbinsx, float xlow, float xhigh, int nbinsy, float ylow, float yhigh, float valuex, float valuey, const std::string& foldername) { +void HistPlotter::Fill2D(const std::string &name, int nbinsx, float xlow, float xhigh, int nbinsy, float ylow, float yhigh, float valuex, float valuey, const std::string &foldername) +{ /*! \fn void Fill2D() - \brief + \brief - Creates a TH2F in memory with name 'name' if it doesn't exist, and fills it with valuex, valuey - Writes present state to disk and fails with return value -1 if the name clashes with another object that's not of type TH2* - Remembers the foldername this particular histogram maps to, if provided. If not defaults to toplevel @@ -330,31 +388,40 @@ void HistPlotter::Fill2D(const std::string& name, int nbinsx, float xlow, float \return No return -- void */ - auto result = oMap.find(name); //result is an iterator - if(result==oMap.end()) { - TH2F* temp2D = new TH2F(name.c_str(), name.c_str(), nbinsx, xlow, xhigh, nbinsy, ylow, yhigh); - oMap.insert(std::make_pair(name,static_cast(temp2D))); - twodimcache.insert(std::make_pair(name, std::make_pair(std::vector(),std::vector()))); + auto result = oMap.find(name); // result is an iterator + if (result == oMap.end()) + { + TH2F *temp2D = new TH2F(name.c_str(), name.c_str(), nbinsx, xlow, xhigh, nbinsy, ylow, yhigh); + oMap.insert(std::make_pair(name, static_cast(temp2D))); + twodimcache.insert(std::make_pair(name, std::make_pair(std::vector(), std::vector()))); twodimcache[name].first.reserve(16384); twodimcache[name].second.reserve(16384); - if(foldername!="") { - if(folderList.find(foldername)==folderList.end()) { + if (foldername != "") + { + if (folderList.find(foldername) == folderList.end()) + { folderList.insert(foldername); } - foldersForObjects.insert(std::make_pair(static_cast(temp2D),foldername)); + foldersForObjects.insert(std::make_pair(static_cast(temp2D), foldername)); } - } else { - //object is present in map, but we enforce unique names - //it must already have a folder attached to it - if(foldersForObjects.find(oMap.at(name))==foldersForObjects.end()) { + } + else + { + // object is present in map, but we enforce unique names + // it must already have a folder attached to it + if (foldersForObjects.find(oMap.at(name)) == foldersForObjects.end()) + { std::cerr << "Object " << name << " already registered at toplevel, choose a different name for the histogram to be stored in " << foldername << " folder .." << std::endl; - } else if(foldersForObjects[oMap.at(name)]!=foldername) { - std::cerr << "Object " << name << " already registered at " << foldersForObjects[oMap[name]] << ", choose a different name for the histogram to be stored in " << foldername << " folder .." << std::endl; + } + else if (foldersForObjects[oMap.at(name)] != foldername) + { + std::cerr << "Object " << name << " already registered at " << foldersForObjects[oMap[name]] << ", choose a different name for the histogram to be stored in " << foldername << " folder .." << std::endl; } } - //Check if the string 'name' maps to a 1D hist. If there's any other object by this name raise issue - if(!oMap.at(name)->InheritsFrom("TH2F")) { + // Check if the string 'name' maps to a 1D hist. If there's any other object by this name raise issue + if (!oMap.at(name)->InheritsFrom("TH2F")) + { std::cerr << "Object " << name << " refers to something other than a TH2*, not filling it hence!" << std::endl; std::cerr << "Abort.." << std::endl; FlushToDisk(); @@ -362,10 +429,11 @@ void HistPlotter::Fill2D(const std::string& name, int nbinsx, float xlow, float } twodimcache[name].first.emplace_back(valuex); twodimcache[name].second.emplace_back(valuey); - //static_cast(oMap.at(name))->Fill(valuex,valuey); + // static_cast(oMap.at(name))->Fill(valuex,valuey); } -void HistPlotter::ReadCuts(std::string filename) { +void HistPlotter::ReadCuts(std::string filename) +{ /*! \fn void ReadCuts() \brief Reads a list of cuts from a file. The file must have the format below, two columns - Column#1 - path to a file that contains a single TCutG object named "CUTG", the default name in ROOT. @@ -377,27 +445,31 @@ void HistPlotter::ReadCuts(std::string filename) { std::ifstream infile; infile.open(filename); std::string cutfilename, cutname; - for(std::string line; std::getline(infile, line); ) { - if(line.size()!=0 && line[0]=='#') - ; //don't do anything with '#' lines - else { + for (std::string line; std::getline(infile, line);) + { + if (line.size() != 0 && line[0] == '#') + ; // don't do anything with '#' lines + else + { std::stringstream ss(line); - ss>>cutfilename>>cutname; + ss >> cutfilename >> cutname; TFile f(cutfilename.c_str()); - if(f.IsZombie()) { + if (f.IsZombie()) + { std::cerr << "Cannot open cutfile " << cutfilename << " .. skipping.." << std::endl; continue; } - TCutG *cut = (TCutG*)(f.Get("CUTG")); - cutsMap.insert(std::make_pair(cutname,static_cast(cut))); + TCutG *cut = (TCutG *)(f.Get("CUTG")); + cutsMap.insert(std::make_pair(cutname, static_cast(cut))); f.Close(); - } //else - }//for loop + } // else + } // for loop infile.close(); } -void HistPlotter::PrintObjects() { +void HistPlotter::PrintObjects() +{ /* void PrintObjects() Prints the contents of the unordered_maps oMap and cutsMap to facilitate debugging @@ -405,11 +477,13 @@ void HistPlotter::PrintObjects() { */ std::cout << "Type | Name " << std::endl; std::cout << "---- | --------------------- " << std::endl; - for(auto it=oMap.begin(); it!=oMap.end(); it++ ) { - std::cout << it->second->ClassName() << " | "<< it->first << std::endl; + for (auto it = oMap.begin(); it != oMap.end(); it++) + { + std::cout << it->second->ClassName() << " | " << it->first << std::endl; } - for(auto it=cutsMap.begin(); it!=cutsMap.end(); it++ ) { - std::cout << it->second->ClassName() << " | "<< it->first << std::endl; + for (auto it = cutsMap.begin(); it != cutsMap.end(); it++) + { + std::cout << it->second->ClassName() << " | " << it->first << std::endl; } std::cout << "---- | --------------------- " << std::endl; } diff --git a/TrackRecon.C b/TrackRecon.C index df4c67a..6dd6651 100644 --- a/TrackRecon.C +++ b/TrackRecon.C @@ -56,7 +56,9 @@ bool process_alpha_proton_scattering = false, // --- Geometry, Calibration, & Model Variables --- double source_vertex = 53.0, - z_entrance = -174.3 - 9.7 - 100.0, + // z_entrance = -174.3 - 9.7 - 100.0, + z_entrance = -174.3 - 9.7 - 270.0, // new measurement of the chamber length puts the chamber at + // 1175mm instead of 1105, plus some part of the window actually lies outside the chamber dither_sigma = 8.0, dither_sigma_c0 = 16.0, cathode_gain = 1.0, @@ -511,6 +513,8 @@ void TrackRecon::Begin(TTree * /*tree*/) else plotter = new HistPlotter("Analyzer_SX3.root", "TFILE"); + plotter->set_barrier_limit(getenv("FLUSH_BARRIER") ? std::atoll(getenv("FLUSH_BARRIER")) : 50000); + if (getenv("reactiondata")) { reactiondata = std::atoi(getenv("reactiondata")); @@ -1008,8 +1012,46 @@ inline void pcEnergyCalibrationAccumulateProton(const std::vector &PC_Eve } } +// Reads VmRSS (resident memory, MB) for this process from /proc/self/status. +// Returns -1.0 if unavailable (e.g. non-Linux) so callers can skip the check. +inline double currentRSS_MB() +{ + std::ifstream statusFile("/proc/self/status"); + std::string line; + while (std::getline(statusFile, line)) + { + if (line.compare(0, 6, "VmRSS:") == 0) + { + std::istringstream iss(line.substr(6)); + double kb = -1.0; + iss >> kb; + return kb > 0.0 ? kb / 1024.0 : -1.0; + } + } + return -1.0; +} + Bool_t TrackRecon::Process(Long64_t entry) { + + static const double maxRSS_MB = getenv("MAX_RSS_MB") ? std::atof(getenv("MAX_RSS_MB")) : 0.0; + static const Long64_t checkStride = getenv("MEMCHECK_STRIDE") ? std::atoll(getenv("MEMCHECK_STRIDE")) : 5000; + static Long64_t processedCount = 0; + ++processedCount; + + if (maxRSS_MB > 0.0 && (processedCount % checkStride == 0)) + { + double rss = currentRSS_MB(); + if (rss > 0.0 && rss > maxRSS_MB) + { + std::cout << "MAX_RSS_MB (" << maxRSS_MB << ") exceeded (RSS=" << rss + << " MB) at entry " << entry << " -- forcing a cache flush and continuing." << std::endl; + plotter->force_flush_caches(); + } + } + + plotter->barrier_increment(); + hitPos.Clear(); qqqenergy = -1; qqqtimestamp = -1; diff --git a/run_27Al.sh b/run_27Al.sh index 4143c4e..a443fe6 100644 --- a/run_27Al.sh +++ b/run_27Al.sh @@ -38,7 +38,7 @@ process_run() { export -f process_run echo "Starting parallel processing..." -time parallel --bar -j 6 process_run ::: {24..41} +# time parallel --bar -j 6 process_run ::: {24..41} time parallel --bar -j 8 process_run ::: {50..59} # time parallel --bar -j 4 process_run ::: 62 63 66 67 68 # time parallel --bar -j 1 process_run ::: 73