diff --git a/algo/ca/core/pars/CaDefs.h b/algo/ca/core/pars/CaDefs.h index 89b8d79a9fbbac7decdd8b899178968c13fbde2a..43507f8cfaf94e169419f52b6e809f93786090a0 100644 --- a/algo/ca/core/pars/CaDefs.h +++ b/algo/ca/core/pars/CaDefs.h @@ -17,13 +17,10 @@ namespace cbm::algo::ca { - using KfFramework_t = cbm::algo::kf::Framework<float>; - using KfParameters_t = cbm::algo::kf::Parameters<float>; - using KfSetup_t = cbm::algo::kf::Setup<float>; + using KfFramework_t = cbm::algo::kf::Framework<fvec>; using cbm::algo::kf::TrackParamBase; using cbm::algo::kf::TrackParamV; - } // namespace cbm::algo::ca /// Namespace contains compile-time constants definition for the CA tracking algorithm diff --git a/algo/ca/core/pars/CaMaterialMap.h b/algo/ca/core/pars/CaMaterialMap.h index 24f8afedbb1775cb7f00fe462c9d57804cbc3e19..f72ebb8d31dacda8ffec447dd86851b69a37a938 100644 --- a/algo/ca/core/pars/CaMaterialMap.h +++ b/algo/ca/core/pars/CaMaterialMap.h @@ -105,6 +105,10 @@ namespace cbm::algo::ca /// \brief String representation of the object std::string ToString() const; + /// \brief Comparison operator + /// \note To be used for the material map ordering along the z-axis + bool operator<(const MaterialMap& r) const { return fZref < r.fZref; } + private: int fNbins = kfdefs::Undef<int>; ///< Number of rows (== N columns) in the material budget table float fXYmax = kfdefs::Undef<float>; ///< Size of the station in x and y dimensions [cm] diff --git a/algo/kf/core/CMakeLists.txt b/algo/kf/core/CMakeLists.txt index 55646bf8c5e58f8105264a5aa4678c65fccac269..5644088641ff9575ab1d53b5bad4b58d5b3ff49f 100644 --- a/algo/kf/core/CMakeLists.txt +++ b/algo/kf/core/CMakeLists.txt @@ -11,13 +11,13 @@ set(SRCS ${CMAKE_CURRENT_SOURCE_DIR}/KfFramework.cxx ${CMAKE_CURRENT_SOURCE_DIR}/data/KfTrackParam.cxx ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfMaterialMap.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfGeoLayer.cxx ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfTarget.cxx ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfField.cxx ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfFieldValue.cxx ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfFieldSlice.cxx ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfFieldRegion.cxx ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfSetup.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfSetupSerializer.cxx ${CMAKE_CURRENT_SOURCE_DIR}/pars/KfParameters.cxx ${CMAKE_CURRENT_SOURCE_DIR}/utils/KfUtils.cxx ) @@ -68,8 +68,11 @@ install( KfFramework.h KfDefs.h data/KfTrackParam.h + geo/KfField.h + geo/KfFieldRegion.h + geo/KfFieldSlice.h + geo/KfFieldValue.h geo/KfMaterialMap.h - geo/KfGeoLayer.h geo/KfSetup.h geo/KfTarget.h pars/KfParameters.h diff --git a/algo/kf/core/KfDefs.h b/algo/kf/core/KfDefs.h index 96588834c608aef76760318b618fef4def0f610f..612bc9ebe0f99181f055eb551ac6ecd706b86b9c 100644 --- a/algo/kf/core/KfDefs.h +++ b/algo/kf/core/KfDefs.h @@ -74,8 +74,8 @@ namespace cbm::algo::kf namespace cbm::algo::kf::defs { // ----- Array sizes ------------------------------------------------------------------------------------------------- - constexpr int MaxNofFieldSlices = 64; ///< Max number of field slices - + constexpr int MaxNofFieldSlices = 64; ///< Max number of field slices + constexpr int MaxNofMaterialLayers = 32; ///< Max number of the material layers // ----- Control ----------------------------------------------------------------------------------------------------- constexpr int DebugLvl = 0; ///< Level of debug output diff --git a/algo/kf/core/KfFramework.cxx b/algo/kf/core/KfFramework.cxx index a11fe973de397e57c9495756612d5439e33d0565..21334b755857c0bbb7e005c87469e15ea38f7cbc 100644 --- a/algo/kf/core/KfFramework.cxx +++ b/algo/kf/core/KfFramework.cxx @@ -24,12 +24,12 @@ try { errMsg << "\tParameters initialization errors: " << err.what() << '\n'; } - try { - fSetup.Init(); - } - catch (const std::runtime_error& err) { - errMsg << "\tSetup initialization errors: " << err.what() << '\n'; - } + //try { + // fSetup.Init(); + //} + //catch (const std::runtime_error& err) { + // errMsg << "\tSetup initialization errors: " << err.what() << '\n'; + //} if (!errMsg.str().empty()) { throw std::runtime_error(errMsg.str()); @@ -43,6 +43,10 @@ catch (const std::exception& err) { return false; } -template class cbm::algo::kf::Framework<float>; -template class cbm::algo::kf::Framework<double>; -// template class cbm::algo::kf::Framework<fvec>; + +namespace cbm::algo::kf +{ + template class Framework<float>; + template class Framework<double>; + template class Framework<fvec>; +} // namespace cbm::algo::kf diff --git a/algo/kf/core/KfFramework.h b/algo/kf/core/KfFramework.h index 902126523d425470db2005ff7e1411f79cf06638..ea5309a051dfd21534d00fef968a80788151cea4 100644 --- a/algo/kf/core/KfFramework.h +++ b/algo/kf/core/KfFramework.h @@ -17,8 +17,8 @@ namespace cbm::algo::kf { /// \class Framework /// \brief Main class of the KfCore library - /// \tparam DataT Underlying data-type - template<typename DataT> + /// \tparam T Underlying floating point data-type + template<typename T> class Framework { public: /// \brief Default constructor @@ -46,20 +46,20 @@ namespace cbm::algo::kf bool IsInitialized() const { return fbInitialized; } /// \brief Parameters access - Parameters<DataT>& Pars() { return fPars; } + kf::Parameters<T>& Pars() { return fPars; } /// \brief Parameters access - const kf::Parameters<DataT>& Pars() const { return fPars; } + const kf::Parameters<T>& Pars() const { return fPars; } /// \brief Setup access (mutable) - kf::Setup<DataT>& Setup() { return fSetup; } + kf::Setup<T>& Setup() { return fSetup; } /// \brief Setup access - const kf::Setup<DataT>& Setup() const { return fSetup; } + const kf::Setup<T>& Setup() const { return fSetup; } private: - kf::Parameters<DataT> fPars; ///< KF parameters - kf::Setup<DataT> fSetup; ///< KF setup + kf::Parameters<T> fPars; ///< KF parameters + kf::Setup<T> fSetup; ///< KF setup bool fbInitialized = false; ///< Initialization status }; } // namespace cbm::algo::kf diff --git a/algo/kf/core/geo/KfField.cxx b/algo/kf/core/geo/KfField.cxx index c9ab45a6b6b70f69f18d845a2b6fcdb2c917c1ec..fc5ae8cd980673c5d8bc84e6329ce85d290172dc 100644 --- a/algo/kf/core/geo/KfField.cxx +++ b/algo/kf/core/geo/KfField.cxx @@ -14,6 +14,7 @@ #include <tuple> using cbm::algo::kf::EFieldMode; +using cbm::algo::kf::Field; using cbm::algo::kf::FieldFactory; using cbm::algo::kf::FieldFnFair_t; using cbm::algo::kf::detail::FieldBase; @@ -34,31 +35,39 @@ FieldBaseIntrpl_t<T>::FieldBase(const FieldBaseIntrpl_t<I>& other) // --------------------------------------------------------------------------------------------------------------------- // -template<typename T> -template<typename I> -FieldBaseIntrpl_t<T>& FieldBaseIntrpl_t<T>::operator=(const FieldBaseIntrpl_t<I>& other) +template<typename T, EFieldMode FldMode> +std::string Field<T, FldMode>::ToString(int indentLevel) const { - if (this != &other) { - for (size_t i = 0; i < defs::MaxNofFieldSlices; ++i) { - fvFieldSlices[i] = utils::simd::Cast<I, T>(other.fvFieldSlices[i]); + constexpr char IndentChar = '\t'; + std::stringstream msg; + std::string indent(indentLevel, IndentChar); + msg << indent << "Field near primary vertex:\n" << this->fPrimVertexField.ToString(indentLevel + 1) << '\n'; + msg << indent << "Field type: " << static_cast<int>(this->fFieldType) << '\n'; + if constexpr (FldMode == EFieldMode::Orig) { + msg << indent << "Original field function"; + } + else if constexpr (FldMode == EFieldMode::Intrpl) { + msg << indent << "Field slices:"; + for (const auto& fldSlice : this->fvFieldSlices) { + msg << indent << "\n - " << fldSlice.ToString(indentLevel + 1); } } - return *this; + return msg.str(); } // --------------------------------------------------------------------------------------------------------------------- // void FieldFactory::AddSliceReference(double halfSizeX, double halfSizeY, double zRef) { - if (!fSliceReferences.emplace().second) { + if (!fSliceReferences.emplace(halfSizeX, halfSizeY, zRef).second) { std::stringstream msg; - msg << "FieldContainerFactory::AddReference: attempt of adding another slice reference with zRef = " << zRef + msg << "FieldFactory::AddReference: attempt of adding another slice reference with zRef = " << zRef << "(halfSizeX = " << halfSizeX << ", halfSizeY = " << halfSizeY << ").\nThe next slice references were " << "added:"; for (const auto& el : fSliceReferences) { msg << "\n\t- halfSizeX = " << el.fHalfSizeX << ", halfSizeY = " << el.fHalfSizeY << ", zRef = " << el.fRefZ; } - throw std::runtime_error(msg.str()); + throw std::logic_error(msg.str()); } } diff --git a/algo/kf/core/geo/KfField.h b/algo/kf/core/geo/KfField.h index 5a18714ebaec9ce08cb955f87ad486db63289270..98882d7c2286c4415860c7e1d292c3034aaf7896 100644 --- a/algo/kf/core/geo/KfField.h +++ b/algo/kf/core/geo/KfField.h @@ -60,9 +60,12 @@ namespace cbm::algo::kf template<typename I> FieldBase& operator=(const FieldBase<I, EFieldMode::Orig>& other) { - if (this != &other) { - fFieldFn = other.fFieldFn; + if constexpr (std::is_same_v<I, T>) { + if (this == &other) { + return *this; + } } + fFieldFn = other.fFieldFn; return *this; } @@ -130,7 +133,18 @@ namespace cbm::algo::kf /// \brief Copy assignment operator /// \tparam I Underlying floating type of the source template<typename I> - FieldBase& operator=(const FieldBase<I, EFieldMode::Intrpl>& other); + FieldBase& operator=(const FieldBase<I, EFieldMode::Intrpl>& other) + { + if constexpr (std::is_same_v<I, T>) { + if (this == &other) { + return *this; + } + } + for (size_t i = 0; i < defs::MaxNofFieldSlices; ++i) { + fvFieldSlices[i] = utils::simd::Cast<I, T>(other.fvFieldSlices[i]); + } + return *this; + } SlicesContainer_t fvFieldSlices; ///< Array of field slices EFieldType fFieldType{EFieldType::Null}; ///< Field type @@ -159,6 +173,7 @@ namespace cbm::algo::kf static constexpr EFieldMode FieldType = FldMode; using FieldRegion_t = typename FieldBase_t::FieldRegion_t; + using Real_t = T; /// \brief Default constructor Field() = default; @@ -178,8 +193,10 @@ namespace cbm::algo::kf template<typename I> Field& operator=(const Field<I, FldMode>& other) { - if (this == &other) { - return *this; + if constexpr (std::is_same_v<I, T>) { + if (this == &other) { + return *this; + } } fPrimVertexField = other.fPrimVertexField; return FieldBase_t::operator=(other); @@ -202,6 +219,10 @@ namespace cbm::algo::kf /// \brief Gets field region near primary vertex const FieldRegion_t& GetPrimVertexField() const { return fPrimVertexField; } + /// \brief String representation of the class + /// \param indentLevel Indent level of the string output + std::string ToString(int indentLevel) const; + private: /// \brief Serialization function friend class boost::serialization::access; @@ -226,12 +247,6 @@ namespace cbm::algo::kf double fHalfSizeY{defs::Undef<double>}; ///< Half-size of the slice in y-direction [cm] double fRefZ{defs::Undef<double>}; ///< Reference z-position of the slice [cm] - /// \brief Default constructor - SliceRef() = default; - - /// \brief Destructor - //~SliceRef() = default; - /// \brief Constructor /// \param halfX Half-size of the slice in x-direction [cm] /// \param halfY Half-size of the slice in y-direction [cm] @@ -239,7 +254,7 @@ namespace cbm::algo::kf SliceRef(double halfX, double halfY, double refZ) : fHalfSizeX(halfX), fHalfSizeY(halfY), fRefZ(refZ) {} /// \brief Comparision operator - friend constexpr bool operator<(const SliceRef& l, const SliceRef& r) { return l.fRefZ < r.fRefZ; } + bool operator<(const SliceRef& r) const { return fRefZ < r.fRefZ; } }; public: @@ -249,18 +264,12 @@ namespace cbm::algo::kf /// \brief Copy constructor FieldFactory(const FieldFactory&) = default; - /// \brief Move constructor - FieldFactory(FieldFactory&&) = default; - /// \brief Destructor ~FieldFactory() = default; /// \brief Copy assignment operator FieldFactory& operator=(const FieldFactory&) = default; - /// \brief Move assignment operator - FieldFactory& operator=(FieldFactory&&) = default; - /// \brief Adds a slice reference /// \param halfSizeX Half-size of the slice in x-direction [cm] /// \param halfSizeY Half-size of the slice in y-direction [cm] @@ -320,19 +329,19 @@ namespace cbm::algo::kf // Check initialization if (std::any_of(fTarget.begin(), fTarget.end(), [](double x) { return !utils::IsFinite(x); })) { - throw std::runtime_error("FieldFactory::MakeField: target is undefined"); + throw std::logic_error("FieldFactory::MakeField: target is undefined"); } if (!fSliceReferences.size()) { // TODO: Remove requirement of slice references - throw std::runtime_error("FieldFactory::MakeField: no slice references were provided"); + throw std::logic_error("FieldFactory::MakeField: no slice references were provided"); } else if (fSliceReferences.size() > defs::MaxNofFieldSlices) { std::stringstream msg; - msg << "FieldFactory::MakeField: to many slice references are provided (" << fSliceReferences.size() << "), " - << "the maximum allowed number of field slices is " << defs::MaxNofFieldSlices; - throw std::runtime_error(msg.str()); + msg << "FieldFactory::MakeField: too many slice references are provided (" << fSliceReferences.size() << "), " + << "the maximum allowed number of field slices is kf::defs::MaxNofFieldSlices = " << defs::MaxNofFieldSlices; + throw std::logic_error(msg.str()); } if (!fFieldFn) { - throw std::runtime_error("FieldFactory::CreateField: no field function is provided"); + throw std::logic_error("FieldFactory::CreateField: no field function is provided"); } // Initialize the Field object diff --git a/algo/kf/core/geo/KfFieldRegion.h b/algo/kf/core/geo/KfFieldRegion.h index 6906a1f9bb832ad76200124ca43a0ff4f89fc540..d7f40d39b117084427671f1f039770572c7cde14 100644 --- a/algo/kf/core/geo/KfFieldRegion.h +++ b/algo/kf/core/geo/KfFieldRegion.h @@ -98,9 +98,12 @@ namespace cbm::algo::kf template<typename I> FieldRegionBase& operator=(const FieldRegionBase<I, EFieldMode::Orig>& other) { - if (this != &other) { - fFieldFn = other.fFieldFn; + if constexpr (std::is_same_v<I, T>) { + if (this == &other) { + return *this; + } } + fFieldFn = other.fFieldFn; return *this; } @@ -159,10 +162,13 @@ namespace cbm::algo::kf template<typename I> FieldRegionBase& operator=(const FieldRegionBase<I, EFieldMode::Orig>& other) { - if (this != &other) { - this->fCoeff = utils::simd::Cast<I, T>(other.fCoeff); - this->fZfirst = utils::simd::Cast<I, T>(other.fZfirst); + if constexpr (std::is_same_v<I, T>) { + if (this == &other) { + return *this; + } } + this->fCoeff = utils::simd::Cast<I, T>(other.fCoeff); + this->fZfirst = utils::simd::Cast<I, T>(other.fZfirst); return *this; } @@ -213,6 +219,10 @@ namespace cbm::algo::kf static constexpr EFieldMode FieldType = FldMode; using FieldValue_t = FieldValue<T>; + using Real_t = T; + + /// \brief Default constructor + FieldRegion() = default; /// \brief Copy constructor /// \tparam I Underlying floating point type of the source @@ -238,8 +248,10 @@ namespace cbm::algo::kf template<typename I> FieldRegion& operator=(const FieldRegion<I, FldMode>& other) { - if (this == &other) { - return *this; + if constexpr (std::is_same_v<I, T>) { + if (this == &other) { + return *this; + } } fFieldType = other.fFieldType; return FieldRegionBase_t::operator=(other); @@ -260,15 +272,12 @@ namespace cbm::algo::kf std::string ToString(int indentLevel = 0) const; private: - /// \brief Default constructor - FieldRegion() = default; - /// \brief Serialization method friend class boost::serialization::access; template<class Archive> void serialize(Archive& ar, const unsigned int) { - ar& boost::serialization::base_object<FieldRegionBase_t>; + ar& boost::serialization::base_object<FieldRegionBase_t>(*this); ar& fFieldType; } diff --git a/algo/kf/core/geo/KfGeoLayer.cxx b/algo/kf/core/geo/KfGeoLayer.cxx deleted file mode 100644 index eaa8e9214b6ca46b71fdbaa166bd7044598fc86e..0000000000000000000000000000000000000000 --- a/algo/kf/core/geo/KfGeoLayer.cxx +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt - SPDX-License-Identifier: GPL-3.0-only - Authors: Sergei Zharko [committer] */ - -/// @file KfGeoLayer.cxx -/// @brief A logical layer of the KF-setup (implementation) -/// @since 18.07.2024 -/// @author Sergei Zharko <s.zharko@gsi.de> - -#include "KfGeoLayer.h" - -using cbm::algo::kf::GeoLayer; - -// --------------------------------------------------------------------------------------------------------------------- -// -GeoLayer::GeoLayer(kf::MaterialMap&& materialMap) : fMaterialMap(std::move(materialMap)) {} - -// --------------------------------------------------------------------------------------------------------------------- -// -std::string GeoLayer::ToString(int verbose) -{ - if (verbose < 1) { - return std::string{}; - } - - // TODO: SZh. 19.07.2024: Implement - std::stringstream msg; - msg << ""; - return msg.str(); -} diff --git a/algo/kf/core/geo/KfGeoLayer.h b/algo/kf/core/geo/KfGeoLayer.h deleted file mode 100644 index 60bd954410c0eb33585fc6450a5155e1ac4ccd12..0000000000000000000000000000000000000000 --- a/algo/kf/core/geo/KfGeoLayer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt - SPDX-License-Identifier: GPL-3.0-only - Authors: Sergei Zharko [committer] */ - -/// @file KfGeoLayer.h -/// @brief A logical layer of the KF-setup (header) -/// @since 18.07.2024 -/// @author Sergei Zharko <s.zharko@gsi.de> - -#pragma once - -#include "KfMaterialMap.h" - -namespace cbm::algo::kf -{ - /// \class GeoLayer - /// \brief A logical layer of the KF-setup for a given [zMin, zMax] interval - /// - /// A layer includes a material budget map and a magnetic field, estimated for a reference z-position. - class GeoLayer { - public: - /// \brief Default constructor - GeoLayer() = default; - - /// \brief Constructor from the parameters - /// \param materialMap Instance of the material budget map - /// - /// \note The constructor moves the material budget map from the source - GeoLayer(kf::MaterialMap&& materialMap); - - /// \brief Copy constructor - GeoLayer(const GeoLayer&) = default; - - /// \brief Move constructor - GeoLayer(GeoLayer&&) = default; - - /// \brief Copy assignment operator - GeoLayer& operator=(const GeoLayer&) = default; - - /// \brief Move assignment operator - GeoLayer& operator=(GeoLayer&&) = default; - - /// \brief Destructor - ~GeoLayer() = default; - - /// \brief Material map accessor (mutable) - kf::MaterialMap& MaterialMap() { return fMaterialMap; } - - /// \brief Material map accessor (constant) - const kf::MaterialMap& MaterialMap() const { return fMaterialMap; } - - /// \brief String representation of the class - /// \param verbose Verbosity level - std::string ToString(int verbose = 1); - - private: - /// \brief Serialization method - friend class boost::serialization::access; - template<class Archive> - void serialize(Archive& ar, const unsigned int /*version*/) - { - ar& fMaterialMap; - } - - kf::MaterialMap fMaterialMap; ///< Material map instance for the geometry layer - }; - - -} // namespace cbm::algo::kf diff --git a/algo/kf/core/geo/KfMaterialMap.cxx b/algo/kf/core/geo/KfMaterialMap.cxx index 9128811ff379a415d1772a2b84f0401a13acbf3d..e6f69ce164128064de0ad604d36060374053e48d 100644 --- a/algo/kf/core/geo/KfMaterialMap.cxx +++ b/algo/kf/core/geo/KfMaterialMap.cxx @@ -15,6 +15,20 @@ using cbm::algo::kf::fvec; using cbm::algo::kf::MaterialMap; +// --------------------------------------------------------------------------------------------------------------------- +// +MaterialMap::MaterialMap(int nBins, float xyMax, float zRef, float zMin, float zMax) + : fNbins(nBins) + , fXYmax(xyMax) + , fFactor(0.5 * fNbins / fXYmax) + , fZref(zRef) + , fZmin(zMin) + , fZmax(zMax) +{ + this->CheckConsistency(); + fTable.resize(fNbins * fNbins); +} + // --------------------------------------------------------------------------------------------------------------------- // MaterialMap::MaterialMap(MaterialMap&& other) noexcept { this->Swap(other); } @@ -77,39 +91,6 @@ int MaterialMap::GetBin(float x, float y) const return i + j * fNbins; } -// --------------------------------------------------------------------------------------------------------------------- -// -void MaterialMap::Initialize(int nBins, float xyMax, float zRef, float zMin, float zMax) -{ - fNbins = nBins; - fXYmax = xyMax; - fZref = zRef; - fZmin = zMin; - fZmax = zMax; - - if (fNbins < 1) { - std::stringstream aStream; - aStream << "MaterialMap: object cannot be initialized with non-positive nBins = " << fNbins; - throw std::logic_error(aStream.str()); - } - - if (fXYmax < 0.) { - std::stringstream aStream; - aStream << "MaterialMap: object cannot be initialized with non-positive XYmax = " << fXYmax << " [cm]"; - throw std::logic_error(aStream.str()); - } - - if (!((fZmin <= fZref) && (fZref <= zMax))) { - std::stringstream aStream; - aStream << "MaterialMap: object cannot be initialized with inconsistent Z: min " << fZmin << " ref " << fZref - << " max " << fZmax << " [cm]"; - throw std::logic_error(aStream.str()); - } - - fFactor = 0.5 * fNbins / fXYmax; - fTable.resize(fNbins * fNbins); -} - // --------------------------------------------------------------------------------------------------------------------- // void MaterialMap::Swap(MaterialMap& other) noexcept @@ -133,3 +114,27 @@ std::string MaterialMap::ToString() const << setw(12) << fZref << ' ' << setw(12) << fZmin << ' ' << setw(12) << fZmax; return msg.str(); } + +// --------------------------------------------------------------------------------------------------------------------- +// +void MaterialMap::CheckConsistency() const +{ + if (fNbins < 1) { + std::stringstream aStream; + aStream << "MaterialMap: object cannot be initialized with non-positive nBins = " << fNbins; + throw std::logic_error(aStream.str()); + } + + if (fXYmax < 0.) { + std::stringstream aStream; + aStream << "MaterialMap: object cannot be initialized with non-positive XYmax = " << fXYmax << " [cm]"; + throw std::logic_error(aStream.str()); + } + + if (!((fZmin <= fZref) && (fZref <= fZmax))) { + std::stringstream aStream; + aStream << "MaterialMap: object cannot be initialized with inconsistent Z: min " << fZmin << " ref " << fZref + << " max " << fZmax << " [cm]"; + throw std::logic_error(aStream.str()); + } +} diff --git a/algo/kf/core/geo/KfMaterialMap.h b/algo/kf/core/geo/KfMaterialMap.h index d336d84eadbbe602a86b3f95f489d93858990bea..30289c882bdc9628c2bd2d945f86a3f2f550a26f 100644 --- a/algo/kf/core/geo/KfMaterialMap.h +++ b/algo/kf/core/geo/KfMaterialMap.h @@ -29,6 +29,14 @@ namespace cbm::algo::kf /// \brief Default constructor MaterialMap() = default; + /// \brief Constructor from parameters + /// \param nBins Number of rows or columns + /// \param xyMax Size of station in x and y dimensions [cm] + /// \param zRef Reference z-coordinate of the material layer [cm] + /// \param zMin Lower boundary z-coordinate for the material layer [cm] + /// \param zMax Upper boundary z-coordinate for the material layer [cm] + MaterialMap(int nBins, float xyMax, float zRef, float zMin, float zMax); + /// \brief Copy constructor MaterialMap(const MaterialMap& other) = default; @@ -98,8 +106,8 @@ namespace cbm::algo::kf } } - /// \brief Checks, if the fields are NaN - bool IsNaN() const + /// \brief Function to test the instance for NaN + bool IsUndefined() const { return utils::IsUndefined(fNbins) || utils::IsUndefined(fXYmax * fFactor * fZref * fZmin * fZmax); } @@ -113,11 +121,6 @@ namespace cbm::algo::kf /// because iBinX = 0 and iBinY = 0 in the TH1::SetBinContent method of usually defines the underflow bin. void SetRadThickBin(int iBinX, int iBinY, float thickness) { fTable[iBinX + fNbins * iBinY] = thickness; } - /// \brief Sets properties of the material table -- number of rows or columnts and the size of station in XY plane - /// \param nBins Number of rows or columns - /// \param xyMax Size of station in x and y dimensions [cm] - void Initialize(int nBins, float xyMax, float zRef, float zMin, float zMax); - /// \brief Swap method void Swap(MaterialMap& other) noexcept; @@ -127,7 +130,14 @@ namespace cbm::algo::kf /// \brief String representation of the object std::string ToString() const; + /// \brief Comparison operator (material map ordering by fZref) + friend bool operator<(const MaterialMap& lhs, const MaterialMap& rhs) { return lhs.fZref < rhs.fZref; } + private: + /// \brief Checks the object consistency + /// \throw std::logic_error If the object is in non-valid mode + void CheckConsistency() const; + int fNbins = defs::Undef<int>; ///< Number of rows (== N columns) in the material budget table float fXYmax = defs::Undef<float>; ///< Size of the station in x and y dimensions [cm] float fFactor = defs::Undef<float>; ///< Util. var. for the conversion of point coordinates to row/column id @@ -150,5 +160,4 @@ namespace cbm::algo::kf ar& fTable; } }; - } // namespace cbm::algo::kf diff --git a/algo/kf/core/geo/KfSetup.cxx b/algo/kf/core/geo/KfSetup.cxx index bce84eece389e15cbf4ed00c23cd9ba090b48e9b..e2ac6a105fa3ce59d3c4a8a2a3f45e24286c65c6 100644 --- a/algo/kf/core/geo/KfSetup.cxx +++ b/algo/kf/core/geo/KfSetup.cxx @@ -12,50 +12,112 @@ #include <sstream> using cbm::algo::kf::Setup; +using cbm::algo::kf::SetupFactory; + +// +// Setup methods definition +// // --------------------------------------------------------------------------------------------------------------------- // -template<typename DataT> -void Setup<DataT>::CheckConsistency() const +template<typename T> +std::string Setup<T>::ToString(int verbosity, int indentLevel) const { - std::stringstream errMsg; - - // checks go here... the errMsg is to be filled on each checking stage - - if (!errMsg.str().empty()) { - throw std::runtime_error(errMsg.str()); + std::stringstream msg; + if (verbosity > 0) { + constexpr char indentCh = '\t'; + std::string indent(indentLevel, indentCh); + msg << indent << "----- KF setup -----\n"; + msg << indent << "Target:\n" << fTarget.ToString(indentLevel + 1); + msg << indent << "Material layers:\n"; + for (const auto& layer : fvMaterialLayers) { + msg << indent << indentCh << layer.ToString() << '\n'; + } + msg << indent << "Interpolated magnetic field:\n" << fIntrplField.ToString(indentLevel + 1); + if (foOrigField) { + msg << indent << "Original magnetic field:\n" << foOrigField->ToString(indentLevel + 1); + } + else { + msg << indent << "Original magnetic field: not provided"; + } } + return msg.str(); } +namespace cbm::algo::kf +{ + template class Setup<float>; + template class Setup<double>; + template class Setup<fvec>; +} // namespace cbm::algo::kf + + +// +// SetupFactory methods definition +// + // --------------------------------------------------------------------------------------------------------------------- // -template<typename DataT> -void Setup<DataT>::Init() +void SetupFactory::AddMaterial(const MaterialMap& material) { - fbInitialized = true; - CheckConsistency(); + if (!fMaterialLayers.emplace(material).second) { + std::stringstream msg; + msg << "SetupFactory::AddMaterial: attempt of adding a duplicating material layer " << material.ToString() + << ".\nThe next material layers were already added:"; + for (const auto& el : fMaterialLayers) { + msg << "\n\t- " << el.ToString(); + } + throw std::logic_error(msg.str()); + } } // --------------------------------------------------------------------------------------------------------------------- // -template<typename DataT> -std::string Setup<DataT>::ToString(int verbosity, int indentLevel) const +template<typename T> +Setup<T> SetupFactory::MakeSetup(bool bProvideOrigField) const { - std::stringstream msg; + Setup<T> setup; + // Target initialization + setup.SetTarget(fTarget); - if (verbosity > 0) { - constexpr char indentCh = '\t'; - std::string indent(indentLevel, indentCh); - msg << indent << " ----- KF setup -----\n"; - msg << indent << "MATERIAL LAYERS:\n"; - for (const auto& layer : fvMatLayers) { - msg << indent << indentCh << layer.ToString() << '\n'; - } + // Field initialization + setup.SetField(fFieldFactory.MakeField<T, EFieldMode::Intrpl>()); + if (bProvideOrigField) { + setup.SetField(fFieldFactory.MakeField<T, EFieldMode::Orig>()); } - return msg.str(); + // Material layers initialization + if (fMaterialLayers.size() > defs::MaxNofMaterialLayers) { + std::stringstream msg; + msg << "kf::SetupFactory::MakeSetup(): too many material layers are provided (" << fMaterialLayers.size() + << "), the maximum allowed number of the layers kf::defs::MaxNofMaterialLayers = " + << defs::MaxNofMaterialLayers; + throw std::logic_error(msg.str()); + } + int layerId = 0; + for (const auto& material : fMaterialLayers) { + setup.SetMaterial(layerId, material); + } + + return setup; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void SetupFactory::Reset() +{ + fFieldFactory.Reset(); + fMaterialLayers.clear(); } -template class cbm::algo::kf::Setup<float>; -template class cbm::algo::kf::Setup<double>; -//template class cbm::algo::kf::Setup<fvec>; +// --------------------------------------------------------------------------------------------------------------------- +// +void SetupFactory::SetTargetProperties(double x, double y, double z, double fieldInitStep, const MaterialMap& material) +{ + fTarget.SetX(x); + fTarget.SetY(y); + fTarget.SetZ(z); + fTarget.SetMaterial(material); + fFieldFactory.SetTarget(x, y, z); + fFieldFactory.SetStep(fieldInitStep); +} diff --git a/algo/kf/core/geo/KfSetup.h b/algo/kf/core/geo/KfSetup.h index 755b02ab5fd97142466fdee938346d6c27a4dfb6..994c056a04b584656f0bfb1e3ca23c601fb761ec 100644 --- a/algo/kf/core/geo/KfSetup.h +++ b/algo/kf/core/geo/KfSetup.h @@ -10,24 +10,31 @@ #pragma once // include this header only once per compilation unit #include "KfDefs.h" -#include "KfGeoLayer.h" +#include "KfField.h" +#include "KfMaterialMap.h" +#include "KfTarget.h" #include "KfVector.h" #include <boost/serialization/access.hpp> +#include <boost/serialization/split_free.hpp> +#include <optional> #include <string> #include <vector> namespace cbm::algo::kf { - using MaterialContainer_t = Vector<MaterialMap>; - /// \class Setup /// \brief KF-framework representation of the detector setup - /// \tparam T Underlying floating point data-type (float, double or fvec) - // TODO: Should the class have a template parameter? + /// \tparam T Underlying floating-point data type template<typename T> class alignas(VcMemAlign) Setup { + friend class boost::serialization::access; // Boost serializer methods + template<typename I> + friend class Setup; + + using MaterialContainer_t = std::array<MaterialMap, defs::MaxNofMaterialLayers>; + public: /// \brief Default constructor Setup() = default; @@ -35,65 +42,209 @@ namespace cbm::algo::kf /// \brief Destructor ~Setup() = default; - /// \brief Move constructor - Setup(Setup&&) = default; - - /// \brief Move assignment operator - Setup& operator=(Setup&&) = default; - - /// \brief Adds material layer - void AddMaterialLayer(const MaterialMap& layer) { fvMatLayers.push_back(layer); } - - /// \brief Adds material layer, moving it from the source - void AddMaterialLayer(MaterialMap&& layer) { fvMatLayers.push_back(std::move(layer)); } + /// \brief Copy constructor + /// \tparam I Underlying floating-point data type of the source + template<typename I> + Setup(const Setup<I>& other) + : fvMaterialLayers(other.fvMaterialLayers) + , foOrigField(other.foOrigField.has_value() ? std::make_optional(*other.foOrigField) : std::nullopt) + , fIntrplField(other.fIntrplField) + , fTarget(other.fTarget) + { + } - /// \brief Check method - /// \note Throws std::runtime_error, if the class inconsistent - void CheckConsistency() const; + /// \brief Move constructor + //Setup(Setup&&) noexcept; - /// \brief Gets material layer - [[gnu::always_inline]] const MaterialMap& GetLayer(int iLayer) const + /// \brief Copy assignment operator + /// \tparam I Underlying floating-point data type of the source + template<typename I> + Setup& operator=(const Setup<I>& other) { - return fvMatLayers.at<defs::GetterCheck>(iLayer); + if constexpr (std::is_same_v<I, T>) { + if (this == &other) { + return *this; + } + } + fvMaterialLayers = other.fvMaterialLayers; + foOrigField = other.foOrigField; + fIntrplField = other.fIntrplField; + fTarget = other.fTarget; + return *this; } - /// \brief Initializes setup - void Init(); + /// \brief Move assignment operator + //Setup& operator=(Setup&&) noexcept; + + /// \brief Makes an instance of the field depending on the template parameter + /// \tparam FldMode Field mode of the returned instance + /// \throw std::logic_error If the particular field member is undefined (nullopt) + template<EFieldMode FldMode> + const Field<T, FldMode>& GetField() const; - /// \brief Returns initialization status - bool IsInitialized() const { return fbInitialized; } + /// \brief Gets material layer + /// \param iLayer Index of layer + const MaterialMap& GetMaterial(int iLayer) const { return fvMaterialLayers[iLayer]; } - /// \brief Resets initialization - void Reset() { *this = std::move(Setup{}); } + /// \brief Gets target + const Target<T>& GetTarget() const { return fTarget; } /// \brief String representation of the class contents /// \param verbosity A verbose level for output /// \param indentLevel Indent level of the string output std::string ToString(int verbosity = 0, int indentLevel = 0) const; - private: - /// \brief Copy constructor - /// \tparam I Underlying floating-point data type of the source - //template<typename I> - Setup(const Setup& other) = default; + /// \brief Sets field + template<EFieldMode FldMode> + void SetField(const Field<double, FldMode>& field); - /// \brief Copy assignment operator - /// \tparam I Underlying floating-point data type of the source - //template<typename I> - Setup& operator=(const Setup& other) = default; + /// \brief Sets material layer + /// \param iLayer Index of layer + /// \param map Material map + void SetMaterial(int iLayer, const MaterialMap& map) { fvMaterialLayers[iLayer] = map; } + + /// \brief Sets target (moves from the source) + /// \param target Target instance + void SetTarget(const Target<double>& target) { fTarget = target; } + + /// \brief BOOST serialization load method + template<class Archive> + void load(Archive& ar, const unsigned int /*version*/) + { + ar >> fvMaterialLayers; + ar >> fTarget; + ar >> fIntrplField; + foOrigField = std::nullopt; + + // NOTE: The original field cannot be serialized, because it contains a pointer to the external magnetic field + // function. + } + + template<class Archive> + void save(Archive& ar, const unsigned int /*version*/) const + { + ar << fvMaterialLayers; + ar << fTarget; + ar << fIntrplField; + } - /// \brief Serialization method - friend class boost::serialization::access; template<class Archive> - void serialize(Archive& ar, const unsigned int /*version*/) + void serialize(Archive& ar, const unsigned int version) { - ar& fvMatLayers; - ar& fbInitialized; + boost::serialization::split_member(ar, *this, version); } - MaterialContainer_t fvMatLayers = {}; ///< Material layers map + MaterialContainer_t fvMaterialLayers = {}; ///< Container of the material maps + Field<T, EFieldMode::Intrpl> fIntrplField; ///< Interpolated field (NOTE: maybe make optional) + std::optional<Field<T, EFieldMode::Orig>> foOrigField{std::nullopt}; ///< Optional original field + Target<T> fTarget; ///< Target layer + }; - bool fbInitialized{false}; ///< Is instance initialized - bool fbOrigFieldAvailable{false}; ///< Is original field available + + /// \class SetupFactory + /// \brief Creates a valid initialized Setup instance + class SetupFactory { + public: + /// \brief Default constructor + SetupFactory() = default; + + /// \brief Copy constructor + SetupFactory(const SetupFactory&) = delete; + + /// \brief Move constructor + SetupFactory(SetupFactory&&) = delete; + + /// \brief Destructor + ~SetupFactory() = default; + + /// \brief Copy assignment operator + SetupFactory& operator=(const SetupFactory&) = delete; + + /// \brief Move assignment operator + SetupFactory& operator=(SetupFactory&&) = delete; + + /// \brief Adds magnetic field slice reference + /// \param halfSizeX Half-size of the slice in x-direction [cm] + /// \param halfSizeY Half-size of the slice in y-direction [cm] + /// \param refZ Reference z-position of the slice [cm] + void AddFieldSliceReference(double halfSizeX, double halfSizeY, double refZ) + { + fFieldFactory.AddSliceReference(halfSizeX, halfSizeY, refZ); + } + + /// \brief Adds material layer + /// \param material Material layer + void AddMaterial(const MaterialMap& material); + + /// \brief Creates a setup instance + /// \param bProvideOrigField Flag: true - defines optional variable of the original field + template<typename T> + Setup<T> MakeSetup(bool bProvideOrigField = true) const; + + /// \brief Resets the instance + void Reset(); + + /// \brief Sets magnetic field function + /// \param fieldFn Magnetic field function (either KF, or FairRoot format) + /// \param fieldType Magnetic field type + template<typename FieldFn> + void SetFieldFunction(const FieldFn& fieldFn, EFieldType fieldType) + { + fFieldFactory.SetFieldFunction(fieldFn); + fFieldFactory.SetFieldType(fieldType); + } + + /// \brief Sets target initialization properties + /// \param x Target x-coordinate [cm] + /// \param y Target y-coordinate [cm] + /// \param z Target z-coordinate [cm] + /// \param fieldInitStep Step between the nodal points in the target field region initialization [cm] + /// \param material Target material layer + void SetTargetProperties(double x, double y, double z, double fieldInitStep, const MaterialMap& material); + + private: + std::set<MaterialMap> fMaterialLayers{}; ///< Set of material maps + FieldFactory fFieldFactory; ///< Instance of field factory + Target<double> fTarget; ///< Field to keep target properties }; + + // + // Template method definition + // + + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + template<EFieldMode FldMode> + const Field<T, FldMode>& Setup<T>::GetField() const + { + if constexpr (FldMode == EFieldMode::Orig) { + if (foOrigField) { + return *foOrigField; + } + else { + throw std::logic_error("kf::Setup::MakeField(): attempt to create a Field instance in the original field mode " + "in the unsuitable scenario (for example, in the online reconstruction code). Please, " + "use the interpolated magnetic field calling Setup::MakeField<T, EFieldMode::Intrpl>() " + "instead."); + } + } + else if constexpr (FldMode == EFieldMode::Intrpl) { + return fIntrplField; + } + } + + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + template<EFieldMode FldMode> + void Setup<T>::SetField(const Field<double, FldMode>& field) + { + if constexpr (FldMode == EFieldMode::Intrpl) { + fIntrplField = field; + } + else if constexpr (FldMode == EFieldMode::Orig) { + foOrigField = std::make_optional(field); + } + } } // namespace cbm::algo::kf diff --git a/algo/kf/core/geo/KfSetupSerializer.cxx b/algo/kf/core/geo/KfSetupSerializer.cxx new file mode 100644 index 0000000000000000000000000000000000000000..52cb6658334b1df83ff0a65df39a05e536583ff0 --- /dev/null +++ b/algo/kf/core/geo/KfSetupSerializer.cxx @@ -0,0 +1,27 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// @file KfSetupSerializer.cxx +/// @brief Helper class for a kf::Setup loading/storing (implementation) +/// @since 26.08.2024 +/// @author Sergei Zharko <s.zharko@gsi.de> + +#include "KfSetupSerializer.h" + +using cbm::algo::kf::Setup; +using cbm::algo::kf::SetupSerializer; + +// --------------------------------------------------------------------------------------------------------------------- +// +void SetupSerializer::Store(const Setup<double>& setup, const std::string& fileName) +{ + std::ofstream ofs(fileName, std::ios::binary); + if (!ofs) { + std::stringstream msg; + msg << "kf::SetupSerializer::Store: failed openning file \"" << fileName << "\" to store the setup"; + throw std::runtime_error(msg.str()); + } + boost::archive::binary_oarchive oa(ofs); + oa << setup; +} diff --git a/algo/kf/core/geo/KfSetupSerializer.h b/algo/kf/core/geo/KfSetupSerializer.h new file mode 100644 index 0000000000000000000000000000000000000000..98af29fc96f7969705600ef6270bea2e45b117aa --- /dev/null +++ b/algo/kf/core/geo/KfSetupSerializer.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// @file KfSetupSerializer.h +/// @brief Helper class for a kf::Setup loading/storing (header) +/// @since 26.08.2024 +/// @author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#include "KfSetup.h" + +#include <boost/archive/binary_iarchive.hpp> +#include <boost/archive/binary_oarchive.hpp> + +#include <fstream> +#include <sstream> +#include <string> + +namespace cbm::algo::kf +{ + /// \class SetupSerializer + /// \brief A helper class for storing/loading a kf::Setup instance + /// + /// A particular setup instance is dependent from a template parameter, which represents an underlying floating + /// point data-type. Only a Setup with T = double can be serialized, so if a particular setup instance has + /// another floating-point type, it will be converted to the double-precision version. + /// Moreover, a Setup instance has two magnetic field representation, an interpolated magnetic field and an + /// optional original field. In the serialization only the interpolated magnetic field variant is stored, the + /// original field version will be set to nullopt during the loading from the file. + /// + class SetupSerializer { + public: + /// \brief Stores a serialized setup to a file + /// \param setup A reference to the Setup (NOTE: a double-Setup must be passed explicitly) + /// \param fileName Output file name + static void Store(const Setup<double>& setup, const std::string& fileName); + + /// \brief Loads a serialized setup from a file + /// \tparam T Underlying floating-point type for the output setup object + /// \param fileName Input file name + /// \throw std::runtime_error If the fileName cannot be opened + template<typename T> + static Setup<T> Load(const std::string& fileName); + }; + + + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + Setup<T> SetupSerializer::Load(const std::string& fileName) + { + Setup<double> setup; + + std::ifstream ifs(fileName, std::ios::binary); + if (!ifs) { + std::stringstream msg; + msg << "kf::SetupSerializer::Load: intput setup file \"" << fileName << "\" was not found"; + throw std::runtime_error(msg.str()); + } + + try { + boost::archive::binary_iarchive ia(ifs); + ia >> setup; + } + catch (const std::exception& err) { + std::stringstream msg; + msg << "kf::SetupSerializer::Load: input setup file \"" << fileName + << "\" has inconsistent format or was " + "corrupted. The exception message: " + << err.what(); + throw std::runtime_error(msg.str()); + } + + return Setup<T>(setup); + } +} // namespace cbm::algo::kf diff --git a/algo/kf/core/geo/KfTarget.cxx b/algo/kf/core/geo/KfTarget.cxx index cb564fbd11f854b8bac9c1afab76f790ab676252..1df0856d6dee7072171f69d1cc9b84afad73e81e 100644 --- a/algo/kf/core/geo/KfTarget.cxx +++ b/algo/kf/core/geo/KfTarget.cxx @@ -9,16 +9,50 @@ #include "KfTarget.h" -using cbm::algo::kf::GeoLayer; +#include <sstream> + using cbm::algo::kf::MaterialMap; using cbm::algo::kf::Target; // --------------------------------------------------------------------------------------------------------------------- // -Target::Target(kf::MaterialMap&& materialMap, float x, float y, float z) - : GeoLayer(std::move(materialMap)) - , fX(x) - , fY(y) - , fZ(z) +template<typename T> +Target<T>::Target(const MaterialMap& material, double x, double y, double z) + : fMaterial(material) + , fX(utils::simd::Cast<double, T>(x)) + , fY(utils::simd::Cast<double, T>(y)) + , fZ(utils::simd::Cast<double, T>(z)) +{ +} + +// --------------------------------------------------------------------------------------------------------------------- +// +template<typename T> +void Target<T>::SetMaterial(const MaterialMap& material) +{ + if (material.IsUndefined()) { + throw std::logic_error("Target:ReceiveMaterial(): attempt to pass an undefined instance of the material map"); + } + fMaterial = material; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +template<typename T> +std::string Target<T>::ToString(int indentLevel) const { + constexpr char IndentChar = '\t'; + std::stringstream msg; + std::string indent(indentLevel, IndentChar); + msg << indent << "position: {" << fX << ", " << fY << ", " << fZ << "} [cm]\n"; + msg << indent << "material: " << fMaterial.ToString(); + return msg.str(); } + + +namespace cbm::algo::kf +{ + template class Target<float>; + template class Target<double>; + template class Target<fvec>; +} // namespace cbm::algo::kf diff --git a/algo/kf/core/geo/KfTarget.h b/algo/kf/core/geo/KfTarget.h index f37bca6eac969c53db01ba6fb5b2c4c3b722030d..78008cc4501d81e6503ddf2c45d82dcccfb2c97e 100644 --- a/algo/kf/core/geo/KfTarget.h +++ b/algo/kf/core/geo/KfTarget.h @@ -10,62 +10,95 @@ #pragma once #include "KfDefs.h" -#include "KfGeoLayer.h" +#include "KfMaterialMap.h" #include <boost/serialization/access.hpp> -#include <boost/serialization/base_object.hpp> + +#include <string> namespace cbm::algo::kf { - /// \class Target - /// \brief A geometry layer in the target region - class Target : public GeoLayer { + /// \class Target + /// \brief A geometry layer in the target region + /// \tparam T Underlying floating-point type + template<typename T> + class alignas(VcMemAlign) Target { + template<typename I> + friend class Target; + public: /// \brief Default constructor Target() = default; /// \brief Constructor from parameters - /// \param materialMap Instance of the material budget map - /// \param x x-coordinate of the nominal target center [cm] - /// \param y y-coordinate of the nominal target center [cm] - /// \param z z-coordinate of the nominal target center [cm] - Target(kf::MaterialMap&& materialMap, float x, float y, float z); + /// \param material Instance of the material budget map near the target region + /// \param x x-coordinate of the nominal target center [cm] + /// \param y y-coordinate of the nominal target center [cm] + /// \param z z-coordinate of the nominal target center [cm] + Target(const MaterialMap& material, double x, double y, double z); /// \brief Copy constructor - Target(const Target&) = default; - - /// \brief Move constructor - Target(Target&&) = default; - - /// \brief Copy assignment operator - Target& operator=(const Target&) = default; - - /// \brief Move assignment operator - Target& operator=(Target&&) = default; + /// \tparam I Underlying floating-point type of the source + template<typename I> + Target(const Target<I>& other) + : fMaterial(other.fMaterial) + , fX(utils::simd::Cast<I, T>(other.fX)) + , fY(utils::simd::Cast<I, T>(other.fY)) + , fZ(utils::simd::Cast<I, T>(other.fZ)) + { + } /// \brief Destructor ~Target() = default; + /// \brief Copy assignment operator + /// \tparam I Underlying floating-point type of the source + template<typename I> + Target& operator=(const Target<I>& other) + { + if constexpr (std::is_same_v<I, T>) { + if (this == &other) { + return *this; + } + } + fMaterial = other.fMaterial; + fX = utils::simd::Cast<I, T>(other.fX); + fY = utils::simd::Cast<I, T>(other.fY); + fZ = utils::simd::Cast<I, T>(other.fZ); + return *this; + } + /// \brief Gets x-coordinate of the nominal target center - float GetX() const { return fX; } + const T& GetX() const { return fX; } /// \brief Gets x-coordinate of the nominal target center - float GetY() const { return fY; } + const T& GetY() const { return fY; } /// \brief Gets x-coordinate of the nominal target center - float GetZ() const { return fZ; } + const T& GetZ() const { return fZ; } + + /// \brief Gets material map + const MaterialMap& GetMaterial() const { return fMaterial; } + + /// \brief Sets material map + /// \param material Material map + void SetMaterial(const MaterialMap& material); /// \brief Sets x-coordinate of the nominal target center /// \param x x-coordinate [cm] - void SetX(float x) { fX = x; } + void SetX(const T& x) { fX = x; } /// \brief Sets y-coordinate of the nominal target center /// \param y y-coordinate [cm] - void SetY(float y) { fY = y; } + void SetY(const T& y) { fY = y; } /// \brief Sets x-coordinate of the nominal target center /// \param z x-coordinate [cm] - void SetZ(float z) { fZ = z; } + void SetZ(const T& z) { fZ = z; } + + /// \brief String representation of the class + /// \param indentLevel Indent level of the string output + std::string ToString(int indentLevel = 0) const; private: /// \brief Serialization method @@ -73,14 +106,15 @@ namespace cbm::algo::kf template<class Archive> void serialize(Archive& ar, const unsigned int /*version*/) { - ar& boost::serialization::base_object<GeoLayer>(*this); + ar& fMaterial; ar& fX; ar& fY; ar& fZ; } - float fX = defs::Undef<float>; ///< x-coordinate of the nominal target center [cm] - float fY = defs::Undef<float>; ///< y-coordinate of the nominal target center [cm] - float fZ = defs::Undef<float>; ///< z-coordinate of the nominal target center [cm] + MaterialMap fMaterial; ///< Material map in the target region + T fX = defs::Undef<T>; ///< x-coordinate of the nominal target center [cm] + T fY = defs::Undef<T>; ///< y-coordinate of the nominal target center [cm] + T fZ = defs::Undef<T>; ///< z-coordinate of the nominal target center [cm] }; } // namespace cbm::algo::kf diff --git a/algo/kf/core/pars/KfParameters.cxx b/algo/kf/core/pars/KfParameters.cxx index 999aec0b9a62980baa577b4ec3d76a9d75f6b928..ce76c88c748f8c900b3819ef64bdff40d1d3bb97 100644 --- a/algo/kf/core/pars/KfParameters.cxx +++ b/algo/kf/core/pars/KfParameters.cxx @@ -54,6 +54,9 @@ std::string Parameters<DataT>::ToString(int verbosity, int indentLevel) const return msg.str(); } -template class cbm::algo::kf::Parameters<float>; -template class cbm::algo::kf::Parameters<double>; -// template class cbm::algo::kf::Parameters<fvec>; +namespace cbm::algo::kf +{ + template class Parameters<float>; + template class Parameters<double>; + template class Parameters<fvec>; +} // namespace cbm::algo::kf