/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt SPDX-License-Identifier: GPL-3.0-only Authors: Sergey Gorbunov, Sergei Zharko [committer] */ /// \file L1InitManager.cxx /// \brief Input parameters management class for L1Algo /// \since 19.01.2022 #include "L1InitManager.h" #include <boost/archive/binary_iarchive.hpp> #include <boost/archive/binary_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> #include <algorithm> #include <fstream> #include <sstream> #include "L1Algo.h" #include "L1Assert.h" using L1Constants::clrs::kCL; // end colored log using L1Constants::clrs::kGNb; // bold green log using L1Constants::clrs::kRDb; // bold red log // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::AddStation(const L1BaseStationInfo& inStation) { // TODO: SZh 15.08.2023: Replace L1MASSERT with throw logic_error L1MASSERT(0, fInitController.GetFlag(EInitKey::kActiveDetectorIDs), "Attempt to add a station info before the active detectors set had been initialized"); // Check, if the detector subsystem for this station is active if (fActiveDetectorIDs.find(inStation.GetDetectorID()) != fActiveDetectorIDs.end()) { fvStationInfo.push_back(inStation); } } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::CheckInit() { this->CheckCAIterationsInit(); this->CheckStationsInfoInit(); } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::ClearSetupInfo() { // Clear stations set and a thickness map fvStationInfo.clear(); std::fill(fParameters.fThickMap.begin(), fParameters.fThickMap.end(), L1Material()); fInitController.SetFlag(EInitKey::kStationsInfo, false); // Set number of stations do default values std::fill(fParameters.fvFirstGeoId.begin(), fParameters.fvFirstGeoId.end(), 0); std::fill(fParameters.fvLocalToGeoIdMap.begin(), fParameters.fvLocalToGeoIdMap.end(), 0); std::fill(fParameters.fvGeoToActiveMap.begin(), fParameters.fvGeoToActiveMap.end(), 0); std::fill(fParameters.fvActiveToGeoMap.begin(), fParameters.fvActiveToGeoMap.end(), 0); fParameters.fNstationsActiveTotal = -1; fInitController.SetFlag(EInitKey::kStationLayoutInitialized, false); // Clear active detectors fActiveDetectorIDs.clear(); fInitController.SetFlag(EInitKey::kActiveDetectorIDs, false); // Clear field info fParameters.fVertexFieldRegion = L1FieldRegion(); fParameters.fVertexFieldValue = L1FieldValue(); fInitController.SetFlag(EInitKey::kPrimaryVertexField, false); // Clear target position std::fill(fParameters.fTargetPos.begin(), fParameters.fTargetPos.end(), L1Utils::kNaN); fTargetZ = 0.; fInitController.SetFlag(EInitKey::kTargetPos, false); // Clear field function fFieldFunction = L1FieldFunction_t([](const double(&)[3], double(&)[3]) {}); fInitController.SetFlag(EInitKey::kFieldFunction, false); // Clear other flags fParameters.fTrackingLevel = 0; fParameters.fGhostSuppression = 0; fParameters.fMomentumCutOff = 0; fInitController.SetFlag(EInitKey::kTrackingLevel, false); fInitController.SetFlag(EInitKey::kGhostSuppression, false); fInitController.SetFlag(EInitKey::kMomentumCutOff, false); fParameters.fDevIsIgnoreHitSearchAreas = false; fParameters.fDevIsUseOfOriginalField = false; fParameters.fDevIsMatchDoubletsViaMc = false; fParameters.fDevIsMatchTripletsViaMc = false; fParameters.fDevIsExtendTracksViaMc = false; fParameters.fDevIsSuppressOverlapHitsViaMc = false; } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::ClearCAIterations() { fParameters.fCAIterations.clear(); fCAIterationsNumberCrosscheck = -1; fInitController.SetFlag(EInitKey::kCAIterations, false); fInitController.SetFlag(EInitKey::kCAIterationsNumberCrosscheck, false); } // ---------------------------------------------------------------------------------------------------------------------- // NOTE: this function should be called once in the SendParameters bool L1InitManager::FormParametersContainer() { // Read configuration files LOG(info) << "L1InitManager: reading parameter configuration ..."; try { fConfigRW.Read(); } catch (const std::runtime_error& err) { LOG(error) << "L1InitManager: reading parameter configuration ... \033[1;31mfail\033[0m. Reason: " << err.what(); return false; } if (!fParameters.fDevIsParSearchWUsed) { fInitController.SetFlag(EInitKey::kSearchWindows, true); } // Apply magnetic field to the station info objects std::for_each(fvStationInfo.begin(), fvStationInfo.end(), [&](auto& st) { st.SetFieldFunction(fFieldFunction); }); // Check initialization this->CheckInit(); if (!fInitController.IsFinalized()) { LOG(error) << "L1InitManager: Attempt to form parameters container before all necessary fields were initialized" << fInitController.ToString(); return false; } { // Form array of stations auto destIt = fParameters.fStations.begin(); for (const auto& station : fvStationInfo) { if (!station.GetTrackingStatus()) { continue; } *destIt = station.GetL1Station(); ++destIt; } } { // Form array of material map auto destIt = fParameters.fThickMap.begin(); for (auto& station : fvStationInfo) { if (!station.GetTrackingStatus()) { continue; } *destIt = std::move(station.TakeMaterialMap()); ++destIt; } } // Check the consistency of the parameters object. If object inconsistent, it throws std::logic_error try { fParameters.CheckConsistency(); } catch (const std::logic_error& err) { LOG(error) << "L1InitManager: parameters container consistency check failed. Reason: " << err.what(); return false; } return true; } // ---------------------------------------------------------------------------------------------------------------------- // int L1InitManager::GetNstationsActive() const { LOG_IF(fatal, !fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) << "L1InitManager: number of active stations cannot be accessed until the station layout is initialized"; return fParameters.GetNstationsActive(); } // ---------------------------------------------------------------------------------------------------------------------- // int L1InitManager::GetNstationsActive(L1DetectorID detectorID) const { LOG_IF(fatal, !fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) << "L1InitManager: number of active stations cannot be accessed until the station layout is initialized"; return fParameters.GetNstationsActive(detectorID); } // ---------------------------------------------------------------------------------------------------------------------- // int L1InitManager::GetNstationsGeometry() const { LOG_IF(fatal, !fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) << "L1InitManager: number of geometry stations cannot be accessed until the station layout is initialized"; return fParameters.GetNstationsGeometry(); } // ---------------------------------------------------------------------------------------------------------------------- // int L1InitManager::GetNstationsGeometry(L1DetectorID detectorID) const { LOG_IF(fatal, !fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) << "L1InitManager: number of geometry stations cannot be accessed until the station layout is initialized"; return fParameters.GetNstationsGeometry(detectorID); } // ---------------------------------------------------------------------------------------------------------------------- // std::vector<L1BaseStationInfo>& L1InitManager::GetStationInfo() { LOG_IF(fatal, !fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) << "L1InitManager: station info container cannot be accessed until the station layout is initialized"; return fvStationInfo; } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::InitStationLayout() { std::sort(fvStationInfo.begin(), fvStationInfo.end()); for (const auto& aStation : fvStationInfo) { ++fParameters.fvFirstGeoId[static_cast<int>(aStation.GetDetectorID()) + 1]; } for (int iDet = 1; iDet < static_cast<int>(fParameters.fvFirstGeoId.size()); ++iDet) { fParameters.fvFirstGeoId[iDet + 1] += fParameters.fvFirstGeoId[iDet]; } fParameters.fNstationsActiveTotal = 0; for (int iStGeo = 0; iStGeo < static_cast<int>(fvStationInfo.size()); ++iStGeo) { const auto& aStation = fvStationInfo[iStGeo]; int iDet = static_cast<int>(aStation.GetDetectorID()); int iStLocal = aStation.GetStationID(); // Fill geo -> local map fParameters.fvLocalToGeoIdMap[fParameters.fvFirstGeoId[iDet] + iStLocal] = iStGeo; // Fill geo <-> active map int iStActive = aStation.GetTrackingStatus() ? fParameters.fNstationsActiveTotal++ : -1; fParameters.fvGeoToActiveMap[iStGeo] = iStActive; if (iStActive > -1) { fParameters.fvActiveToGeoMap[iStActive] = iStGeo; } } fInitController.SetFlag(EInitKey::kStationLayoutInitialized, true); } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::InitTargetField(double zStep) { if (fInitController.GetFlag(EInitKey::kPrimaryVertexField)) { LOG(warn) << "L1InitManager::InitTargetField: attempt to reinitialize the field value and field region " << "near target. Ignore"; return; } // Check for field function L1MASSERT(0, fInitController.GetFlag(EInitKey::kFieldFunction), "Attempt to initialize the field value and field region near target before initializing field function"); // Check for target defined L1MASSERT( 0, fInitController.GetFlag(EInitKey::kTargetPos), "Attempt to initialize the field value and field region near target before the target position initialization"); constexpr int nDimensions {3}; constexpr int nPointsNodal {3}; std::array<double, nPointsNodal> inputNodalZ {fTargetZ, fTargetZ + zStep, fTargetZ + 2. * zStep}; std::array<L1FieldValue, nPointsNodal> B {}; std::array<fvec, nPointsNodal> z {}; // loop over nodal points for (int idx = 0; idx < nPointsNodal; ++idx) { double point[nDimensions] {0., 0., inputNodalZ[idx]}; double field[nDimensions] {}; fFieldFunction(point, field); z[idx] = inputNodalZ[idx]; B[idx].x = field[0]; B[idx].y = field[1]; B[idx].z = field[2]; } // loop over nodal points: end fParameters.fVertexFieldRegion.Set(B[0], z[0], B[1], z[1], B[2], z[2]); fParameters.fVertexFieldValue = B[0]; fInitController.SetFlag(EInitKey::kPrimaryVertexField); } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::PushBackCAIteration(const L1CAIteration& iteration) { // TODO: probably some checks must be inserted here (S.Zharko) bool control = fInitController.GetFlag(EInitKey::kCAIterationsNumberCrosscheck); L1MASSERT(0, control, //fInitController.GetFlag(EInitKey::kCAIterationsNumberCrosscheck), "Attempt to push back a CA track finder iteration before the number of iterations was defined"); fParameters.fCAIterations.push_back(iteration); } // --------------------------------------------------------------------------------------------------------------------- // void L1InitManager::ReadParametersObject(const std::string& fileName) { // Open input binary file std::ifstream ifs(fileName, std::ios::binary); if (!ifs) { LOG(fatal) << "L1InitManager: parameters data file \"" << kGNb << fileName << kCL << "\" was not found"; } // Get L1InputData object try { boost::archive::binary_iarchive ia(ifs); ia >> fParameters; } catch (const std::exception&) { LOG(fatal) << "L1InitManager: parameters file \"" << kGNb << fileName << kCL << "\" has incorrect data format or was corrupted"; } } // --------------------------------------------------------------------------------------------------------------------- // void L1InitManager::ReadSearchWindows(const std::string& fileName) { // Open input binary file std::ifstream ifs(fileName); if (!ifs) { LOG(fatal) << "L1InitManager: search window file \"" << fileName << "\" was not found"; } try { boost::archive::text_iarchive ia(ifs); int nPars = -1; int nWindows = -1; ia >> nPars; assert(nPars == 1); // Currently only the constant windows are available ia >> nWindows; std::stringstream errMsg; for (int iW = 0; iW < nWindows; ++iW) { L1SearchWindow swBuffer; ia >> swBuffer; int iStationID = swBuffer.GetStationID(); int iTrackGrID = swBuffer.GetTrackGroupID(); if (iStationID < 0 || iStationID > L1Constants::size::kMaxNstations) { errMsg << "\t- wrong station id for entry " << iW << ": " << iStationID << " (should be between 0 and " << L1Constants::size::kMaxNstations << ")\n"; } if (iTrackGrID < 0 || iTrackGrID > L1Constants::size::kMaxNtrackGroups) { errMsg << "\t- wrong track group id for entry " << iW << ": " << iTrackGrID << " (should be between 0 and " << L1Constants::size::kMaxNtrackGroups << ")\n"; } fParameters.fSearchWindows[iTrackGrID * L1Constants::size::kMaxNstations + iStationID] = swBuffer; } if (errMsg.str().size()) { LOG(fatal) << "L1InitManager: some errors occurred while reading search windows: " << errMsg.str(); } } catch (const std::exception&) { LOG(fatal) << "L1InitManager: search windows file \"" << fileName << "\" has incorrect data format or was corrupted"; } fInitController.SetFlag(EInitKey::kSearchWindows, true); } // --------------------------------------------------------------------------------------------------------------------- // bool L1InitManager::SendParameters(L1Algo* pAlgo) { assert(pAlgo); pAlgo->ReceiveParameters(std::move(fParameters)); LOG(info) << "L1InitManager: parameters object was sent to the tracking algorithm"; return true; } // --------------------------------------------------------------------------------------------------------------------- // bool L1InitManager::SendParameters(L1Parameters& destination) { destination = std::move(fParameters); LOG(info) << "L1InitManager: parameters object was sent to an external destination"; return true; } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::SetActiveDetectorIDs(const L1DetectorIDSet_t& detectorIDs) { // TODO: To think about redefinition possibilities: should it be allowed or not? (S.Zh.) fActiveDetectorIDs = detectorIDs; fInitController.SetFlag(EInitKey::kActiveDetectorIDs); } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::SetCAIterationsNumberCrosscheck(int nIterations) { fCAIterationsNumberCrosscheck = nIterations; L1Vector<L1CAIteration>& iterationsContainer = fParameters.fCAIterations; // NOTE: should be called to prevent multiple copies of objects between the memory reallocations iterationsContainer.reserve(nIterations); fInitController.SetFlag(EInitKey::kCAIterationsNumberCrosscheck); } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::SetFieldFunction(const L1FieldFunction_t& fieldFunction) { if (!fInitController.GetFlag(EInitKey::kFieldFunction)) { fFieldFunction = fieldFunction; fInitController.SetFlag(EInitKey::kFieldFunction); } else { LOG(warn) << "L1InitManager::SetFieldFunction: attempt to reinitialize the field function. Ignored"; } } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::SetGhostSuppression(int ghostSuppression) { if (fInitController.GetFlag(EInitKey::kGhostSuppression)) { LOG(warn) << "L1InitManager::SetGhostSuppression: attempt of reinitializating the ghost suppresion flag. Ignore"; return; } fParameters.fGhostSuppression = ghostSuppression; fInitController.SetFlag(EInitKey::kGhostSuppression); } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::SetMomentumCutOff(float momentumCutOff) { if (fInitController.GetFlag(EInitKey::kMomentumCutOff)) { LOG(warn) << "L1InitManager::SetMomentumCutOff: attempt of reinitializating the momentum cutoff value. Ignore"; return; } fParameters.fMomentumCutOff = momentumCutOff; fInitController.SetFlag(EInitKey::kMomentumCutOff); } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::SetTargetPosition(double x, double y, double z) { if (fInitController.GetFlag(EInitKey::kTargetPos)) { LOG(warn) << "L1InitManager::SetTargetPosition: attempt to reinitialize the target position. Ignore"; return; } /// Fill fvec target fields fParameters.fTargetPos[0] = x; fParameters.fTargetPos[1] = y; fParameters.fTargetPos[2] = z; /// Set additional field for z component in double precision fTargetZ = z; fInitController.SetFlag(EInitKey::kTargetPos); } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::SetTrackingLevel(int trackingLevel) { if (fInitController.GetFlag(EInitKey::kTrackingLevel)) { LOG(warn) << "L1InitManager::SetTrackingLevel: attempt of reinitialization the tracking level. Ignore"; return; } fParameters.fTrackingLevel = trackingLevel; fInitController.SetFlag(EInitKey::kTrackingLevel); } // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::WriteParametersObject(const std::string& fileName) const { // Open output binary file std::ofstream ofs(fileName, std::ios::binary); if (!ofs) { LOG(error) << "L1InitManager: failed opening file \"" << kGNb << fileName << kCL << "\" to write parameters object"; return; } LOG(info) << "L1InitManager: writing CA parameters object to file \"" << kGNb << fileName << '\"' << kCL; // Serialize L1Parameters object and write boost::archive::binary_oarchive oa(ofs); oa << fParameters; } // // INIT CHECKERS // // ---------------------------------------------------------------------------------------------------------------------- // void L1InitManager::CheckCAIterationsInit() { // // 1) Check number of iterations // bool ifInitPassed = true; if (!fInitController.GetFlag(EInitKey::kCAIterations)) { int nIterationsActual = fParameters.fCAIterations.size(); int nIterationsExpected = fCAIterationsNumberCrosscheck; if (nIterationsActual != nIterationsExpected) { LOG(warn) << "L1InitManager::CheckCAIterations: incorrect number of iterations registered: " << nIterationsActual << " of " << nIterationsExpected << " expected"; ifInitPassed = false; } } fInitController.SetFlag(EInitKey::kCAIterations, ifInitPassed); } // ---------------------------------------------------------------------------------------------------------------------- // TODO: REWRITE! and add const qualifier (S.Zharko) void L1InitManager::CheckStationsInfoInit() { bool ifInitPassed = true; if (!fInitController.GetFlag(EInitKey::kStationsInfo)) { // (1) Check the stations themselves bool bStationsFinalized = std::all_of(fvStationInfo.begin(), fvStationInfo.end(), [](const auto& st) { return st.GetInitController().IsFinalized(); }); if (!bStationsFinalized) { LOG(fatal) << "At least one of the L1BaseStationInfo objects is not finalized"; } // (2) Check for maximum allowed number of stations if (fParameters.GetNstationsGeometry() > L1Constants::size::kMaxNstations) { LOG(fatal) << "Actual total number of registered stations in geometry (" << fParameters.GetNstationsGeometry() << ") is larger then possible (" << L1Constants::size::kMaxNstations << "). Please, select another set of active tracking detectors or recompile the code with enlarged" << " L1Constants::size::kMaxNstations value"; } } fInitController.SetFlag(EInitKey::kStationsInfo, ifInitPassed); }