diff --git a/algo/detectors/bmon/Calibrate.cxx b/algo/detectors/bmon/Calibrate.cxx index 70d99daeb463f1563bd4594e6c1b0a03f56a384b..53b40e6b13fdec26b63778780af01d1a0d696ff8 100644 --- a/algo/detectors/bmon/Calibrate.cxx +++ b/algo/detectors/bmon/Calibrate.cxx @@ -13,6 +13,7 @@ #include "CbmTofAddress.h" #include "util/TimingsFormat.h" +#include <bitset> #include <chrono> using cbm::algo::bmon::Calibrate; @@ -21,36 +22,56 @@ using fles::Subsystem; // --------------------------------------------------------------------------------------------------------------------- // -Calibrate::Calibrate(CalibrateSetup setup) : fSetup(setup), fSmOffset(1, 0), fRpcOffset(1, 0) +Calibrate::Calibrate(CalibrateSetup setup) : fSetup(setup), fSelectionBitsOffset(0) { // Initialize offset arrays for channel deadtime check - int32_t NbSm = fSetup.NbSm; - int32_t NbRpc = fSetup.NbRpc; - for (int32_t Sm = 0; Sm < NbSm; Sm++) { - fSmOffset.push_back(fSmOffset.back() + NbRpc); - for (int32_t Rpc = 0; Rpc < NbRpc; Rpc++) { - int32_t NbChan = fSetup.rpcs[Sm * NbRpc + Rpc].chanPar.size(); - fRpcOffset.push_back(fRpcOffset.back() + 2 * NbChan); //Factor 2 for channel sides + int nDiamondsInSetup = fSetup.diamonds.size(); + if (nDiamondsInSetup == 0) { + throw std::runtime_error("No diamonds found in the BMON calibration config"); + } + if (!(fSetup.selectionMask) != (nDiamondsInSetup == 1)) { + throw std::runtime_error("Wrong diamond selection mask: for a single diamond it must be zero, and for multiple" + " diamonds it must be non-zero"); + } + if (nDiamondsInSetup > 1) { + // Define the selection bit offset + while (!((fSetup.selectionMask >> fSelectionBitsOffset) % 2)) { + ++fSelectionBitsOffset; } + + // Sort the diamonds in the setup by their SM or Side or other distinguishing index + std::sort(fSetup.diamonds.begin(), fSetup.diamonds.end(), [&](const auto& lhs, const auto& rhs) { + return GetDiamondIndex(lhs.refAddress) < GetDiamondIndex(rhs.refAddress); + }); } - // **** DEBUG: BEGIN - for (size_t iO = 0; iO < fSmOffset.size(); ++iO) { - L_(info) << "SM offset: " << iO << ", " << fSmOffset[iO]; + // Remove the channel information from the reference address + for (auto& diamond : fSetup.diamonds) { + diamond.refAddress = CbmTofAddress::GetModFullId(diamond.refAddress); } - for (size_t iO = 0; iO < fRpcOffset.size(); ++iO) { - L_(info) << "RPC offset: " << iO << ", " << fRpcOffset[iO]; + + // Calculate the channel offsets, needed for the dead time + fChannelOffset = std::vector<size_t>(nDiamondsInSetup + 1, 0); // the last element -- total number of channels + for (int32_t iD = 0; iD < nDiamondsInSetup; ++iD) { + fChannelOffset[iD + 1] = fChannelOffset[iD] + fSetup.diamonds[iD].chanPar.size(); } - // **** DEBUG: END + fChannelDeadTime = std::vector<double>(fChannelOffset.back(), std::numeric_limits<double>::quiet_NaN()); - fChannelDeadTime = std::vector<double>(fRpcOffset.back(), std::numeric_limits<double>::quiet_NaN()); + // **** DEBUG: BEGIN + for (size_t iO = 0; iO < fChannelOffset.size(); ++iO) { + L_(info) << "Channel offset: diamond=" << iO << ", offset=" << fChannelOffset[iO]; + } + L_(info) << "Selection mask: 0b" << std::bitset<32>(fSetup.selectionMask); + L_(info) << "Bits offset: " << static_cast<uint32_t>(fSelectionBitsOffset); + L_(info) << "Size of the channel dead time vector: " << fChannelDeadTime.size(); + // **** DEBUG: END } // --------------------------------------------------------------------------------------------------------------------- // Calibrate::resultType Calibrate::operator()(gsl::span<const CbmBmonDigi> digiIn) { - xpu::push_timer("TofCalibrate"); + xpu::push_timer("BmonCalibrate"); xpu::t_add_bytes(digiIn.size_bytes()); // --- Output data @@ -60,79 +81,60 @@ Calibrate::resultType Calibrate::operator()(gsl::span<const CbmBmonDigi> digiIn) auto& monitor = result.second; calDigiOut.reserve(digiIn.size()); + // Reset the channel dead time std::fill(fChannelDeadTime.begin(), fChannelDeadTime.end(), std::numeric_limits<double>::quiet_NaN()); + const auto& diamonds = fSetup.diamonds; for (const auto& digi : digiIn) { uint32_t address = static_cast<uint32_t>(digi.GetAddress()); - const int32_t SmType{CbmTofAddress::GetSmType(address)}; - const int32_t Sm{CbmTofAddress::GetSmId(address)}; - const int32_t Rpc{CbmTofAddress::GetRpcId(address)}; - const int NbRpc{fSetup.NbRpc}; - - int32_t Chan{CbmTofAddress::GetChannelId(address)}; - int32_t Side{CbmTofAddress::GetChannelSide(address)}; - - // NOTE: Follow the hack in the CbmTofEventClusterizer::Exec() for the BMON digis and change the address - // of calibrated digis. In general it is incorrect and needs further investigation. - uint32_t calAddress = address; - if (Side == 1) { - Side = 0; - Chan += 6; - calAddress = CbmTofAddress::GetUniqueAddress(Sm, Rpc, Chan, Side, SmType); - } - - auto& rpcs = fSetup.rpcs; - if (SmType != fSetup.SmType || Sm * NbRpc + Rpc >= static_cast<int>(rpcs.size())) { + int32_t iChannel = CbmTofAddress::GetChannelId(address); + size_t iDiamond = GetDiamondIndex(address); + if (iDiamond >= diamonds.size() + || static_cast<uint32_t>(CbmTofAddress::GetModFullId(address)) != diamonds[iDiamond].refAddress) { monitor.fDigiCalibUnknownRPC++; - L_(error) << "Unknown BMON digi address: " << CbmTofAddress::ToString(calAddress); + L_(error) << "Unknown BMON digi address: " << CbmTofAddress::ToString(address) << ", iDiamond = " << iDiamond; continue; } - CalibrateSetup::Rpc& rpcPar = fSetup.rpcs[Sm * NbRpc + Rpc]; - CalibrateSetup::Channel& chanPar = rpcPar.chanPar[Chan]; + const auto& diamondPar = diamonds[iDiamond]; + const auto& channelPar = diamondPar.chanPar[iChannel]; // Check dead time - // FIXME: BMON digis (must) have only one side -> Fix the offsets, when mcbm2024_05 will be fixed - const size_t chanIdx = fRpcOffset[fSmOffset[Sm] + Rpc] + Chan + Side * rpcPar.chanPar.size(); - const double deadTime = fChannelDeadTime[chanIdx]; + const size_t iChannelGlb = fChannelOffset[iDiamond] + iChannel; + const double deadTime = fChannelDeadTime[iChannelGlb]; if (!std::isnan(deadTime) && digi.GetTime() <= deadTime) { - fChannelDeadTime[chanIdx] = digi.GetTime() + rpcPar.channelDeadtime; + fChannelDeadTime[iChannelGlb] = digi.GetTime() + diamondPar.channelDeadtime; monitor.fDigiDeadTimeCount++; continue; } - fChannelDeadTime[chanIdx] = digi.GetTime() + rpcPar.channelDeadtime; + fChannelDeadTime[iChannelGlb] = digi.GetTime() + diamondPar.channelDeadtime; // Create calibrated digi CbmBmonDigi& pCalDigi = calDigiOut.emplace_back(digi); - pCalDigi.SetAddress(calAddress); - - // Check if channel sides need to be swapped - if (rpcPar.swapChannelSides) { - pCalDigi.SetAddress(CbmTofAddress::GetUniqueAddress(Sm, Rpc, Chan, (0 == Side) ? 1 : 0, SmType)); - } + pCalDigi.SetAddress(address); // calibrate Digi Time - pCalDigi.SetTime(pCalDigi.GetTime() - chanPar.vCPTOff[Side]); + pCalDigi.SetTime(pCalDigi.GetTime() - channelPar.vCPTOff); // subtract Offset - const double dTot = std::max(pCalDigi.GetCharge() - chanPar.vCPTotOff[Side], 0.001); + const double dTot = std::max(pCalDigi.GetCharge() - channelPar.vCPTotOff, 0.001); // calibrate Digi charge (corresponds to TOF ToT) - pCalDigi.SetCharge(dTot * chanPar.vCPTotGain[Side]); + pCalDigi.SetCharge(dTot * channelPar.vCPTotGain); // walk correction - std::vector<double>& walk = chanPar.vCPWalk[Side]; - const double dTotBinSize = (rpcPar.TOTMax - rpcPar.TOTMin) / rpcPar.numClWalkBinX; - int32_t iWx = std::max((int32_t)((pCalDigi.GetCharge() - rpcPar.TOTMin) / dTotBinSize), 0); - iWx = std::min(iWx, rpcPar.numClWalkBinX - 1); + const std::vector<double>& walk = channelPar.vCPWalk; + const double dTotBinSize = (diamondPar.TOTMax - diamondPar.TOTMin) / diamondPar.numClWalkBinX; + int32_t iWx = std::max((int32_t)((pCalDigi.GetCharge() - diamondPar.TOTMin) / dTotBinSize), 0); + iWx = std::min(iWx, diamondPar.numClWalkBinX - 1); - const double dDTot = (pCalDigi.GetCharge() - rpcPar.TOTMin) / dTotBinSize - (double) iWx - 0.5; + const double dDTot = (pCalDigi.GetCharge() - diamondPar.TOTMin) / dTotBinSize - (double) iWx - 0.5; double dWT = walk[iWx]; // linear interpolation to next bin if (dDTot > 0) { - if (iWx < rpcPar.numClWalkBinX - 1) { + if (iWx < diamondPar.numClWalkBinX - 1) { dWT += dDTot * (walk[iWx + 1] - walk[iWx]); } } diff --git a/algo/detectors/bmon/Calibrate.h b/algo/detectors/bmon/Calibrate.h index 291a6882b4074035b2e0c3f01429dff069806a08..72d3914794d5bfa1161e1ee37052e4d658625b25 100644 --- a/algo/detectors/bmon/Calibrate.h +++ b/algo/detectors/bmon/Calibrate.h @@ -13,7 +13,6 @@ #include "PartitionedVector.h" #include "bmon/CalibrateSetup.h" #include "tof/Calibrate.h" // for the monitor data -#include "tof/Clusterizer.h" #include <gsl/span> #include <optional> @@ -42,9 +41,15 @@ namespace cbm::algo::bmon resultType operator()(gsl::span<const CbmBmonDigi> digiIn); private: + /// \brief A digi address + size_t GetDiamondIndex(uint32_t address) const + { + return ((fSetup.selectionMask & address) >> fSelectionBitsOffset); + } + CalibrateSetup fSetup; ///< Parameters of calibrator - std::vector<double> fChannelDeadTime; ///< Storage for dead time check - std::vector<size_t> fSmOffset; ///< Super module offset - std::vector<size_t> fRpcOffset; ///< RPC offset + std::vector<size_t> fChannelOffset; ///< Channel offset: offset for the channel index of each diamond + std::vector<double> fChannelDeadTime; ///< Channel dead time + uint32_t fSelectionBitsOffset; ///< Number of bits to ther right from the first bit in the selection mask }; } // namespace cbm::algo::bmon diff --git a/algo/detectors/bmon/CalibrateSetup.h b/algo/detectors/bmon/CalibrateSetup.h index 0d9dedd93c2b547e3f40768988dfa5c2d003233c..26803bd010da857a78908b48da369e043566dba7 100644 --- a/algo/detectors/bmon/CalibrateSetup.h +++ b/algo/detectors/bmon/CalibrateSetup.h @@ -22,12 +22,12 @@ namespace cbm::algo::bmon /// \struct CalibrateSetup /// \brief BMON calibration per channel struct CalibrateSetup { - + // FIXME: remove 'v' from non-vector variable names struct Channel { - std::vector<double> vCPTOff; - std::vector<double> vCPTotGain; - std::vector<double> vCPTotOff; - std::vector<std::vector<double>> vCPWalk; + double vCPTOff; + double vCPTotGain; + double vCPTotOff; + std::vector<double> vCPWalk; CBM_YAML_PROPERTIES(yaml::Property(&Channel::vCPTOff, "vCPTOff", "CPT offset"), yaml::Property(&Channel::vCPTotGain, "vCPTotGain", "CP time over threshold gain"), @@ -35,7 +35,8 @@ namespace cbm::algo::bmon yaml::Property(&Channel::vCPWalk, "vCPWalk", "CP walk correction", YAML::Block, YAML::Flow)); }; - struct Rpc { + struct Diamond { + uint32_t refAddress; int32_t numClWalkBinX; double TOTMax; double TOTMin; @@ -43,25 +44,23 @@ namespace cbm::algo::bmon double channelDeadtime; std::vector<Channel> chanPar; - CBM_YAML_PROPERTIES(yaml::Property(&Rpc::numClWalkBinX, "numClWalkBinX", "number of walk correction bins"), - yaml::Property(&Rpc::TOTMax, "TOTMax", "maximum time over threshold"), - yaml::Property(&Rpc::TOTMin, "TOTMin", "minimum time over threshold"), - yaml::Property(&Rpc::swapChannelSides, "swapChannelSides", "flag for swapping channel sides"), - yaml::Property(&Rpc::channelDeadtime, "channelDeadtime", "channel dead time"), - yaml::Property(&Rpc::chanPar, "chanPar", "channel parameters")); + CBM_YAML_PROPERTIES( + yaml::Property(&Diamond::refAddress, "refAddress", "reference HW address to distinguish this BMON"), + yaml::Property(&Diamond::numClWalkBinX, "numClWalkBinX", "number of walk correction bins"), + yaml::Property(&Diamond::TOTMax, "TOTMax", "maximum time over threshold"), + yaml::Property(&Diamond::TOTMin, "TOTMin", "minimum time over threshold"), + yaml::Property(&Diamond::swapChannelSides, "swapChannelSides", "flag for swapping channel sides"), + yaml::Property(&Diamond::channelDeadtime, "channelDeadtime", "channel dead time"), + yaml::Property(&Diamond::chanPar, "chanPar", "channel parameters")); }; /* Members */ - int32_t SmType; - int32_t NbSm; - int32_t NbRpc; - std::vector<Rpc> rpcs; + uint32_t selectionMask; + std::vector<Diamond> diamonds; CBM_YAML_PROPERTIES( - yaml::Property(&CalibrateSetup::SmType, "SmType", "Super module type"), - yaml::Property(&CalibrateSetup::NbSm, "NbSm", "Number of SMs"), - yaml::Property(&CalibrateSetup::NbRpc, "NbRpc", "Number of RPCs"), - yaml::Property(&CalibrateSetup::rpcs, "rpcs", "Parameters of RPCs")); + yaml::Property(&CalibrateSetup::selectionMask, "selectionMask", "A mask to distinguish between different diamonds"), + yaml::Property(&CalibrateSetup::diamonds, "diamonds", "Parameters of each diamond")); }; } // namespace cbm::algo::bmon diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index 9bdc35bb6bf856c443779334dee966ee848a8a1d..b16a463d0758b0af1d13c8c5a2154028e754df18 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -390,7 +390,7 @@ RecoResults Reco::Run(const fles::Timeslice& ts) std::set<uint32_t> bmonFoundAddressesUnp; // found addresses among unpacked bmon digis std::set<uint32_t> bmonFoundAddressesCal; // found addresses among clalibrated bmon digis - int nEvents = 20; //events.size(); + int nEvents = events.size(); for (int iE = 0; iE < nEvents; ++iE) { //L_(info) << "-------------- event #" << iE; const auto& event = events[iE]; @@ -428,9 +428,9 @@ RecoResults Reco::Run(const fles::Timeslice& ts) stsMinT = std::min(stsMinT, digi.GetTime()); stsMaxT = std::max(stsMaxT, digi.GetTime()); } - L_(info) << "BMON time: " << bmonMinT << ", " << bmonMaxT << ", " << (bmonMaxT - bmonMinT); - L_(info) << "TOF time: " << tofMinT << ", " << tofMaxT << ", " << (tofMaxT - tofMinT); - L_(info) << "STS time: " << stsMinT << ", " << stsMaxT << ", " << (stsMaxT - stsMinT); + //L_(info) << "BMON time: " << bmonMinT << ", " << bmonMaxT << ", " << (bmonMaxT - bmonMinT); + //L_(info) << "TOF time: " << tofMinT << ", " << tofMaxT << ", " << (tofMaxT - tofMinT); + //L_(info) << "STS time: " << stsMinT << ", " << stsMaxT << ", " << (stsMaxT - stsMinT); } L_(info) << "!!!! Found addresses in BMON after unpacking: "; for (auto address : bmonFoundAddressesUnp) { diff --git a/core/data/tof/CbmTofAddress.h b/core/data/tof/CbmTofAddress.h index 3abf9b170309c5d97d0ee02f8a8fe01d7d2651be..d174064bf263428eb7fb2f6a8cc87a4b9bf9351f 100644 --- a/core/data/tof/CbmTofAddress.h +++ b/core/data/tof/CbmTofAddress.h @@ -182,6 +182,7 @@ public: static std::string ToString(int32_t address); private: + // FIXME: SZh 7.2.2025: Make these fields constexpr /** ** To adapt the address sub-fields repartition in size, ** you just need to change number of bits of the two sub-fields changing length. diff --git a/external/InstallParameter.cmake b/external/InstallParameter.cmake index b368899baf13fbb817e5b97a7dcb7cb6fb5fd3ed..74e6f43126f4c5990ecbe4300caade7e4469b631 100644 --- a/external/InstallParameter.cmake +++ b/external/InstallParameter.cmake @@ -1,7 +1,5 @@ set(PARAMETER_VERSION ab9972f137bc52efd58bf3672e670a2d4fbcb1be) # 2025/02/11 set(PARAMETER_SRC_URL "https://git.cbm.gsi.de/CbmSoft/cbmroot_parameter.git") -#set(PARAMETER_VERSION 96b2189ac86b3d49c32f63da76e68f66544bba55) # 2025/05/02, BMON hitfinder parameters for online -#set(PARAMETER_SRC_URL "https://git.cbm.gsi.de/s.zharko/cbmroot_parameter.git") download_project_if_needed(PROJECT Parameter_source GIT_REPOSITORY ${PARAMETER_SRC_URL}