Skip to content
Snippets Groups Projects
CaInitManager.cxx 23.1 KiB
Newer Older
/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
   SPDX-License-Identifier: GPL-3.0-only
   Authors: Sergey Gorbunov, Sergei Zharko [committer] */

/// \file   CaInitManager.cxx
/// \brief  Input data management class for the CA tracking algorithm (implementation)
/// \since  19.01.2022
/// \author Sergei Zharko <s.zharko@gsi.de>
#include "CaInitManager.h"
#include "CaConfigReader.h"
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <algorithm>
Sergei Zharko's avatar
Sergei Zharko committed
#include <sstream>
namespace cbm::algo::ca
{
  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::AddStation(const StationInitializer& inStation) { fvStationInfo.push_back(inStation); }

  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::AddStations(const Parameters<fvec>& par)
  {
    const auto& stations = par.GetStations();
    for (int iSt = 0; iSt < par.GetNstationsActive(); ++iSt) {
      auto stationIn = Station<double>(stations[iSt]);
      // Get detector ID of the station
      auto [detId, locId] = par.GetStationIndexLocal(par.GetActiveToGeoMap()[iSt]);
      auto stationInfo    = ca::StationInitializer(detId, locId);
      stationInfo.SetStationType(stationIn.type);
      stationInfo.SetZmin(0.);  // NOTE: Deprecated (not used)
      stationInfo.SetZmax(0.);  // NOTE: Deprecated (not used)
      stationInfo.SetZref(stationIn.fZ);
      stationInfo.SetXmax(stationIn.Xmax);
      stationInfo.SetYmax(stationIn.Ymax);
      stationInfo.SetFieldStatus(stationIn.fieldStatus);
      stationInfo.SetTimeInfo(stationIn.timeInfo);
      stationInfo.SetTrackingStatus(true);
      this->AddStation(stationInfo);
    }
  }

  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::CheckInit()
  {
    this->CheckCAIterationsInit();
    this->CheckStationsInfoInit();
    fbConfigIsRead       = false;
    fbGeometryConfigLock = false;
  }

  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::ClearSetupInfo()
  {
    // Clear stations set and a thickness map
    fvStationInfo.clear();
    fInitController.SetFlag(EInitKey::kStationsInfo, false);

    // Set number of stations do default values
    this->ClearStationLayout();

    // Clear field info
    fParameters.fVertexFieldRegion = kf::FieldRegion<fvec>();
    fParameters.fVertexFieldValue  = kf::FieldValue<fvec>();
    fInitController.SetFlag(EInitKey::kPrimaryVertexField, false);

    // Clear target position
    fParameters.fTargetPos.fill(Undef<float>);
    fTargetZ = 0.;
    fInitController.SetFlag(EInitKey::kTargetPos, false);

    // Clear field function
    fFieldFunction = FieldFunction_t([](const double(&)[3], double(&)[3]) {});
    fInitController.SetFlag(EInitKey::kFieldFunction, false);

    // Clear other flags
    fParameters.fRandomSeed       = 1;
    fParameters.fGhostSuppression = 0;
    fInitController.SetFlag(EInitKey::kRandomSeed, false);
    fInitController.SetFlag(EInitKey::kGhostSuppression, false);

    fParameters.fMisalignmentX.fill(0.);
    fParameters.fMisalignmentY.fill(0.);
    fParameters.fMisalignmentT.fill(0.);

    fParameters.fDevIsIgnoreHitSearchAreas     = false;
    fParameters.fDevIsUseOfOriginalField       = false;
    fParameters.fDevIsMatchDoubletsViaMc       = false;
    fParameters.fDevIsMatchTripletsViaMc       = false;
    fParameters.fDevIsExtendTracksViaMc        = false;
    fParameters.fDevIsSuppressOverlapHitsViaMc = false;
    fParameters.fDevIsParSearchWUsed           = false;

    fbGeometryConfigLock = false;
  }

  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::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 InitManager::FormParametersContainer()
  {
    // Read configuration files
    this->ReadInputConfigs();
    if (!fbConfigIsRead) {  // Check config reading status
      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); });
    if (!fInitController.IsFinalized()) {
      LOG(error) << "ca::InitManager: 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.GetStation();
        ++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) << "ca::InitManager: parameters container consistency check failed. Reason: " << err.what();
      return false;
    }
  // --------------------------------------------------------------------------------------------------------------------
  //
  int InitManager::GetNstationsActive() const
  {
    if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
      std::stringstream msg;
      msg << "ca::InitManager: number of active stations cannot be accessed until the station layout is initialized";
      throw std::runtime_error(msg.str());
  // --------------------------------------------------------------------------------------------------------------------
  //
  int InitManager::GetNstationsActive(EDetectorID detectorID) const
  {
    if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
      std::stringstream msg;
      msg << "ca::InitManager: number of active stations cannot be accessed until the station layout is initialized";
      throw std::runtime_error(msg.str());
    }
    return fParameters.GetNstationsActive(detectorID);
  // --------------------------------------------------------------------------------------------------------------------
  //
  int InitManager::GetNstationsGeometry() const
  {
    if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
      std::stringstream msg;
      msg << "ca::InitManager: number of geometry stations cannot be accessed until the station layout is initialized";
      throw std::runtime_error(msg.str());
    }
    return fParameters.GetNstationsGeometry();
  // --------------------------------------------------------------------------------------------------------------------
  //
  int InitManager::GetNstationsGeometry(EDetectorID detectorID) const
  {
    if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
      std::stringstream msg;
      msg << "ca::InitManager: number of geometry stations cannot be accessed until the station layout is initialized";
      throw std::runtime_error(msg.str());
    }
    return fParameters.GetNstationsGeometry(detectorID);
  // --------------------------------------------------------------------------------------------------------------------
  //
  std::vector<StationInitializer>& InitManager::GetStationInfo()
  {
    if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) {
      std::stringstream msg;
      msg << "ca::InitManager: station info container cannot be accessed until the station layout is initialized";
      throw std::runtime_error(msg.str());
    }
    return fvStationInfo;
  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::InitStationLayout()
  {
    LOG(info) << "ca::InitManager::InitStationLayout(): ....";
    this->ClearStationLayout();
    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()) - 1; ++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 local -> geo map
      fParameters.fvGeoToLocalIdMap[iStGeo] = std::make_pair(aStation.GetDetectorID(), iStLocal);
      // 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);
    for (auto& aStation : fvStationInfo) {
      aStation.SetGeoLayerID(fParameters.GetStationIndexGeometry(aStation.GetStationID(), aStation.GetDetectorID()));
    }
  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::InitTargetField(double zStep)
  {
    if (fInitController.GetFlag(EInitKey::kPrimaryVertexField)) {
      LOG(warn) << "ca::InitManager::InitTargetField: attempt to reinitialize the field value and field region "
                << "near target. Ignore";
      return;
    // Check for field function
    if (!fInitController.GetFlag(EInitKey::kFieldFunction)) {
      std::stringstream msg;
      msg << "Attempt to initialize the field value and field region near target before initializing field function";
      throw std::runtime_error(msg.str());
    }
    // Check for target defined
    if (!fInitController.GetFlag(EInitKey::kTargetPos)) {
      std::stringstream msg;
      msg << "Attempt to initialize the field value and field region near target before the target position"
          << "initialization";
      throw std::runtime_error(msg.str());
    }
    constexpr int nDimensions{3};
    constexpr int nPointsNodal{3};

    std::array<double, nPointsNodal> inputNodalZ{fTargetZ, fTargetZ + zStep, fTargetZ + 2. * zStep};
    std::array<kf::FieldValue<fvec>, 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].Set(field[0], field[1], 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 InitManager::PushBackCAIteration(const Iteration& iteration)
  {
    // TODO: probably some checks must be inserted here (S.Zharko)
    if (!fInitController.GetFlag(EInitKey::kCAIterationsNumberCrosscheck)) {
      std::stringstream msg;
      msg << "Attempt to push back a CA track finder iteration before the number of iterations was defined";
      throw std::runtime_error(msg.str());
    }
    fParameters.fCAIterations.push_back(iteration);
  }

  // -------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::ReadInputConfigs()
  {
    if (!fbConfigIsRead) {
      LOG(info) << "ca::InitManager: reading parameter configuration ...";
      try {
        auto configReader = ConfigReader(this, 4);
        configReader.SetMainConfigPath(fsConfigInputMain);
        configReader.SetUserConfigPath(fsConfigInputUser);
        configReader.SetGeometryLock(fbGeometryConfigLock);
        configReader.Read();
        fbConfigIsRead = true;
        LOG(info) << "ca::InitManager: reading parameter configuration ... \033[1;32mdone\033[0m";
      }
      catch (const std::runtime_error& err) {
        LOG(error) << "ca::InitManager: reading parameter configuration ... \033[1;31mfail\033[0m. Reason: "
                   << err.what();
      }
    }
  // -------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::ReadGeometrySetup(const std::string& fileName)
  {
    // Open input binary file
    this->SetGeometrySetup(cbm::algo::kf::SetupBuilder::Load<fvec>(fileName));
  // -------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::ReadParametersObject(const std::string& fileName)
  {
    using namespace constants;
    // clrs::CL  - end colored log
    // clrs::GNb - bold green log
    // clrs::RDb - bold red log
    // Open input binary file
    std::ifstream ifs(fileName, std::ios::binary);
    if (!ifs) {
      std::stringstream msg;
      msg << "ca::InitManager: parameters data file \"" << clrs::GNb << fileName << clrs::CL << "\" was not found";
      throw std::runtime_error(msg.str());
    // Get L1InputData object
    try {
      boost::archive::binary_iarchive ia(ifs);
      ia >> fParameters;
      fbGeometryConfigLock = true;
    }
    catch (const std::exception&) {
      std::stringstream msg;
      msg << "ca::InitManager: parameters file \"" << clrs::GNb << fileName << clrs::CL
          << "\" has incorrect data format or was corrupted";
      throw std::runtime_error(msg.str());
    }
    fInitController.SetFlag(EInitKey::kStationLayoutInitialized, true);
    fInitController.SetFlag(EInitKey::kPrimaryVertexField, true);
    fInitController.SetFlag(EInitKey::kSearchWindows, true);
  // -------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::ReadSearchWindows(const std::string& fileName)
  {
    // Open input binary file
    std::ifstream ifs(fileName);
    if (!ifs) {
      std::stringstream msg;
      msg << "ca::InitManager: search window file \"" << fileName << "\" was not found";
      throw std::runtime_error(msg.str());
    }
    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) {
        SearchWindow swBuffer;
        ia >> swBuffer;
        int iStationID = swBuffer.GetStationID();
        int iTrackGrID = swBuffer.GetTrackGroupID();
        if (iStationID < 0 || iStationID > constants::size::MaxNstations) {
          errMsg << "\t- wrong station id for entry " << iW << ": " << iStationID << " (should be between 0 and "
                 << constants::size::MaxNstations << ")\n";
        }
        if (iTrackGrID < 0 || iTrackGrID > constants::size::MaxNtrackGroups) {
          errMsg << "\t- wrong track group id for entry " << iW << ": " << iTrackGrID << " (should be between 0 and "
                 << constants::size::MaxNtrackGroups << ")\n";
        }
        fParameters.fSearchWindows[iTrackGrID * constants::size::MaxNstations + iStationID] = swBuffer;
      if (errMsg.str().size()) {
        std::stringstream msg;
        msg << "ca::InitManager: some errors occurred while reading search windows: " << errMsg.str();
        throw std::runtime_error(msg.str());
      msg << "search windows file \"" << fileName << "\" has incorrect data format or was corrupted. ";
      msg << "Exception catched: " << err.what();
      throw std::runtime_error(msg.str());
    fInitController.SetFlag(EInitKey::kSearchWindows, true);
  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::SetCAIterationsNumberCrosscheck(int nIterations)
  {
    fCAIterationsNumberCrosscheck = nIterations;
    auto& 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 InitManager::SetFieldFunction(const FieldFunction_t& fieldFunction)
  {
    if (!fInitController.GetFlag(EInitKey::kFieldFunction)) {
      fFieldFunction = fieldFunction;
      fInitController.SetFlag(EInitKey::kFieldFunction);
    }
    else {
      LOG(warn) << "ca::InitManager::SetFieldFunction: attempt to reinitialize the field function. Ignored";
    }
  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::SetGhostSuppression(int ghostSuppression)
  {
    if (fInitController.GetFlag(EInitKey::kGhostSuppression)) {
      LOG(warn)
        << "ca::InitManager::SetGhostSuppression: attempt of reinitializating the ghost suppresion flag. Ignore";
      return;
    }
    fParameters.fGhostSuppression = ghostSuppression;
    fInitController.SetFlag(EInitKey::kGhostSuppression);
  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::SetRandomSeed(unsigned int seed)
  {
    if (fInitController.GetFlag(EInitKey::kRandomSeed)) {
      LOG(warn) << "ca::InitManager::SetRandomSeed: attempt of reinitializating the random seed. Ignore";
      return;
    fParameters.fRandomSeed = seed;
    fInitController.SetFlag(EInitKey::kRandomSeed);
  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::SetTargetPosition(double x, double y, double z)
  {
    if (fInitController.GetFlag(EInitKey::kTargetPos)) {
      LOG(warn) << "ca::InitManager::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);
  }

  // --------------------------------------------------------------------------------------------------------------------
  //
  Parameters<fvec>&& InitManager::TakeParameters() { return std::move(fParameters); }

  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::WriteParametersObject(const std::string& fileName) const
  {
    using constants::clrs::CL;
    using constants::clrs::GNb;
    // Open output binary file
    std::ofstream ofs(fileName, std::ios::binary);
    if (!ofs) {
      msg << "ca::InitManager: failed opening file \"" << GNb << fileName << CL << "\" to write parameters object";
      throw std::runtime_error(msg.str());
    LOG(info) << "ca::InitManager: writing CA parameters object to file \"" << GNb << fileName << '\"' << CL;

    // Serialize L1Parameters object and write
    boost::archive::binary_oarchive oa(ofs);
    oa << fParameters;
  }

  // --------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::CheckCAIterationsInit()
  {
    bool ifInitPassed = true;
    if (!fInitController.GetFlag(EInitKey::kCAIterations)) {
      int nIterationsActual   = fParameters.fCAIterations.size();
      int nIterationsExpected = fCAIterationsNumberCrosscheck;
      if (nIterationsActual != nIterationsExpected) {
        LOG(warn) << "ca::InitManager::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 InitManager::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) {
        std::stringstream msg;
        msg << "ca::InitManager: At least one of the StationInitializer objects is not finalized";
      }

      // (2) Check for maximum allowed number of stations
      if (fParameters.GetNstationsGeometry() > constants::size::MaxNstations) {
        std::stringstream msg;
        msg << "Actual total number of registered stations in geometry (" << fParameters.GetNstationsGeometry()
            << ") is larger then possible (" << constants::size::MaxNstations
            << "). Please, select another set of active tracking detectors or recompile the code with enlarged"
            << " constants::size::MaxNstations value";
        throw std::runtime_error(msg.str());
      }
    }
    fInitController.SetFlag(EInitKey::kStationsInfo, ifInitPassed);
  }

  // -------------------------------------------------------------------------------------------------------------------
  //
  void InitManager::ClearStationLayout()
  {
    fParameters.fvFirstGeoId.fill(0);
    fParameters.fvLocalToGeoIdMap.fill(0);
    fParameters.fvGeoToLocalIdMap.fill(std::make_pair(static_cast<EDetectorID>(0), -1));
    fParameters.fvGeoToActiveMap.fill(-1);  // Note: by default all the stations are inactive
    fParameters.fvActiveToGeoMap.fill(0);
    fParameters.fNstationsActiveTotal = -1;
    fInitController.SetFlag(EInitKey::kStationLayoutInitialized, false);
  }