From 44db5a9d402ad7fc2d03d217be76baeb6c60c862 Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Tue, 30 Aug 2022 19:27:46 +0200 Subject: [PATCH] L1: added input data IO functionality --- reco/L1/CbmL1.cxx | 115 ++++++++++++++++++++--------- reco/L1/CbmL1.h | 8 +- reco/L1/CbmL1ReadEvent.cxx | 3 + reco/L1/L1Algo/L1Hit.h | 22 ++++++ reco/L1/L1Algo/L1IODataManager.cxx | 46 ++++++++++++ reco/L1/L1Algo/L1IODataManager.h | 8 ++ reco/L1/L1Algo/L1InputData.h | 15 +++- reco/L1/L1Algo/L1Vector.h | 14 ++++ 8 files changed, 191 insertions(+), 40 deletions(-) diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx index d8e8386fb4..27655f2603 100644 --- a/reco/L1/CbmL1.cxx +++ b/reco/L1/CbmL1.cxx @@ -425,30 +425,6 @@ InitStatus CbmL1::Init() fInitManager.SetNstations(L1DetectorID::kTrd, fNTrdStationsGeom); fInitManager.SetNstations(L1DetectorID::kTof, fNTofStationsGeom); - { - if (fSTAPDataMode % 2 == 1) { // 1,3 - LOG(fatal) << "CbmL1::Init: geo vector was removed, currently data cannot be written to a text-file"; - // TODO: Rewrite parameters i/o into L1InitManager (S.Zharko, 12.05.2022) - //WriteSTAPGeoData(geo); - }; - //if(fSTAPDataMode >= 2){ // 2,3 - // int ind2, ind = geo.size(); - // ReadSTAPGeoData(geo, ind2); - // if (ind2 != ind) LOG(error) << "-E- CbmL1: Read geometry from file " << fSTAPDataDir + "geo_algo.txt was NOT successful."; - //}; - } - - if (fSTAPDataMode >= 2) { // 2,3 - LOG(fatal) << "CbmL1::Init: geo vector was removed, currently data cannot be read from a text-file. " - << "Please, run CbmL1 task with STAPDataMode option < 2"; - // TODO: Rewrite parameters i/o into L1InitManager (S.Zharko, 12.05.2022) - //int ind2, ind = geo.size(); - //ReadSTAPGeoData(geo, ind2); - //if (ind2 != ind) - // LOG(error) << "-E- CbmL1: Read geometry from file " << fSTAPDataDir + "geo_algo.txt was NOT successful."; - } - - /**************************** ** Material budget input ** ****************************/ @@ -952,10 +928,6 @@ void CbmL1::Reconstruct(CbmEvent* event) FstHitinTs = 0; } - if (fSTAPDataMode >= 2) { // 2,3 - LOG(fatal) << "L1: Sorry, at the moment standalone tracking module is unavailable. This functionality will be " - << "reimplemented soon."; - } // ----- Read data from branches and send data from IODataManager to L1Algo ---------------------------------------- ReadEvent(TsStart, TsLength, TsOverlap, FstHitinTs, areDataLeft, event); @@ -1302,36 +1274,109 @@ void CbmL1::IdealTrackFinder() /// ----- STandAlone Package service-functions ----------------------------- +// --------------------------------------------------------------------------------------------------------------------- +// void CbmL1::WriteSTAPGeoData(const L1Vector<float>& /*geo_*/) { LOG(fatal) << "CbmL1: Running in standalone mode is not available at the moment. It will be updated soon..."; } -void CbmL1::WriteSTAPAlgoData() // must be called after ReadEvent +// --------------------------------------------------------------------------------------------------------------------- +// +void CbmL1::WriteAlgoInputData() // must be called after ReadEvent { - LOG(fatal) << "CbmL1: Running in standalone mode is not available at the moment. It will be updated soon..."; + // Check if output directory exists + if (!boost::filesystem::exists(fSTAPDataDir.Data())) { + LOG(warn) << "CbmL1: directory " << fSTAPDataDir.Data() + << " (full path: " << boost::filesystem::system_complete(fSTAPDataDir.Data()).string() + << ") for writing L1AlgoData object does not exist"; + fSTAPDataDir = "."; + } + + if (!boost::filesystem::is_directory(fSTAPDataDir.Data())) { + LOG(warn) << "CbmL1: path " << fSTAPDataDir.Data() + << " (full path: " << boost::filesystem::system_complete(fSTAPDataDir.Data()).string() + << ") is not a directory"; + fSTAPDataDir = "."; + } + + // Define output directory + std::string hitsDir = (fSTAPDataDir + "/tracking_input_hits").Data(); + if (!boost::filesystem::exists(hitsDir)) { boost::filesystem::create_directories(hitsDir); } + + // Get filename + static int iEvent = 0; + boost::filesystem::path p = (FairRunAna::Instance()->GetUserOutputFileName()).Data(); + std::string prefix = p.filename().string(); + std::string suffix = "reco.root"; + prefix.erase(prefix.find("reco.root")); + std::string filename = hitsDir + "/" + prefix + "event" + std::to_string(iEvent) + ".L1InputData.dat"; + ++iEvent; + + // Write file + L1_SHOW(filename); + fIODataManager.WriteInputData(filename); } +// --------------------------------------------------------------------------------------------------------------------- +// void CbmL1::WriteSTAPPerfData() // must be called after ReadEvent { LOG(fatal) << "CbmL1: Running in standalone mode is not available at the moment. It will be updated soon..."; -} // void CbmL1::WriteSTAPPerfData() +} -void CbmL1::ReadSTAPGeoData(L1Vector<fscal>& /*geo_*/, int& /*size*/) +// --------------------------------------------------------------------------------------------------------------------- +// +void CbmL1::ReadSTAPGeoData() { LOG(fatal) << "CbmL1: Running in standalone mode is not available at the moment. It will be updated soon..."; -} // void CbmL1::ReadSTAPGeoData(void* geo_, int &size) +} -void CbmL1::ReadSTAPAlgoData() +// --------------------------------------------------------------------------------------------------------------------- +// +void CbmL1::ReadAlgoInputData() { - LOG(fatal) << "CbmL1: Running in standalone mode is not available at the moment. It will be updated soon..."; + // Check if output directory exists + if (!boost::filesystem::exists(fSTAPDataDir.Data())) { + LOG(warn) << "CbmL1: directory " << fSTAPDataDir.Data() + << " (full path: " << boost::filesystem::system_complete(fSTAPDataDir.Data()).string() + << ") for reading L1AlgoData object does not exist"; + fSTAPDataDir = "."; + } + + if (!boost::filesystem::is_directory(fSTAPDataDir.Data())) { + LOG(warn) << "CbmL1: path " << fSTAPDataDir.Data() + << " (full path: " << boost::filesystem::system_complete(fSTAPDataDir.Data()).string() + << ") is not a directory"; + fSTAPDataDir = "."; + } + + // Define output directory + std::string hitsDir = fSTAPDataDir.Data(); + + // Get filename + static int iEvent = 0; + boost::filesystem::path p = (FairRunAna::Instance()->GetUserOutputFileName()).Data(); + std::string prefix = p.filename().string(); + std::string suffix = "reco.root"; + prefix.erase(prefix.find("reco.root")); + std::string filename = hitsDir + "/" + prefix + "event" + std::to_string(iEvent) + ".L1InputData.dat"; + ++iEvent; + + // Write file + L1_SHOW(filename); + fIODataManager.ReadInputData(filename); } +// --------------------------------------------------------------------------------------------------------------------- +// void CbmL1::ReadSTAPPerfData() { LOG(fatal) << "CbmL1: Running in standalone mode is not available at the moment. It will be updated soon..."; } +// --------------------------------------------------------------------------------------------------------------------- +// void CbmL1::WriteSIMDKFData() { // TODO: Must be totally reimplemented (S.Zharko) diff --git a/reco/L1/CbmL1.h b/reco/L1/CbmL1.h index eaf828052b..db153bfec3 100644 --- a/reco/L1/CbmL1.h +++ b/reco/L1/CbmL1.h @@ -360,11 +360,11 @@ private: /// STandAlone Package service-functions void WriteSTAPGeoData(const L1Vector<float>& geo); // create geo_algo.dat - void WriteSTAPAlgoData(); // create data_algo.dat + void WriteAlgoInputData(); // create data_algo.dat void WriteSTAPPerfData(); // create data_perfo.dat //void ReadSTAPGeoData(L1Vector<float> geo, int &size); - void ReadSTAPGeoData(L1Vector<float>& geo, int& size); - void ReadSTAPAlgoData(); + void ReadSTAPGeoData(); + void ReadAlgoInputData(); void ReadSTAPPerfData(); /// SIMD KF Banchmark service-functions void WriteSIMDKFData(); @@ -387,6 +387,8 @@ private: inline Double_t dFEI(int file, int event, int idx) { return (1000 * idx) + file + (0.0001 * event); } +private: + std::string fInputDataFilename = ""; ///< File name to read/write input hits // *************************** // ** Member variables list ** diff --git a/reco/L1/CbmL1ReadEvent.cxx b/reco/L1/CbmL1ReadEvent.cxx index f781e68b0e..ede3970530 100644 --- a/reco/L1/CbmL1ReadEvent.cxx +++ b/reco/L1/CbmL1ReadEvent.cxx @@ -1185,6 +1185,9 @@ void CbmL1::ReadEvent(float& TsStart, float& TsLength, float& /*TsOverlap*/, int if (fVerbose >= 1) cout << "ReadEvent: mvd and sts are saved." << endl; // ----- Send data from IODataManager to L1Algo -------------------------------------------------------------------- + if (1 == fSTAPDataMode) { WriteAlgoInputData(); } + if (2 == fSTAPDataMode) { ReadAlgoInputData(); } + // TODO: SZh: If we read data from file, we don't need to collect them above. This should be addressed fIODataManager.SendInputData(fpAlgo); if (fPerformance) { diff --git a/reco/L1/L1Algo/L1Hit.h b/reco/L1/L1Algo/L1Hit.h index 4568b1eda8..acdea6e3c4 100644 --- a/reco/L1/L1Algo/L1Hit.h +++ b/reco/L1/L1Algo/L1Hit.h @@ -12,6 +12,8 @@ #ifndef L1Hit_h #define L1Hit_h +#include <boost/serialization/access.hpp> + #include "L1Constants.h" using L1HitIndex_t = unsigned /*short*/ int; ///< Index of L1Hit @@ -23,6 +25,8 @@ using L1StripIndex_t = unsigned /*short*/ int; ///< Index of the station strip /// Note: V is a transverse coordinate of the hit in the axis perpendicular to the back strip /// class /*alignas(L1Constants::misc::kAlignment)*/ L1Hit { + friend class boost::serialization::access; + public: L1StripIndex_t f {0}; ///< front hit key index L1StripIndex_t b {0}; ///< back hit key index @@ -40,6 +44,24 @@ public: int ID = 0; ///< index of hit before hits sorting int iSt = 0; ///< index of station in the active stations array // TODO: Test speed penalty of using iSt index + +private: + /// Serialization method, used to save L1Hit objects into binary or text file in a defined order + template<class Archive> + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar& f; + ar& b; + ar& u; + ar& v; + ar& t; + ar& z; + ar& du; + ar& dv; + ar& dt; + ar& ID; + ar& iSt; + } }; #endif diff --git a/reco/L1/L1Algo/L1IODataManager.cxx b/reco/L1/L1Algo/L1IODataManager.cxx index 2b7f7d5682..86bc8a7662 100644 --- a/reco/L1/L1Algo/L1IODataManager.cxx +++ b/reco/L1/L1Algo/L1IODataManager.cxx @@ -9,6 +9,11 @@ #include "L1IODataManager.h" +#include <boost/archive/binary_iarchive.hpp> +#include <boost/archive/binary_oarchive.hpp> + +#include <fstream> + #include "L1Algo.h" // --------------------------------------------------------------------------------------------------------------------- @@ -32,6 +37,28 @@ bool L1IODataManager::SendInputData(L1Algo* pAlgo) return false; } +// --------------------------------------------------------------------------------------------------------------------- +// +void L1IODataManager::ReadInputData(const std::string& fileName) +{ + // Reset input data object + this->ResetInputData(); + LOG(info) << "L1: Input data will be read from file \"" << fileName << "\""; + + // Open input binary file + std::ifstream ifs(fileName, std::ios::binary); + if (!ifs) { LOG(fatal) << "L1: input data reader: data file \"" << fileName << "\" was not found"; } + + // Get L1InputData object + try { + boost::archive::binary_iarchive ia(ifs); + ia >> fInputData; + } + catch (const std::exception&) { + LOG(fatal) << "L1: input data reader: data file \"" << fileName << "\" has incorrect data format or was corrupted"; + } +} + // --------------------------------------------------------------------------------------------------------------------- // void L1IODataManager::ResetInputData() noexcept @@ -66,3 +93,22 @@ void L1IODataManager::SetStartStopHitIndexes() // --------------------------------------------------------------------------------------------------------------------- // +void L1IODataManager::WriteInputData(const std::string& fileName) const +{ + // Check current data object for consistency + if (!CheckInputData<L1Constants::control::kInputDataQaLevel>()) { + LOG(error) << "L1: input data writer: attempt to write invalid input data object to file \"" << fileName << "\""; + return; + } + + // Open output binary file + std::ofstream ofs(fileName, std::ios::binary); + if (!ofs) { + LOG(error) << "L1: input data writer: failed opening file \"" << fileName << " for writing input data\""; + return; + } + + // Serialize L1InputData object and write + boost::archive::binary_oarchive oa(ofs); + oa << fInputData; +} diff --git a/reco/L1/L1Algo/L1IODataManager.h b/reco/L1/L1Algo/L1IODataManager.h index 98fa077937..a59dfcaa30 100644 --- a/reco/L1/L1Algo/L1IODataManager.h +++ b/reco/L1/L1Algo/L1IODataManager.h @@ -49,6 +49,10 @@ public: /// Move assignment operator L1IODataManager& operator=(L1IODataManager&& other) = delete; + /// Reads input data object from boost-serialized binary file + /// \param fileName Name of input file + void ReadInputData(const std::string& fileName); + /// Reserve number of hits /// \param nHits Number of hits to be stored /// \note If one does not call this method, the underlying vector of hits will be filled with the time penalty @@ -70,6 +74,10 @@ public: /// \return Success flag bool SendInputData(L1Algo* pAlgo); + /// Writes input data object to boost-serialized binary file + /// \param fileName Name of input file + void WriteInputData(const std::string& fileName) const; + private: /// Sets the start and stop indexes vs. station index void SetStartStopHitIndexes(); diff --git a/reco/L1/L1Algo/L1InputData.h b/reco/L1/L1Algo/L1InputData.h index 88a204d045..d7c2569110 100644 --- a/reco/L1/L1Algo/L1InputData.h +++ b/reco/L1/L1Algo/L1InputData.h @@ -10,13 +10,15 @@ #ifndef L1InputData_h #define L1InputData_h 1 +#include <boost/serialization/access.hpp> +#include <boost/serialization/array.hpp> + #include <array> #include "L1Constants.h" #include "L1Hit.h" #include "L1Vector.h" - /// Class L1InputData represents a block of the input data to the L1 tracking algorithm per event or time slice. /// Filling of the L1InputData is carried out with L1IODataManager class /// @@ -27,7 +29,7 @@ public: // ************************** friend class L1IODataManager; ///< Class which fills the L1InputData object for each event or time slice - + friend class boost::serialization::access; // *************************** // ** Member functions list ** @@ -85,6 +87,15 @@ private: /// Swap method void Swap(L1InputData& other) noexcept; + /// Data serialization method + template<class Archive> + void serialize(Archive& ar, const unsigned int /*versino*/) + { + ar& fvHits; + ar& fvStartHitIndexes; + ar& fvStopHitIndexes; + ar& fNhitKeys; + } // *************************** // ** Member variables list ** diff --git a/reco/L1/L1Algo/L1Vector.h b/reco/L1/L1Algo/L1Vector.h index 780a9cf125..5e5654afb8 100644 --- a/reco/L1/L1Algo/L1Vector.h +++ b/reco/L1/L1Algo/L1Vector.h @@ -14,6 +14,11 @@ #ifndef FAST_CODE #include <FairLogger.h> #endif +#include <boost/serialization/access.hpp> +#include <boost/serialization/base_object.hpp> +#include <boost/serialization/string.hpp> +#include <boost/serialization/vector.hpp> + #include <sstream> /// L1Vector class is a wrapper around std::vector. @@ -30,6 +35,8 @@ template<class T> class L1Vector : private std::vector<T> { + friend class boost::serialization::access; + public: typedef std::vector<T> Tbase; @@ -239,6 +246,13 @@ private: using Tbase::assign; // use reset() instead using Tbase::at; using Tbase::resize; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar& boost::serialization::base_object<Tbase>(*this); + ar& fName; + } }; /// -- GitLab