diff --git a/core/data/base/CbmDigiBranch.h b/core/data/base/CbmDigiBranch.h index 4820d6bf9a1da12b93f242d7b918ce9a3c0eadb8..73c9ca535b485108fc79ee2af735e096ef55538e 100644 --- a/core/data/base/CbmDigiBranch.h +++ b/core/data/base/CbmDigiBranch.h @@ -173,6 +173,22 @@ public: } // ----------------------------------------------------------------------- + // ----------------------------------------------------------------------- + /** @brief Get branch pointer + ** @return Pointer to the connected data container + ** A std::vector is first looked for; if not found, a TClonesArray + ** is looked for. + ** Returns a null pointer if the branch is not present. + **/ + virtual boost::any GetBranchContainer() const + { + if (fDigiVector) return fDigiVector; + else if (fDigiArray) + return fDigiArray; + return nullptr; + } + // ----------------------------------------------------------------------- + private: const std::vector<Digi>* fDigiVector; //! Vector of Digi objects diff --git a/core/data/base/CbmDigiBranchBase.h b/core/data/base/CbmDigiBranchBase.h index 1b33cfdee25d838162b8c883baf719eb213006da..7e9c06637f366172477385c5d7d008f04b9b73ba 100644 --- a/core/data/base/CbmDigiBranchBase.h +++ b/core/data/base/CbmDigiBranchBase.h @@ -79,6 +79,8 @@ public: /** @brief String output **/ virtual std::string ToString() const { return ""; } + /** @brief Get branch pointer **/ + virtual boost::any GetBranchContainer() const { return nullptr; } protected: TString fName; ///< Branch name diff --git a/core/data/test/trd/_GTestCbmTrdDigi.cxx b/core/data/test/trd/_GTestCbmTrdDigi.cxx index 75f4e69fe84d3b448f70bb13557fdc027494549e..19ca86d9c6e5dc67ea8af7967738c162659d6285 100644 --- a/core/data/test/trd/_GTestCbmTrdDigi.cxx +++ b/core/data/test/trd/_GTestCbmTrdDigi.cxx @@ -28,13 +28,13 @@ TEST(_GTestCbmTrdDigi, CheckStandardConstructor) Double_t charge = 42.42; ULong64_t digiTime = 42001; Int_t errClass = 0; - CbmTrdDigi test(padChNr, uniqueModuleId, charge, digiTime, ((Int_t) CbmTrdDigi::kSelf), errClass); - compareTrdDigiDataMembers(test, padChNr, ECbmModuleId::kTrd, digiTime, charge); + CbmTrdDigi test(padChNr, uniqueModuleId, charge, digiTime, CbmTrdDigi::eTriggerType::kSelf, errClass); + compareTrdDigiDataMembers(test, padChNr, ECbmModuleId::kTrd, digiTime, CbmTrdDigi::eTriggerType::kSelf, charge); - CbmTrdDigi* test1 = new CbmTrdDigi(padChNr, uniqueModuleId, charge, digiTime, ((Int_t) CbmTrdDigi::kSelf), errClass); + CbmTrdDigi* test1 = + new CbmTrdDigi(padChNr, uniqueModuleId, charge, digiTime, CbmTrdDigi::eTriggerType::kSelf, errClass); - compareTrdDigiDataMembers(*test1, padChNr, ECbmModuleId::kTrd, digiTime, charge); - ; + compareTrdDigiDataMembers(*test1, padChNr, ECbmModuleId::kTrd, digiTime, CbmTrdDigi::eTriggerType::kSelf, charge); } diff --git a/core/data/test/trd/compareTrdDigi.h b/core/data/test/trd/compareTrdDigi.h index 2c7217574ca5c970379b049b10025725f34dd8f7..d1bddf259fa96359e3b2d9340923f9a7f515e9ea 100644 --- a/core/data/test/trd/compareTrdDigi.h +++ b/core/data/test/trd/compareTrdDigi.h @@ -33,4 +33,34 @@ void compareTrdDigiDataMembers(CbmTrdDigi& test, Int_t padChNr, ECbmModuleId sys EXPECT_FLOAT_EQ(static_cast<Double_t>(charge), retValDouble); } +void compareTrdDigiDataMembers(CbmTrdDigi& test, Int_t padChNr, ECbmModuleId systemid, ULong64_t time, + CbmTrdDigi::eTriggerType triggerType, Double_t charge) +{ + Int_t retValInt {-222}; + Double_t retValDouble {-222.}; + ECbmModuleId retVal {ECbmModuleId::kNotExist}; + + retValInt = test.GetAddressChannel(); + EXPECT_EQ(padChNr, retValInt); + + retValInt = test.GetAddressModule(); + EXPECT_EQ((Int_t) systemid, retValInt); + + // GetAddress() returns the full Address part of the fInfo data member. However, since Module-5 translated via CbmTrdAddress corresponds to the value 0 it should return the setted channel number. + retValInt = test.GetAddress(); + EXPECT_EQ(padChNr, retValInt); + + retVal = test.GetSystem(); + EXPECT_EQ(systemid, retVal); + + retValDouble = test.GetTime(); + EXPECT_FLOAT_EQ(static_cast<Double_t>(time), retValDouble); + + retValDouble = test.GetCharge(); + EXPECT_FLOAT_EQ(static_cast<Double_t>(charge), retValDouble); + + retValInt = test.GetTriggerType(); + EXPECT_EQ(static_cast<Int_t>(triggerType), retValInt); +} + #endif // COMPARETRDDIGI_H diff --git a/core/data/trd/CbmTrdDigi.cxx b/core/data/trd/CbmTrdDigi.cxx index 57adc84d87662cf07d96cd88dc69c5393356f0d3..60a685cba770908ae474813f2293d83fd1ebbb9b 100644 --- a/core/data/trd/CbmTrdDigi.cxx +++ b/core/data/trd/CbmTrdDigi.cxx @@ -28,15 +28,13 @@ using std::stringstream; * M - module id in the layer * p - pad address within the module */ -Double_t CbmTrdDigi::fgClk[] = {62.5, 12.5}; -Float_t CbmTrdDigi::fgPrecission[] = {1.e3, 1.}; -//__________________________________________________________________________________________ + +const Double_t CbmTrdDigi::fgClk[] = {62.5, 12.5, 0.0}; +const Float_t CbmTrdDigi::fgPrecission[] = {1.e3, 1., 0.0}; +//_________________________________________________________________________________ CbmTrdDigi::CbmTrdDigi() : fInfo(0), fCharge(0), fTime(0) {} -//__________________________________________________________________________________________ -CbmTrdDigi::CbmTrdDigi(Int_t padChNr, Float_t chargeT, Float_t chargeR, ULong64_t time) - : fInfo(0) - , fCharge(0.) - , fTime(time) +//_________________________________________________________________________________ +CbmTrdDigi::CbmTrdDigi(Int_t padChNr, Float_t chargeT, Float_t chargeR, ULong64_t time) : fTime(time) { /** Fill data structure according to FASP representation * A - Asic type according to CbmTrdAsicType @@ -48,17 +46,15 @@ CbmTrdDigi::CbmTrdDigi(Int_t padChNr, Float_t chargeT, Float_t chargeR, ULong64_ * t - tilt paired charge * r - rectangle paired charge */ - SetAsic(kFASP); + SetAsic(eCbmTrdAsicType::kFASP); SetChannel(padChNr); SetCharge(chargeT, chargeR); } -//__________________________________________________________________________________________ -CbmTrdDigi::CbmTrdDigi(Int_t padChNr, Int_t uniqueModuleId, Float_t charge, ULong64_t time, Int_t triggerType, +//_________________________________________________________________________________ +CbmTrdDigi::CbmTrdDigi(Int_t padChNr, Int_t uniqueModuleId, Float_t charge, ULong64_t time, eTriggerType triggerType, Int_t errClass) - : fInfo(0) - , fCharge(0.) - , fTime(time) + : fTime(time) { /** * Fill data structure according to SPADIC representation @@ -70,7 +66,7 @@ CbmTrdDigi::CbmTrdDigi(Int_t padChNr, Int_t uniqueModuleId, Float_t charge, ULon * p - pad address within the module * fCharge definition UInt_t(charge*fgPrecission) */ - SetAsic(kSPADIC); + SetAsic(eCbmTrdAsicType::kSPADIC); SetChannel(padChNr); SetAddress(uniqueModuleId); SetCharge(charge); @@ -78,10 +74,18 @@ CbmTrdDigi::CbmTrdDigi(Int_t padChNr, Int_t uniqueModuleId, Float_t charge, ULon SetErrorClass(errClass); } -//__________________________________________________________________________________________ +// ---- Copy c'tor ---- +CbmTrdDigi::CbmTrdDigi(const CbmTrdDigi& digi) +{ + fInfo = digi.fInfo; + fCharge = digi.fCharge; + fTime = digi.fTime; +} + +//_________________________________________________________________________________ void CbmTrdDigi::AddCharge(CbmTrdDigi* sd, Double_t f) { - if (GetType() != kFASP) { + if (GetType() != eCbmTrdAsicType::kFASP) { LOG(warn) << "CbmTrdDigi::AddCharge(CbmTrdDigi*, Double_t) : Only available for " "FASP. Use AddCharge(Double_t, Double_t) instead."; return; @@ -90,9 +94,10 @@ void CbmTrdDigi::AddCharge(CbmTrdDigi* sd, Double_t f) UInt_t t = ((fCharge & 0xfff000) >> 12), r = (fCharge & 0xfff), ts = ((sd->fCharge & 0xfff000) >> 12), rs = (sd->fCharge & 0xfff); // apply correction factor to charge - Float_t tsf = f * ts / fgPrecission[kFASP], rsf = f * rs / fgPrecission[kFASP]; - ts = tsf * fgPrecission[kFASP]; - rs = rsf * fgPrecission[kFASP]; + Float_t tsf = f * ts / fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kFASP)], + rsf = f * rs / fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kFASP)]; + ts = tsf * fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kFASP)]; + rs = rsf * fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kFASP)]; if (t + ts < 0xfff) t += ts; else @@ -105,10 +110,10 @@ void CbmTrdDigi::AddCharge(CbmTrdDigi* sd, Double_t f) fCharge |= dt << 24; } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ void CbmTrdDigi::AddCharge(Double_t c, Double_t f) { - if (GetType() != kSPADIC) { + if (GetType() != eCbmTrdAsicType::kSPADIC) { LOG(warn) << "CbmTrdDigi::AddCharge(Double_t, Double_t) : Only available " "for SPADIC. Use AddCharge(CbmTrdDigi*, Double_t) instead."; return; @@ -116,7 +121,7 @@ void CbmTrdDigi::AddCharge(Double_t c, Double_t f) SetCharge(GetCharge() + f * c); } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ Int_t CbmTrdDigi::GetAddressChannel() const { /** Returns index of the read-out unit in the module in the format row x ncol + col @@ -124,7 +129,7 @@ Int_t CbmTrdDigi::GetAddressChannel() const return (fInfo >> fgkRoOffset) & 0xfff; } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ Int_t CbmTrdDigi::GetAddressModule() const { /** Convert internal representation of module address to CBM address as defined in CbmTrdAddress @@ -132,18 +137,18 @@ Int_t CbmTrdDigi::GetAddressModule() const return CbmTrdAddress::GetAddress(Layer(), Module(), 0, 0, 0); } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ Double_t CbmTrdDigi::GetCharge() const { - if (GetType() != kSPADIC) { + if (GetType() != eCbmTrdAsicType::kSPADIC) { LOG(warn) << "CbmTrdDigi::GetCharge() : Use Double_t GetCharge(Double_t " "&tilt) instead."; return 0; } - return fCharge / fgPrecission[kSPADIC]; + return fCharge / fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kSPADIC)]; } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ Double_t CbmTrdDigi::GetCharge(Double_t& tilt, Int_t& dt) const { /** Retrieve signal information for FASP. @@ -152,43 +157,43 @@ Double_t CbmTrdDigi::GetCharge(Double_t& tilt, Int_t& dt) const * T : tilt pads signal * R : Rectangular pads signal */ - if (GetType() != kFASP) { + if (GetType() != eCbmTrdAsicType::kFASP) { LOG(warn) << "CbmTrdDigi::GetCharge(Double_t &) : Use Double_t GetCharge() " "instead."; return 0; } Char_t toff = fCharge >> 24; dt = toff; - tilt = ((fCharge & 0xfff000) >> 12) / fgPrecission[kFASP]; - return (fCharge & 0xfff) / fgPrecission[kFASP]; + tilt = ((fCharge & 0xfff000) >> 12) / fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kFASP)]; + return (fCharge & 0xfff) / fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kFASP)]; } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ Double_t CbmTrdDigi::GetChargeError() const { return 0; } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ Bool_t CbmTrdDigi::IsFlagged(const Int_t iflag) const { if (iflag < 0 || iflag >= kNflags) return kFALSE; return (fInfo >> (fgkFlgOffset + iflag)) & 0x1; } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ void CbmTrdDigi::SetAddress(Int_t address) { SetLayer(CbmTrdAddress::GetLayerId(address)); SetModule(CbmTrdAddress::GetModuleId(address)); } -//__________________________________________________________________________________________ -void CbmTrdDigi::SetAsic(CbmTrdAsicType ty) +//_________________________________________________________________________________ +void CbmTrdDigi::SetAsic(eCbmTrdAsicType ty) { - if (ty == kSPADIC) CLRBIT(fInfo, fgkTypOffset); + if (ty == eCbmTrdAsicType::kSPADIC) CLRBIT(fInfo, fgkTypOffset); else SETBIT(fInfo, fgkTypOffset); } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ void CbmTrdDigi::SetCharge(Float_t cT, Float_t cR, Int_t dt) { /** Load signal information for FASP. @@ -197,7 +202,8 @@ void CbmTrdDigi::SetCharge(Float_t cT, Float_t cR, Int_t dt) * T : tilt pads signal (12 bits) * R : Rectangular pads signal (12 bits) */ - UInt_t r = UInt_t(cR * fgPrecission[kFASP]), t = UInt_t(cT * fgPrecission[kFASP]); + UInt_t r = UInt_t(cR * fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kFASP)]), + t = UInt_t(cT * fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kFASP)]); Char_t toff = dt; if (dt > 127) toff = 127; else if (dt < -127) @@ -208,17 +214,14 @@ void CbmTrdDigi::SetCharge(Float_t cT, Float_t cR, Int_t dt) fCharge |= toff << 24; } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ void CbmTrdDigi::SetCharge(Float_t c) { - // printf("SetCharge :: prec[%f] c[%f] uint[%d] \n", fgPrecission[kSPADIC],c,UInt_t(c*fgPrecission[kSPADIC])); - // std::cout<<" setcharge: "<< UInt_t(c*fgPrecission[kSPADIC])<<std::endl; - fCharge = UInt_t(c * fgPrecission[kSPADIC]); - // fCharge = UInt_t(c*1e9); + fCharge = UInt_t(c * fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kSPADIC)]); } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ void CbmTrdDigi::SetFlag(const Int_t iflag, Bool_t set) { if (iflag < 0 || iflag >= kNflags) return; @@ -227,33 +230,43 @@ void CbmTrdDigi::SetFlag(const Int_t iflag, Bool_t set) CLRBIT(fInfo, fgkFlgOffset + iflag); } -//__________________________________________________________________________________________ -void CbmTrdDigi::SetTime(Double_t t) { fTime = ULong64_t(TMath::Ceil(t / fgClk[GetType()])); } +//_________________________________________________________________________________ +void CbmTrdDigi::SetTime(Double_t t) { fTime = ULong64_t(TMath::Ceil(t / Clk(GetType()))); } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ void CbmTrdDigi::SetTimeOffset(Char_t t) { - if (GetType() != kFASP) return; + if (GetType() != eCbmTrdAsicType::kFASP) return; fCharge <<= 8; fCharge >>= 8; fCharge |= t << 24; } -//__________________________________________________________________________________________ +//_________________________________________________________________________________ +void CbmTrdDigi::SetTriggerType(const eTriggerType triggerType) +{ + if (triggerType < eTriggerType::kBeginTriggerTypes || triggerType >= eTriggerType::kNTrg) return; + const Int_t ttype = static_cast<Int_t>(triggerType); + fInfo |= (ttype << fgkTrgOffset); +} + +//_________________________________________________________________________________ void CbmTrdDigi::SetTriggerType(const Int_t ttype) { - if (ttype < kBeginTriggerTypes || ttype >= kNTrg) return; + if (ttype < static_cast<Int_t>(eTriggerType::kBeginTriggerTypes) || ttype >= static_cast<Int_t>(eTriggerType::kNTrg)) + return; fInfo |= (ttype << fgkTrgOffset); } -//__________________________________________________________________________________________ + +//_________________________________________________________________________________ string CbmTrdDigi::ToString() const { stringstream ss; - ss << "CbmTrdDigi(" << (GetType() == kFASP ? "T)" : "R)") << " | moduleAddress=" << GetAddressModule() - << " | layer=" << Layer() << " | moduleId=" << Module() << " | pad=" << GetAddressChannel() - << " | time[ns]=" << std::fixed << std::setprecision(1) << GetTime(); - if (GetType() == kFASP) { + ss << "CbmTrdDigi(" << (GetType() == eCbmTrdAsicType::kFASP ? "T)" : "R)") + << " | moduleAddress=" << GetAddressModule() << " | layer=" << Layer() << " | moduleId=" << Module() + << " | pad=" << GetAddressChannel() << " | time[ns]=" << std::fixed << std::setprecision(1) << GetTime(); + if (GetType() == eCbmTrdAsicType::kFASP) { Int_t trg(GetTriggerType()), dt; Double_t t, r = GetCharge(t, dt); Bool_t ttrg(trg & 1), rtrg((trg & 2) >> 1); diff --git a/core/data/trd/CbmTrdDigi.h b/core/data/trd/CbmTrdDigi.h index ee4c6e7ea983b0234592e024bdc4a6484ae4a363..55e3166f540e739ca4ca0a1d54894392b0835a10 100644 --- a/core/data/trd/CbmTrdDigi.h +++ b/core/data/trd/CbmTrdDigi.h @@ -17,13 +17,13 @@ class CbmTrdDigi { public: - enum CbmTrdAsicType + enum class eCbmTrdAsicType : size_t { kSPADIC = 0, kFASP, kNTypes }; - enum ECbmTrdTriggerType + enum class eTriggerType : Int_t { kBeginTriggerTypes = 0, kSelf = kBeginTriggerTypes, @@ -57,12 +57,13 @@ public: /** * \brief Constructor for the SPADIC type. * \param[in] padChNr Unique channel address in the module. + * \param[in] uniqueModuleId Unique Id of the module. * \param[in] charge Charge. * \param[in] time Absolute time [ns]. * \param[in] triggerType SPADIC trigger type see CbmTrdTriggerType. * \param[in] errClass SPADIC signal error parametrization based on message type. */ - CbmTrdDigi(Int_t padChNr, Int_t uniqueModuleId, Float_t charge, ULong64_t time, Int_t triggerType, + CbmTrdDigi(Int_t padChNr, Int_t uniqueModuleId, Float_t charge, ULong64_t time, eTriggerType triggerType, Int_t errClass /*nrSamples*/); /** @@ -78,6 +79,13 @@ public: ; } + /** + * @brief Copy Construct a new Cbm Trd Digi + * + */ + CbmTrdDigi(const CbmTrdDigi&); + + /** \brief Charge addition in case of pile-up (FASP simulation only) * \param[in] sd previous digi absorbed by current * \param[in] f scaling factor @@ -89,7 +97,7 @@ public: */ void AddCharge(Double_t c, Double_t f = 1); /** \brief DAQ clock accessor for each ASIC*/ - static Float_t Clk(CbmTrdAsicType ty) { return (ty == kNTypes ? 0 : fgClk[ty]); } + static Float_t Clk(eCbmTrdAsicType ty) { return fgClk[static_cast<size_t>(ty)]; } /** \brief Address getter for module in the format defined by CbmTrdDigi (format of CbmTrdAddress can be accessed via CbmTrdParModDigi) */ Int_t GetAddress() const { return (fInfo >> fgkRoOffset) & 0x7fffff; } @@ -125,20 +133,34 @@ public: **/ static const char* GetClassName() { return "CbmTrdDigi"; } + /** @brief Get the desired name of the branch for this obj in the cbm output tree (static) + ** @return TrdDigi + **/ + static const char* GetBranchName() { return "TrdDigi"; } + /** \brief Getter for physical time [ns]. Accounts for clock representation of each ASIC. In SPADIC case physical time is already stored in fTime. */ - Double_t GetTime() const { return (GetType() == kFASP) ? fTime * fgClk[GetType()] : fTime; } + Double_t GetTime() const + { + return (GetType() == eCbmTrdAsicType::kFASP) ? fTime * fgClk[static_cast<size_t>(GetType())] : fTime; + } /** \brief Getter for global DAQ time [clk]. Differs for each ASIC. In FASP case DAQ time is already stored in fTime.*/ - ULong64_t GetTimeDAQ() const { return (GetType() == kFASP) ? fTime : fTime / fgClk[GetType()]; } + ULong64_t GetTimeDAQ() const + { + return (GetType() == eCbmTrdAsicType::kFASP) ? fTime : fTime / fgClk[static_cast<size_t>(GetType())]; + } /** \brief Channel trigger type. SPADIC specific see CbmTrdTriggerType*/ Int_t GetTriggerType() const { return (fInfo >> fgkTrgOffset) & 0x3; } /** \brief Channel FEE SPADIC/FASP according to CbmTrdAsicType*/ - CbmTrdAsicType GetType() const { return ((fInfo >> fgkTypOffset) & 0x1) ? kFASP : kSPADIC; } + eCbmTrdAsicType GetType() const + { + return ((fInfo >> fgkTypOffset) & 0x1) ? eCbmTrdAsicType::kFASP : eCbmTrdAsicType::kSPADIC; + } /** \brief Query digi mask (FASP only)*/ - Bool_t IsMasked() const { return (GetType() == kFASP) && IsFlagged(kFlag3); } + Bool_t IsMasked() const { return (GetType() == eCbmTrdAsicType::kFASP) && IsFlagged(kFlag3); } /** \brief Query digi pile-up (FASP only)*/ - Bool_t IsPileUp() const { return (GetType() == kFASP) && IsFlagged(kFlag2); } + Bool_t IsPileUp() const { return (GetType() == eCbmTrdAsicType::kFASP) && IsFlagged(kFlag2); } /** \brief Query flag status (generic)*/ Bool_t IsFlagged(const Int_t iflag) const; Int_t Layer() const { return (fInfo >> fgkLyOffset) & 0xf; } @@ -151,7 +173,7 @@ public: /** \brief Alias for SetAddress() */ void SetAddressModule(const Int_t a) { SetAddress(a); } - void SetAsic(CbmTrdAsicType ty = kSPADIC); + void SetAsic(eCbmTrdAsicType ty = eCbmTrdAsicType::kSPADIC); /** \brief Charge setter for SPADIC ASIC * \param[in] c charge on read-out pad */ @@ -167,12 +189,12 @@ public: /** \brief Set digi mask (FASP only)*/ void SetMasked(Bool_t set = kTRUE) { - if (GetType() == kFASP) SetFlag(kFlag3, set); + if (GetType() == eCbmTrdAsicType::kFASP) SetFlag(kFlag3, set); } /** \brief Set digi pile-up (FASP only)*/ void SetPileUp(Bool_t set = kTRUE) { - if (GetType() == kFASP) SetFlag(kFlag2, set); + if (GetType() == eCbmTrdAsicType::kFASP) SetFlag(kFlag2, set); } /** \brief Set global digi time (ns)*/ void SetTime(Double_t t); @@ -180,8 +202,10 @@ public: void SetTimeDAQ(ULong64_t t) { fTime = t; } /** \brief Set time offset of rectangular to tilt pads for FASP (clk)*/ void SetTimeOffset(Char_t t); - /** \brief Set digi trigger type (SPADIC only)*/ - void SetTriggerType(const Int_t ttype); + /** \brief Set digi trigger type */ + void SetTriggerType(const eTriggerType triggerType); + /** \brief Set digi trigger type */ + void SetTriggerType(const Int_t triggerValue); /** \brief Set digi error class (SPADIC only)*/ void SetErrorClass(const Int_t n) { @@ -219,13 +243,23 @@ protected: fInfo |= ((a & 0x7f) << fgkModOffset); } - UInt_t fInfo; //< pad address and extra information - UInt_t fCharge; //< measured charge. For SPADIC is Int_t(charge*1eN) where N is the precission while + UInt_t fInfo = 0; //< pad address and extra information + UInt_t fCharge = 0; //< measured charge. For SPADIC is Int_t(charge*1eN) where N is the precission while //< for FASP it contains the R and T charges each on 12bits and the time difference between R and T pads in CLK (8 bits). - ULong64_t fTime; //< global time of the digi: For SPADIC in ns, for FASP in ASIC clock + ULong64_t fTime = 0; //< global time of the digi: For SPADIC in ns, for FASP in ASIC clock + + /** + * @brief clock length in ns for acquisition + * + */ + static const Double_t fgClk[static_cast<size_t>(eCbmTrdAsicType::kNTypes) + 1]; + + /** + * @brief Nr. of digits stored for ASIC + * + */ + static const Float_t fgPrecission[static_cast<size_t>(eCbmTrdAsicType::kNTypes) + 1]; - static Double_t fgClk[kNTypes]; //< clock length in ns for acquisition - static Float_t fgPrecission[kNTypes]; //< no. of digits stored for ASIC private: static const Int_t fgkRoOffset = 0; @@ -246,7 +280,7 @@ private: ar& fTime; } - ClassDefNV(CbmTrdDigi, 3); // Production ready TRD digit + ClassDefNV(CbmTrdDigi, 4); // Production ready TRD digit }; #endif diff --git a/core/data/trd/CbmTrdRawMessageSpadic.cxx b/core/data/trd/CbmTrdRawMessageSpadic.cxx index 14da8bbc0b7fb63c00e9c76246f19b0f4ae1d0dd..dfe783ee6c14e91795214735aa46cbae2496f077 100644 --- a/core/data/trd/CbmTrdRawMessageSpadic.cxx +++ b/core/data/trd/CbmTrdRawMessageSpadic.cxx @@ -26,7 +26,7 @@ CbmTrdRawMessageSpadic::CbmTrdRawMessageSpadic() // ------- Constructor ---------------- CbmTrdRawMessageSpadic::CbmTrdRawMessageSpadic(std::uint8_t channelId, std::uint8_t elinkId, std::uint8_t crobId, std::uint16_t criId, std::uint8_t hitType, std::uint8_t nrSamples, - bool multiHit, std::uint64_t fullTime, std::vector<std::int16_t> samples) + bool multiHit, size_t fullTime, std::vector<std::int16_t> samples) : fChannelID {channelId} , fElinkID {elinkId} , fCrobId(crobId) @@ -71,11 +71,13 @@ int16_t CbmTrdRawMessageSpadic::GetMaxAdc() void CbmTrdRawMessageSpadic::SetSample(std::int16_t value, std::uint8_t pos) { if (pos > 31 || value < -256 || value > 256 || pos >= fNrSamples) { - LOG(error) << "CbmTrdRawMessageSpadic::SetSample() Out of range!"; + LOG(error) << "CbmTrdRawMessageSpadic::SetSample() pos = " << static_cast<std::uint16_t>(pos) + << " fNrSamples = " << static_cast<std::uint16_t>(fNrSamples) << " value = " << value + << " so we are out of range!"; return; } if ((std::uint8_t)(pos + 1) > fSamples.size()) { fSamples.resize(pos + 1); } - fSamples[pos] = value; + fSamples.at(pos) = value; return; } diff --git a/core/data/trd/CbmTrdRawMessageSpadic.h b/core/data/trd/CbmTrdRawMessageSpadic.h index 3a02f6c6690c987a34db3bbed0460780c9b395aa..4ff1080b962c31a0a25674b8bfd035fa33ae8c51 100644 --- a/core/data/trd/CbmTrdRawMessageSpadic.h +++ b/core/data/trd/CbmTrdRawMessageSpadic.h @@ -25,23 +25,21 @@ namespace Spadic { /** Spadic Message Types that can occur inside a Microslice. * - * A message is a 64bit word, its most significant bits (MSB) define the type. + * Definition of the message types. Selection happens in the unpacker algorithms. **/ enum class MsMessageType : uint8_t { - kEPO = 0x40, ///< Epoch Marker. MSB: 01.. .... uTS-MSB (bits 61-32) in clockcycles. - kSOM = - 0x20, ///< Start of Message. MSB: 001. .... timestamp (bits 50-35) in clockcycles. Currently (Feb 2020) only 11 LSB in use. - kRDA = - 0x80, ///< Raw Data. Preceded by SOM. MSB: 1... .... always 64bits, bits after last transmitted sample are filled with 0. - kINF = - 0x10, ///< Info Message. MSB: 0001 .... The 20 LSBs of the 64bit word contain the 20 LSBs of a raw spadic InfoType frame e.g. BOM. - kNUL = 0x00, ///< Microslice End. 0x0000000000000000 Last Word in a Microslice is 64 zeros. + kSOM = 0x20, ///< Start of Message + kEOM = 0x30, ///< End of Message. + kEPO = 0x40, ///< Epoch Marker or TS_MSB depending on the hitmessage version + kRDA = 0x80, ///< Raw Data + kINF = 0x10, ///< Info Message + kNUL = 0x00, ///< Microslice End kUNK = 0x01 ///< Unkown Word. }; /** Hit Type of CbmTrdRawMessageSpadic, explains why a message was generated. */ - enum class TriggerType : uint8_t + enum class eTriggerType : uint8_t { kGlobal = 0, ///< global trigger. kSelf = 1, ///< Self trigger. @@ -57,11 +55,15 @@ namespace Spadic **/ enum class MsInfoType : uint8_t { - kBOM, ///< Buffer overflow count. 11nn nnnn nnnn nnnn cccc - kMSB, ///< Message build error. 010. .... .... .... cccc - kBUF, ///< Buffer full. 011b b... .... .... cccc - kUNU, ///< Unused request. 100. .... .... .... cccc - kMIS ///< Missing request. 101. .... .... .... .... + kBOM = 0, ///< Buffer overflow count. 11nn nnnn nnnn nnnn cccc + kMSB, ///< Message build error. 010. .... .... .... cccc + kBUF, ///< Buffer full. 011b b... .... .... cccc + kUNU, ///< Unused request. 100. .... .... .... cccc + kMIS, ///< Missing request. 101. .... .... .... .... + kChannelBuf, ///< Channel buffer full from kEPO msg + kOrdFifoBuf, ///< Multi-hit but ordering buffer full from kEPO msg + kChannelBufM, ///< Channel buffer full and multihit from kEPO msg + kNInfMsgs ///< Number of different info messages }; } // namespace Spadic @@ -82,7 +84,7 @@ private: std::uint8_t fHitType; std::uint8_t fNrSamples; bool fMultiHit; - std::uint64_t fFullTime; /**< Fulltime in units of Clockcycles. */ + size_t fFullTime; /**< Fulltime in units of Clockcycles. */ std::vector<std::int16_t> fSamples; /**< Holds up to 32 Samples from a Spadic Message. Valid values [-256,255] */ public: @@ -91,7 +93,7 @@ public: /** Constructor **/ CbmTrdRawMessageSpadic(std::uint8_t channelId, std::uint8_t elinkId, std::uint8_t crobId, std::uint16_t criId, - std::uint8_t hitType, std::uint8_t nrSamples, bool multiHi, std::uint64_t fullTime, + std::uint8_t hitType, std::uint8_t nrSamples, bool multiHi, size_t fullTime, std::vector<std::int16_t> samples); /** Copy Constructor **/ @@ -105,6 +107,7 @@ public: CbmTrdRawMessageSpadic& operator=(const CbmTrdRawMessageSpadic&) = default; // ----------------- Getters ----------------------------- + static const char* GetBranchName() { return "CbmTrdRawMessageSpadic"; } std::uint8_t GetChannelId() const { return fChannelID; } std::uint8_t GetElinkId() const { return fElinkID; } @@ -113,14 +116,17 @@ public: std::uint8_t GetHitType() const { return fHitType; } std::uint8_t GetNrSamples() const { return fNrSamples; } bool GetMultiHit() const { return fMultiHit; } - std::uint64_t GetFullTime() const { return fFullTime; } - const std::vector<std::int16_t> GetSamples() const { return fSamples; } + size_t GetFullTime() const { return fFullTime; } + const std::vector<std::int16_t>* GetSamples() const { return &fSamples; } /** Returns the full time in nanoseconds */ Double_t GetTime() const { return fFullTime * 62.5; } + /** @brief increase the number of samples stored in this raw message by one */ + void IncNrSamples() { fNrSamples++; } + /** Set the full time in nanoseconds */ - void SetTime(Double_t setvalue) { fFullTime = (std::uint64_t)(setvalue / 62.5); } + void SetTime(Double_t setvalue) { fFullTime = (size_t)(setvalue / 62.5); } /** Returns the value of the sample with the highest value. */ int16_t GetMaxAdc(); diff --git a/core/detectors/trd/CMakeLists.txt b/core/detectors/trd/CMakeLists.txt index 871ab6f0b2047904a140f49758cc509f5a5b5daf..e4e8f8886edcdd57c7465c05360a9ca5482f64a8 100644 --- a/core/detectors/trd/CMakeLists.txt +++ b/core/detectors/trd/CMakeLists.txt @@ -42,7 +42,7 @@ CbmTrdParSetDigi.cxx CbmTrdParMod.cxx CbmTrdParAsic.cxx CbmTrdParSpadic.cxx -CbmTrdSPADIC.cxx +CbmTrdSpadic.cxx CbmTrdFASP.cxx CbmTrdParFasp.cxx CbmTrdParModDigi.cxx @@ -52,6 +52,7 @@ CbmTrdParModGeo.cxx #tools CbmTrdGeoHandler.cxx CbmTrdUtils.cxx +CbmTrddEdxUtils.cxx CbmTrdHardwareSetupR.cxx CbmTrdRadiator.cxx ) diff --git a/core/detectors/trd/CbmTrdBaseLinkDef.h b/core/detectors/trd/CbmTrdBaseLinkDef.h index 85fb599dbbda4950b7922c5d989dac7f8ce2443a..f1cb16ad5c664421bcefac4dc3cff5da5b3586b6 100644 --- a/core/detectors/trd/CbmTrdBaseLinkDef.h +++ b/core/detectors/trd/CbmTrdBaseLinkDef.h @@ -12,7 +12,7 @@ #pragma link C++ class CbmTrdGas + ; #pragma link C++ class CbmTrdContFact + ; -#pragma link C++ class CbmMcbm2020TrdTshiftPar +; +#pragma link C++ class CbmMcbm2020TrdTshiftPar + ; #pragma link C++ class CbmTrdModuleAbstract + ; #pragma link C++ class CbmTrdParManager + ; @@ -25,7 +25,7 @@ #pragma link C++ class CbmTrdParMod + ; #pragma link C++ class CbmTrdParAsic + ; #pragma link C++ class CbmTrdParSpadic + ; -#pragma link C++ class CbmTrdSPADIC + ; +#pragma link C++ class CbmTrdSpadic + ; #pragma link C++ class CbmTrdFASP + ; #pragma link C++ class CbmTrdParFasp + ; #pragma link C++ class CbmTrdParFaspChannel + ; @@ -35,6 +35,7 @@ #pragma link C++ class CbmTrdParModDigi + ; //tools #pragma link C++ class CbmTrdGeoHandler + ; +#pragma link C++ class CbmTrddEdxUtils + ; #pragma link C++ class CbmTrdUtils + ; #pragma link C++ class CbmTrdHardwareSetupR + ; #pragma link C++ class CbmTrdRadiator + ; diff --git a/core/detectors/trd/CbmTrdFASP.cxx b/core/detectors/trd/CbmTrdFASP.cxx index 6693c8814ff4e08d587b98d4c11a5811282a07bc..fcd255666bdbb3fce900ebe56451b804a8f838d6 100644 --- a/core/detectors/trd/CbmTrdFASP.cxx +++ b/core/detectors/trd/CbmTrdFASP.cxx @@ -5,7 +5,7 @@ #include "CbmTrdFASP.h" #include "CbmMatch.h" // for CbmMatch -#include "CbmTrdDigi.h" // for CbmTrdDigi, CbmTrdDigi::kFASP +#include "CbmTrdDigi.h" // for CbmTrdDigi, CbmTrdDigi::eCbmTrdAsicType::kFASP #include <Logger.h> // for Logger, LOG @@ -313,9 +313,9 @@ void CbmTrdFASP::Print(Option_t* opt) const printf("FASP Simulator : Col[%2d] NeighbourTrigger[%c]\n", fCol, fgNeighbour ? 'y' : 'n'); printf(" Main CH : Trigger[V]=%4.2f Flat-Top[ns]=%5.1f\n", fgShaperThr, - fgkNclkFT * CbmTrdDigi::Clk(CbmTrdDigi::kFASP)); + fgkNclkFT * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP)); printf(" Neighbour CH : Trigger[V]=%4.2f Linear-gate[ns]=%5.1f\n", fgNeighbourThr, - fgNclkLG * CbmTrdDigi::Clk(CbmTrdDigi::kFASP)); + fgNclkLG * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP)); if (strcmp(opt, "all") != 0) return; Int_t time = 0; @@ -396,7 +396,7 @@ Int_t CbmTrdFASP::ProcessShaper(Char_t typ) if (fTimeLG < 0) { // check if linear-gate is closed if ((fgNeighbour && (htf_prev || htf || htf_next)) || (!fgNeighbour && htf)) { lg_cmd = 1; - fTimeLG = i + 0.2 * fgNclkLG * CbmTrdDigi::Clk(CbmTrdDigi::kFASP); + fTimeLG = i + 0.2 * fgNclkLG * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP); if (VERBOSE) printf(" %4lu : LG_CMD 1 -> MinGateEnd[ns]=%d\n", i * 5, fTimeLG * 5); } } @@ -425,7 +425,7 @@ Int_t CbmTrdFASP::ProcessShaper(Char_t typ) if (VERBOSE) printf(" %4lu : MAX[V]=%5.2f\n", i * 5, max); } if (out < max - 0.05) { - fTimeFT = i + 0.2 * fgkNclkFT * CbmTrdDigi::Clk(CbmTrdDigi::kFASP); + fTimeFT = i + 0.2 * fgkNclkFT * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP); fTimeDY = -1; fFT = max + 0.01; // save data for digi update @@ -821,9 +821,10 @@ void CbmTrdFASP::WriteDigi() printf(" [R] ht[ns]=%4d CS[ns]=%4d FT[ADC]=%4u Trg[%s]\n", hTime, csTime, get<2>(*jt), (get<3>(*jt) ? "S" : "N")); if (dtime) { - if (csTime > dtime) ddt = TMath::Ceil(Int_t(csTime - dtime) / CbmTrdDigi::Clk(CbmTrdDigi::kFASP)); + if (csTime > dtime) + ddt = TMath::Ceil(Int_t(csTime - dtime) / CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP)); else - ddt = TMath::Floor(Int_t(csTime - dtime) / CbmTrdDigi::Clk(CbmTrdDigi::kFASP)); + ddt = TMath::Floor(Int_t(csTime - dtime) / CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP)); } else dtime = csTime; diff --git a/core/detectors/trd/CbmTrdHardwareSetupR.cxx b/core/detectors/trd/CbmTrdHardwareSetupR.cxx index f75dd303a73d3c6876fd5ccf0d8e166c6c95ad23..dad35997b13fea13ff881ef0dcdcf28ae1dcc5eb 100644 --- a/core/detectors/trd/CbmTrdHardwareSetupR.cxx +++ b/core/detectors/trd/CbmTrdHardwareSetupR.cxx @@ -21,7 +21,7 @@ #include <TArrayI.h> // for TArrayI #include <TString.h> // for Form, TString -#include <cstdint> // for uint64_t +#include <cstdint> // for size_t #include <map> // for map, __map_iterator #include <utility> // for pair #include <vector> // for vector @@ -33,16 +33,16 @@ CbmTrdHardwareSetupR::CbmTrdHardwareSetupR(/* args */) : fComponentIdMap(), fPar CbmTrdHardwareSetupR::~CbmTrdHardwareSetupR() {} // ---- GetComponentId ---------------------------------------------------- -std::uint64_t CbmTrdHardwareSetupR::GetComponentId(Int_t asicAddress, ECbmTrdHardwareSetupVersion hwSetup) +size_t CbmTrdHardwareSetupR::GetComponentId(Int_t asicAddress, ECbmTrdHardwareSetupVersion hwSetup) { SelectComponentIdMap(hwSetup); return GetComponentId(asicAddress); } // ---- GetComponentId ---------- ----------------------------------------- -std::uint64_t CbmTrdHardwareSetupR::GetComponentId(Int_t asicAddress) +size_t CbmTrdHardwareSetupR::GetComponentId(Int_t asicAddress) { - std::uint64_t componentId(-1); + size_t componentId(-1); if (fComponentIdMap.empty()) { LOG(error) << Form("Seems like the component map is empty. If you selected a hardware " "setup, check that there is a correct map for this setup. Else select a " @@ -53,8 +53,8 @@ std::uint64_t CbmTrdHardwareSetupR::GetComponentId(Int_t asicAddress) return componentId; } -// ---- CreateHwToSwAsicAddressTranslatorMap -------------------------------------- -std::map<std::uint64_t, Int_t> CbmTrdHardwareSetupR::CreateHwToSwAsicAddressTranslatorMap(bool isLoadedParameters) +// ---- CreateHwToSwAsicAddressTranslatorMap ---- +std::map<size_t, Int_t> CbmTrdHardwareSetupR::CreateHwToSwAsicAddressTranslatorMap(bool isLoadedParameters) { FairRuntimeDb* rtdb = FairRuntimeDb::instance(); CbmTrdParSetAsic* moduleAsicParSets = @@ -68,11 +68,18 @@ std::map<std::uint64_t, Int_t> CbmTrdHardwareSetupR::CreateHwToSwAsicAddressTran parInAsic.close(); } + return CreateHwToSwAsicAddressTranslatorMap(moduleAsicParSets); +} + +// ---- CreateHwToSwAsicAddressTranslatorMap ---- +std::map<size_t, Int_t> CbmTrdHardwareSetupR::CreateHwToSwAsicAddressTranslatorMap(CbmTrdParSetAsic* moduleparsets) +{ + Int_t nModuleAsicParSets(0); - nModuleAsicParSets = moduleAsicParSets->GetNrOfModules(); + nModuleAsicParSets = moduleparsets->GetNrOfModules(); FairParamList moduleAsicParSetsList; - moduleAsicParSets->putParams(&moduleAsicParSetsList); + moduleparsets->putParams(&moduleAsicParSetsList); TArrayI uniqueModuleIds(nModuleAsicParSets); moduleAsicParSetsList.fill("ModuleId", &uniqueModuleIds); @@ -80,14 +87,14 @@ std::map<std::uint64_t, Int_t> CbmTrdHardwareSetupR::CreateHwToSwAsicAddressTran CbmTrdParSpadic* currentSpadicPar = nullptr; Int_t currentUniqueModuleId(-1); - std::uint64_t currentSpadicCompId(100098); + size_t currentSpadicCompId(100098); - std::map<std::uint64_t, Int_t> + std::map<size_t, Int_t> spadicHwMap; // keyA = CriId+CrobId+ElinkId decoded with CbmTrdParAsic::ECbmTrdComponentIdDecoding, keyB = uniqueAsicAddress for (Int_t iModule = 0; iModule < nModuleAsicParSets; iModule++) { currentUniqueModuleId = uniqueModuleIds[iModule]; - moduleAsicsParSet = (CbmTrdParSetAsic*) moduleAsicParSets->GetModuleSet(currentUniqueModuleId); + moduleAsicsParSet = (CbmTrdParSetAsic*) moduleparsets->GetModuleSet(currentUniqueModuleId); std::vector<Int_t> asicAddresses; moduleAsicsParSet->GetAsicAddresses(&asicAddresses); for (auto iAsicIt : asicAddresses) { @@ -113,12 +120,12 @@ std::map<std::uint64_t, Int_t> CbmTrdHardwareSetupR::CreateHwToSwAsicAddressTran return spadicHwMap; } -// ---- CreateAsicChannelMap -------------------------------------- +// ---- CreateAsicChannelMap ---- std::map<Int_t, std::vector<Int_t>> CbmTrdHardwareSetupR::CreateAsicChannelMap(bool isLoadedParameters) { - FairRuntimeDb* rtdb = FairRuntimeDb::instance(); - CbmTrdParSetAsic* moduleAsicParSets = - (CbmTrdParSetAsic*) rtdb->getContainer("CbmTrdParSetAsic"); // Container for all ParSets of Module AsicParSets; + FairRuntimeDb* rtdb = FairRuntimeDb::instance(); + CbmTrdParSetAsic* moduleAsicParSets = (CbmTrdParSetAsic*) rtdb->getContainer("CbmTrdParSetAsic"); + // Container for all ParSets of Module AsicParSets; if (!isLoadedParameters) { FairParAsciiFileIo parInAsic; @@ -127,12 +134,18 @@ std::map<Int_t, std::vector<Int_t>> CbmTrdHardwareSetupR::CreateAsicChannelMap(b rtdb->initContainers(0); // no run defined for the time being parInAsic.close(); } + return CreateAsicChannelMap(moduleAsicParSets); +} + +// ---- CreateAsicChannelMap ---- +std::map<Int_t, std::vector<Int_t>> CbmTrdHardwareSetupR::CreateAsicChannelMap(CbmTrdParSetAsic* moduleparsets) +{ Int_t nModuleAsicParSets(0); - nModuleAsicParSets = moduleAsicParSets->GetNrOfModules(); + nModuleAsicParSets = moduleparsets->GetNrOfModules(); FairParamList moduleAsicParSetsList; - moduleAsicParSets->putParams(&moduleAsicParSetsList); + moduleparsets->putParams(&moduleAsicParSetsList); TArrayI uniqueModuleIds(nModuleAsicParSets); moduleAsicParSetsList.fill("ModuleId", &uniqueModuleIds); @@ -146,7 +159,7 @@ std::map<Int_t, std::vector<Int_t>> CbmTrdHardwareSetupR::CreateAsicChannelMap(b std::vector<Int_t> channelAddressVec; for (Int_t iModule = 0; iModule < nModuleAsicParSets; iModule++) { currentUniqueModuleId = uniqueModuleIds[iModule]; - moduleAsicsParSet = (CbmTrdParSetAsic*) moduleAsicParSets->GetModuleSet(currentUniqueModuleId); + moduleAsicsParSet = (CbmTrdParSetAsic*) moduleparsets->GetModuleSet(currentUniqueModuleId); std::vector<Int_t> asicAddresses; moduleAsicsParSet->GetAsicAddresses(&asicAddresses); for (auto iAsicIt : asicAddresses) { diff --git a/core/detectors/trd/CbmTrdHardwareSetupR.h b/core/detectors/trd/CbmTrdHardwareSetupR.h index 93bc667580ebdeb86e4e9711c71faf7f721c09a1..a8607f6dbeb4aead670b60d4969ce63a8c23620c 100644 --- a/core/detectors/trd/CbmTrdHardwareSetupR.h +++ b/core/detectors/trd/CbmTrdHardwareSetupR.h @@ -12,6 +12,8 @@ #ifndef CBMTRDHARDWARESETUPR_H #define CBMTRDHARDWARESETUPR_H +#include "CbmTrdParSetAsic.h" + #include <Rtypes.h> // for THashConsistencyHolder, ClassDef #include <RtypesCore.h> // for Int_t #include <TNamed.h> // for TNamed @@ -20,7 +22,7 @@ #include <map> // for map #include <vector> // for vector -#include <stdint.h> // for uint64_t +#include <stdint.h> // for size_t enum class ECbmTrdHardwareSetupVersion : Int_t { @@ -39,27 +41,56 @@ public: CbmTrdHardwareSetupR operator=(const CbmTrdHardwareSetupR&); ~CbmTrdHardwareSetupR(); - std::uint64_t - GetComponentId(Int_t asicAddress, - ECbmTrdHardwareSetupVersion - hwSetup); ///< Retrieve componentId of the asic add the passed address for the passed hwSetup - std::uint64_t GetComponentId( + size_t GetComponentId(Int_t asicAddress, + ECbmTrdHardwareSetupVersion + hwSetup); ///< Retrieve componentId of the asic add the passed address for the passed hwSetup + size_t GetComponentId( Int_t asicAddress); ///< Retrieve componentId of the asic add the passed address for the currently selected ComponentIdMap - std::map<Int_t, std::uint64_t> GetComponentIdMap() { return fComponentIdMap; } + std::map<Int_t, size_t> GetComponentIdMap() { return fComponentIdMap; } void SetParameterFile(TString fileName) { fParameterFileName = fileName; } - void SetComponentIdMap(std::map<Int_t, std::uint64_t> compMap) { fComponentIdMap = compMap; } + void SetComponentIdMap(std::map<Int_t, size_t> compMap) { fComponentIdMap = compMap; } + + /** + * @brief Create a hardware to software asic addreess translator map, with hidden parameter loading. + * + * @param isLoadedParameters + * @return std::map<size_t, Int_t> + */ + std::map<size_t, Int_t> CreateHwToSwAsicAddressTranslatorMap(bool isLoadedParameters); + + /** + * @brief Create a hardware to software asic addreess translator map + * + * @param moduleparsets par container for all asics on a module + * @return std::map<size_t, Int_t> + */ + std::map<size_t, Int_t> CreateHwToSwAsicAddressTranslatorMap(CbmTrdParSetAsic* moduleparsets); - std::map<std::uint64_t, Int_t> CreateHwToSwAsicAddressTranslatorMap(bool isLoadedParameters); + /** + * @brief Create a Asic Channel Map, with hidden parameter loading. + * + * @param isLoadedParameters + * @return std::map<Int_t, std::vector<Int_t>> + */ std::map<Int_t, std::vector<Int_t>> CreateAsicChannelMap(bool isLoadedParameters); + + /** + * @brief Create a Asic Channel Map + * + * @param parset + * @return std::map<Int_t, std::vector<Int_t>> + */ + std::map<Int_t, std::vector<Int_t>> CreateAsicChannelMap(CbmTrdParSetAsic* parset); + void SelectComponentIdMap(ECbmTrdHardwareSetupVersion hwSetup); void SelectComponentIdMap(TString geoTag); bool WriteComponentIdsToParams(); private: /* data */ - std::map<Int_t, uint64_t> + std::map<Int_t, size_t> fComponentIdMap; ///< Container for the translation betweem software asicAddress and hardware asicAddress. First: CbmTrdParAsic::fAddress, Second CbmTrdParAsic::fComponentId TString fParameterFileName; ///< Name of the parameter file correlated to the hardware setup diff --git a/core/detectors/trd/CbmTrdParAsic.cxx b/core/detectors/trd/CbmTrdParAsic.cxx index c2ac1527d2216052a39768d27ada26377ebcbcd1..21c66ecffa2f0e18c3a18e08f6158fb199e915ad 100644 --- a/core/detectors/trd/CbmTrdParAsic.cxx +++ b/core/detectors/trd/CbmTrdParAsic.cxx @@ -9,7 +9,7 @@ #include <stdio.h> // for printf //___________________________________________________________________ -CbmTrdParAsic::CbmTrdParAsic(Int_t address, Int_t FebGrouping, Double_t x, Double_t y, Double_t z, std::uint64_t compId) +CbmTrdParAsic::CbmTrdParAsic(Int_t address, Int_t FebGrouping, Double_t x, Double_t y, Double_t z, size_t compId) : CbmTrdParMod("CbmTrdParAsic", "TRD ASIC definition") , fAddress(address) , fX(x) diff --git a/core/detectors/trd/CbmTrdParAsic.h b/core/detectors/trd/CbmTrdParAsic.h index 07c325ce96cff3e782fe4ec8d12e63b6c75cbd6b..8f66342b8ff916f8ae937c3d01faa4fa61a42b01 100644 --- a/core/detectors/trd/CbmTrdParAsic.h +++ b/core/detectors/trd/CbmTrdParAsic.h @@ -12,7 +12,7 @@ #include <vector> // for vector -#include <stdint.h> // for uint64_t +#include <stdint.h> // for size_t class FairParamList; @@ -20,7 +20,7 @@ class FairParamList; class CbmTrdParAsic : public CbmTrdParMod { public: CbmTrdParAsic(Int_t address = 0, Int_t FebGrouping = -1, Double_t x = 0, Double_t y = 0, Double_t z = 0, - std::uint64_t compId = 0); + size_t compId = 0); virtual ~CbmTrdParAsic() { ; } /** \brief Enum for decodation of spadic componentId (Hardware to software mapping) @@ -41,7 +41,7 @@ public: virtual Double_t GetZ() const { return fZ; } virtual Int_t GetAddress() const { return fAddress; } - virtual std::uint64_t GetComponentId() const { return fComponentId; } + virtual size_t GetComponentId() const { return fComponentId; } virtual Int_t GetNchannels() const = 0; virtual Int_t GetFebGrouping() const { return fFebGrouping; } virtual Int_t GetChannelAddress(Int_t ich) const @@ -65,7 +65,7 @@ public: fY = y; fZ = z; } - virtual void SetComponentId(std::uint64_t id) { fComponentId = id; } + virtual void SetComponentId(size_t id) { fComponentId = id; } protected: Int_t fAddress; ///< unique ASIC ID @@ -73,9 +73,15 @@ protected: Double_t fY; ///< center of asic in global c.s. [cm] Double_t fZ; ///< center of asic in global c.s. [cm] Int_t fFebGrouping; ///< no of ASIC in ROB - std::uint64_t - fComponentId; ///< For the digit decoding see ECbmTrdComponentIdDecoding. nTh cRob on the module counted from top to bottom a long the sensitive side. This Id is needed to connect the microslice to a given channel, has to be set "by hand", i.e. is not given in the geometry macros. ComponentIdMaps for the Spadic are stored in CbmTrdHardwareSetupR. A macro to write those Ids to the parameter files can be found at https://git.cbm.gsi.de/trd/macros/mcbm2020/blob/master/writeSpadicHwAddresses.C - std::vector<Int_t> fChannelAddresses; ///< addresses of individual output channels + + /** + * @brief Hardware component Id used for addressing + * For the digit decoding see ECbmTrdComponentIdDecoding. nTh cRob on the module counted from top to bottom along the sensitive side. This Id is needed to connect the microslice to a given channel, has to be set "by hand", i.e. is not given in the geometry macros. ComponentIdMaps for the Spadic are stored in CbmTrdHardwareSetupR. A macro to write those Ids to the parameter files can be found at https://git.cbm.gsi.de/trd/macros/mcbm2020/blob/master/writeSpadicHwAddresses.C + */ + size_t fComponentId; + + /** @brief addresses of individual output channels */ + std::vector<Int_t> fChannelAddresses; ClassDef(CbmTrdParAsic, 1) // Definition of common ASIC parameters }; diff --git a/core/detectors/trd/CbmTrdParManager.cxx b/core/detectors/trd/CbmTrdParManager.cxx index ee2f5edde322d20113a0dafc157b6dcc193b573b..aa94a212d257383fcf75f281e8e49234043146a9 100644 --- a/core/detectors/trd/CbmTrdParManager.cxx +++ b/core/detectors/trd/CbmTrdParManager.cxx @@ -38,6 +38,7 @@ #include <TObject.h> // for TObject #include <TRandom.h> // for TRandom, gRandom +#include <memory> #include <vector> // for vector #include <stdio.h> // for printf @@ -406,16 +407,16 @@ bool CbmTrdParManager::CreateParFilesFromGeometry(TString outDir) } // ---- GetParSetList ---- -void CbmTrdParManager::GetParSetList(std::vector<CbmTrdParSet*>* parSetList) +void CbmTrdParManager::GetParSetList(std::vector<std::shared_ptr<CbmTrdParSet>>* parSetList) { // std::vector<CbmTrdParSet*> parSetList; - CbmTrdParSet* parSet = nullptr; + std::shared_ptr<CbmTrdParSet> parSet = nullptr; for (Int_t iParSetType = (Int_t) ECbmTrdParSets::kBegin; iParSetType <= (Int_t) ECbmTrdParSets::kEnd; iParSetType++) { switch (iParSetType) { - case (Int_t) ECbmTrdParSets::kCbmTrdParSetAsic: parSet = new CbmTrdParSetAsic(); break; - case (Int_t) ECbmTrdParSets::kCbmTrdParSetDigi: parSet = new CbmTrdParSetDigi(); break; - case (Int_t) ECbmTrdParSets::kCbmTrdParSetGain: parSet = new CbmTrdParSetGain(); break; - case (Int_t) ECbmTrdParSets::kCbmTrdParSetGas: parSet = new CbmTrdParSetGas(); break; + case (Int_t) ECbmTrdParSets::kCbmTrdParSetAsic: parSet = std::make_shared<CbmTrdParSetAsic>(); break; + case (Int_t) ECbmTrdParSets::kCbmTrdParSetDigi: parSet = std::make_shared<CbmTrdParSetDigi>(); break; + case (Int_t) ECbmTrdParSets::kCbmTrdParSetGain: parSet = std::make_shared<CbmTrdParSetGain>(); break; + case (Int_t) ECbmTrdParSets::kCbmTrdParSetGas: parSet = std::make_shared<CbmTrdParSetGas>(); break; } parSetList->emplace_back(parSet); } diff --git a/core/detectors/trd/CbmTrdParManager.h b/core/detectors/trd/CbmTrdParManager.h index 685b0a71efdd3d81744b0a38e24a4cc20d50b3a9..51e5e19dc061a5fa8585d15bdf594dd2f28bb270 100644 --- a/core/detectors/trd/CbmTrdParManager.h +++ b/core/detectors/trd/CbmTrdParManager.h @@ -27,6 +27,8 @@ #include <RtypesCore.h> // for Bool_t, kFALSE, Int_t, Option_t, kTRUE #include <TString.h> // for TString +#include <memory> + class CbmTrdGeoHandler; class CbmTrdParSetAsic; class CbmTrdParSetDigi; @@ -96,7 +98,7 @@ public: **/ bool CreateParFilesFromGeometry(bool createRootFileOutput, TString outDir = ""); - static void GetParSetList(std::vector<CbmTrdParSet*>* parSetList); + static void GetParSetList(std::vector<std::shared_ptr<CbmTrdParSet>>* parSetList); static void GetParFileExtensions(std::vector<std::string>* vec); private: diff --git a/core/detectors/trd/CbmTrdParSetAsic.cxx b/core/detectors/trd/CbmTrdParSetAsic.cxx index 4aa821fafcf32614918321189294fc38721650d1..bcd84aeaa53288f3b1ed8883b61a938d93248ff8 100644 --- a/core/detectors/trd/CbmTrdParSetAsic.cxx +++ b/core/detectors/trd/CbmTrdParSetAsic.cxx @@ -18,7 +18,7 @@ #include <utility> // for pair -#include <stdint.h> // for uint64_t +#include <stdint.h> // for size_t #include <stdio.h> // for printf #include <string.h> // for strcmp @@ -137,7 +137,7 @@ void CbmTrdParSetAsic::putParams(FairParamList* l) TArrayI asicInfo(fullSize); iAsicNr = 0; for (auto iModuleIt : mod->fModuleMap) { - std::uint64_t asicComponentId(100098); // 100098 = undefined + size_t asicComponentId(100098); // 100098 = undefined currentAsicAddress = iModuleIt.first; asicComponentId = ((CbmTrdParSpadic*) iModuleIt.second)->GetComponentId(); int offset = iAsicNr * sizePerSpadic; diff --git a/core/detectors/trd/CbmTrdParSpadic.cxx b/core/detectors/trd/CbmTrdParSpadic.cxx index ebc0cf22552d67f5711b50f77911e950c877b2cf..c59e6e44c33996bc547631f5f07668733b628136 100644 --- a/core/detectors/trd/CbmTrdParSpadic.cxx +++ b/core/detectors/trd/CbmTrdParSpadic.cxx @@ -19,8 +19,7 @@ Double_t CbmTrdParSpadic::fgSizeY = 3.0; Double_t CbmTrdParSpadic::fgSizeZ = 0.5; //___________________________________________________________________ -CbmTrdParSpadic::CbmTrdParSpadic(Int_t address, Int_t FebGrouping, Double_t x, Double_t y, Double_t z, - std::uint64_t compId) +CbmTrdParSpadic::CbmTrdParSpadic(Int_t address, Int_t FebGrouping, Double_t x, Double_t y, Double_t z, size_t compId) : CbmTrdParAsic(address, FebGrouping, x, y, z, compId) { fChannelAddresses.resize(NSPADICCH); @@ -65,11 +64,11 @@ void CbmTrdParSpadic::LoadParams(FairParamList* inList) } // ---- CreateComponentId --------------------------------------------- -std::uint64_t CbmTrdParSpadic::CreateComponentId(Int_t criId, Int_t crobId, Int_t nThCrobOnModule, Int_t eLinkId) +size_t CbmTrdParSpadic::CreateComponentId(Int_t criId, Int_t crobId, Int_t nThCrobOnModule, Int_t eLinkId) { - std::uint64_t compId = criId * ECbmTrdComponentIdDecoding::kCriIdPosition - + crobId * ECbmTrdComponentIdDecoding::kCrobIdPosition - + nThCrobOnModule * ECbmTrdComponentIdDecoding::kCrobNrPosition + eLinkId; + size_t compId = criId * ECbmTrdComponentIdDecoding::kCriIdPosition + + crobId * ECbmTrdComponentIdDecoding::kCrobIdPosition + + nThCrobOnModule * ECbmTrdComponentIdDecoding::kCrobNrPosition + eLinkId; return compId; } @@ -77,7 +76,7 @@ std::uint64_t CbmTrdParSpadic::CreateComponentId(Int_t criId, Int_t crobId, Int_ std::uint16_t CbmTrdParSpadic::GetCriId() { return GetCriId(fComponentId); } // ---- GetCriId ---------------------------------------------------- -std::uint16_t CbmTrdParSpadic::GetCriId(std::uint64_t componentId) +std::uint16_t CbmTrdParSpadic::GetCriId(size_t componentId) { uint16_t returnId = (componentId / (ECbmTrdComponentIdDecoding::kCriIdPosition)); return returnId; @@ -87,7 +86,7 @@ std::uint16_t CbmTrdParSpadic::GetCriId(std::uint64_t componentId) std::uint8_t CbmTrdParSpadic::GetCrobId() { return GetCrobId(fComponentId); } // ---- GetCrobId ---------------------------------------------------- -std::uint8_t CbmTrdParSpadic::GetCrobId(std::uint64_t componentId) +std::uint8_t CbmTrdParSpadic::GetCrobId(size_t componentId) { std::uint8_t returnId(-1); returnId = ((componentId % ECbmTrdComponentIdDecoding::kCriIdPosition) / ECbmTrdComponentIdDecoding::kCrobIdPosition); @@ -98,7 +97,7 @@ std::uint8_t CbmTrdParSpadic::GetCrobId(std::uint64_t componentId) std::uint8_t CbmTrdParSpadic::GetCrobNumber() { return GetCrobNumber(fComponentId); } // ---- GetCrobNumber ---------------------------------------------------- -std::uint8_t CbmTrdParSpadic::GetCrobNumber(std::uint64_t componentId) +std::uint8_t CbmTrdParSpadic::GetCrobNumber(size_t componentId) { std::uint8_t returnId(-1); returnId = (componentId % ECbmTrdComponentIdDecoding::kCrobIdPosition / ECbmTrdComponentIdDecoding::kCrobNrPosition); @@ -109,7 +108,7 @@ std::uint8_t CbmTrdParSpadic::GetCrobNumber(std::uint64_t componentId) std::uint8_t CbmTrdParSpadic::GetElinkId(Int_t channelId) { return GetElinkId(fComponentId, channelId); } // ---- GetElinkId ---------------------------------------------------- -std::uint8_t CbmTrdParSpadic::GetElinkId(std::uint64_t componentId, Int_t channelId) +std::uint8_t CbmTrdParSpadic::GetElinkId(size_t componentId, Int_t channelId) { std::uint8_t eLinkId(-1); diff --git a/core/detectors/trd/CbmTrdParSpadic.h b/core/detectors/trd/CbmTrdParSpadic.h index 35bc17026f4dbc50c8e77db13be5c0ff39fa9546..fd11ae6e892b33afe196ce067f9b9d2b9d47db93 100644 --- a/core/detectors/trd/CbmTrdParSpadic.h +++ b/core/detectors/trd/CbmTrdParSpadic.h @@ -15,7 +15,7 @@ #include <map> // fMapAsicChannelToElink #include <vector> // fVecSpadicChannels -#include <stdint.h> // for uint64_t, uint8_t, uint16_t +#include <stdint.h> // for size_t, uint8_t, uint16_t class FairParamList; @@ -23,7 +23,7 @@ class FairParamList; class CbmTrdParSpadic : public CbmTrdParAsic { public: CbmTrdParSpadic(Int_t address = 0, Int_t FebGrouping = -1, Double_t x = 0, Double_t y = 0, Double_t z = 0, - std::uint64_t compId = 0); + size_t compId = 0); virtual ~CbmTrdParSpadic() { ; } virtual void LoadParams( @@ -36,7 +36,7 @@ public: virtual Double_t GetSizeY() const { return fgSizeY; } virtual Double_t GetSizeZ() const { return fgSizeZ; } - static std::uint64_t CreateComponentId( + static size_t CreateComponentId( Int_t criId, Int_t crobId, Int_t nThCrobOnModule, Int_t eLinkId); ///< Create the componentId from a given criId, crobId, eLinkId and the nThCrobOnModule count, according to the scheme, defined by ECbmTrdComponentIdDecoding. @@ -49,13 +49,13 @@ public: static Int_t GetNasicsPerCrob( Int_t moduleType); ///< Returns the number of asics per Crob on a given moduleType defined in eCbmTrdModuleTypes static std::uint16_t GetCriId( - std::uint64_t + size_t componentId); ///< Extracts the CriId from a given componentId - Remark when the par files are created from geometries the CriId is set to the unique module number - static std::uint8_t GetCrobId(std::uint64_t componentId); ///< Extracts the CrobId from a given componentId - static std::uint8_t GetCrobNumber( - std::uint64_t componentId); ///< Extracts the CrobNumber (nTh Crob on the module) from a given componentId + static std::uint8_t GetCrobId(size_t componentId); ///< Extracts the CrobId from a given componentId + static std::uint8_t + GetCrobNumber(size_t componentId); ///< Extracts the CrobNumber (nTh Crob on the module) from a given componentId static std::uint8_t GetElinkId( - std::uint64_t componentId, + size_t componentId, Int_t channelId); ///< eLinkId for the given asicAddress and channelId (in the asic coordinates, i.e. 00..31). Remark: no check of a correct componentId is performed diff --git a/core/detectors/trd/CbmTrdSPADIC.cxx b/core/detectors/trd/CbmTrdSPADIC.cxx deleted file mode 100644 index c2db988c959b5257f517e9457ac2fb34bde84ae1..0000000000000000000000000000000000000000 --- a/core/detectors/trd/CbmTrdSPADIC.cxx +++ /dev/null @@ -1,309 +0,0 @@ -/* Copyright (C) 2014-2021 Institut fuer Kernphysik, Westfaelische Wilhelms-Universitaet Muenster, Muenster - SPDX-License-Identifier: GPL-3.0-only - Authors: Cyrano Bergmann [committer], Florian Uhlig */ - -#include "CbmTrdSPADIC.h" - -#include "CbmTrdAddress.h" // for CbmTrdAddress -#include "CbmTrdDigi.h" // for CbmTrdDigi -#include "CbmTrdGeoHandler.h" // for CbmTrdGeoHandler -#include "CbmTrdParModDigi.h" // for CbmTrdParModDigi -#include "CbmTrdParSetDigi.h" // for CbmTrdParSetDigi - -#include <FairRootManager.h> // for FairRootManager -#include <FairRunAna.h> // for FairRunAna -#include <FairRuntimeDb.h> // for FairRuntimeDb -#include <FairTask.h> // for FairTask, InitStatus, kSUCCESS -#include <Logger.h> // for LOG, Logger - -#include <TAxis.h> // for TAxis -#include <TCanvas.h> // for TCanvas -#include <TClonesArray.h> // for TClonesArray -#include <TGenericClassInfo.h> // for TGenericClassInfo -#include <TH1.h> // for TH1D - -#include <list> // for list, list<>::iterator, operator!= -#include <map> // for map, operator!=, map<>::iterator, __m... -#include <utility> // for pair, make_pair - -#include <cmath> // for pow, exp -#include <stdio.h> // for printf - -CbmTrdSPADIC::CbmTrdSPADIC() - : FairTask("TrdSPADIC", 1) - , fSpadicResponse(nullptr) - , fShaperOrder(2) - , fShapingTime(0.09) - , fPeakBin(2) - , fBitResolution(8) - , fmaxdEdx(0.0001) - , fAdcBit(fmaxdEdx / pow(2, fBitResolution)) - , fPulseShape(false) - , fSelectionMask() - , fDigis(nullptr) - , fDigiPar(nullptr) - , fModuleInfo(nullptr) - , fGeoHandler(nullptr) - , fMinimumChargeTH(1.0e-06) -{ -} -CbmTrdSPADIC::~CbmTrdSPADIC() -{ - fDigis->Delete(); - delete fDigis; -} -void CbmTrdSPADIC::SetParContainers() -{ - fDigiPar = (CbmTrdParSetDigi*) (FairRunAna::Instance()->GetRuntimeDb()->getContainer("CbmTrdParSetDigi")); -} - -InitStatus CbmTrdSPADIC::Init() -{ - FairRootManager* ioman = FairRootManager::Instance(); - - fDigis = (TClonesArray*) ioman->GetObject("TrdDigi"); - if (fDigis == nullptr) LOG(fatal) << "CbmTrdSPADIC::Init No TrdDigi array"; - - fGeoHandler = new CbmTrdGeoHandler(); - fGeoHandler->Init(); - - InitSpadicResponseFunction(); - - return kSUCCESS; -} - - -// -------------------------------------------------------------------- -void CbmTrdSPADIC::SetBitResolution(Int_t bit) { fBitResolution = pow(2, bit); } -// -------------------------------------------------------------------- -void CbmTrdSPADIC::SetMaxRange(Double_t maxRange) -{ - fmaxdEdx = maxRange; - fAdcBit = fmaxdEdx / fBitResolution; -} -// -------------------------------------------------------------------- -void CbmTrdSPADIC::SetPulseShapeSim(Bool_t pulseShape) { fPulseShape = pulseShape; } -// -------------------------------------------------------------------- -void CbmTrdSPADIC::SetTriggerThreshold(Double_t minCharge) -{ - fMinimumChargeTH = minCharge; // To be used for test beam data processing -} -// -------------------------------------------------------------------- -Bool_t CbmDigiSorter(std::pair<Int_t, Int_t /*CbmTrdDigi**/> a, std::pair<Int_t, Int_t /*CbmTrdDigi**/> b) -{ - return (a.first < b.first); -} -// -------------------------------------------------------------------- -void CbmTrdSPADIC::InitSpadicResponseFunction() -{ - fSpadicResponse = new TH1D("SpadicResponseFunction", "SpadicResponseFunction", fnBins, 0 - (1.8 / fnBins), - 1.8 - (1.8 / fnBins)); // 1/25MHz * 45Timebins = 1.8µs200000,0,20); - Double_t t = 0; //[µs] - Double_t h = 0; - // Double_t T = 0.09; //[µs] - // Double_t t_peak = fSpadicResponse->GetBinCenter(fPeakBin); - for (Int_t k = 1; k <= fSpadicResponse->GetNbinsX(); k++) { - t = fSpadicResponse->GetBinCenter(k); - //t = fSpadicResponse->GetBinCenter(k) * t_peak; - //h = t/pow(fShapingTime,fShaperOrder) * exp(-1. * t / fShapingTime); // Tim thesis p.42 - h = (pow(t / fShapingTime, fShaperOrder) * exp(-1. * t / fShapingTime)); // with time compesation - fSpadicResponse->SetBinContent(k, h); - } - fSpadicResponse->Scale(1. / fSpadicResponse->Integral()); -} -// -------------------------------------------------------------------- -void CbmTrdSPADIC::SetSelectionMask(Bool_t mask[fnBins]) -{ - for (Int_t iBin = 0; iBin < fnBins; iBin++) { - fSelectionMask[iBin] = mask[iBin]; - } -} -// -------------------------------------------------------------------- -void CbmTrdSPADIC::ADC(TH1D* spadicPulse) -{ - for (Int_t k = 1; k <= spadicPulse->GetNbinsX(); k++) { - if (spadicPulse->GetBinContent(k) > fmaxdEdx) spadicPulse->SetBinContent(k, fmaxdEdx); - else - spadicPulse->SetBinContent(k, Int_t(spadicPulse->GetBinContent(k) / fAdcBit) * fAdcBit); - if (!fSelectionMask[k - 1]) { spadicPulse->SetBinContent(k, 0); } - } -} -// -------------------------------------------------------------------- -void CbmTrdSPADIC::ADC(CbmTrdDigi* digi) -{ - if (digi->GetCharge() > fmaxdEdx) digi->SetCharge(fmaxdEdx); - else - digi->SetCharge(Int_t(digi->GetCharge() / fAdcBit) * fAdcBit); -} -// -------------------------------------------------------------------- -void CbmTrdSPADIC::CR_RC_Shaper(CbmTrdDigi* digi, TH1D* spadicPulse) -{ - Double_t amplitude = digi->GetCharge(); - if (amplitude <= 0.0) return; - TH1D* event = new TH1D("deltaPulse", "deltaPulse", fnBins, 0 - (1.8 / fnBins), - 1.8 - (1.8 / fnBins)); // 1/25MHz * 45Timebins = 1.8µs - event->SetBinContent(1, 0); - for (Int_t k = fPeakBin; k <= event->GetNbinsX(); k++) { - event->SetBinContent(k, amplitude * exp(-0.65 * (k - fPeakBin))); - } - spadicPulse->Reset(); - // Double_t t = 0; //[µs] - Double_t x = 0; - Double_t h = 0; - // Double_t T_0 = event->GetBinWidth(1); //[µs] - // Double_t t_peak = event->GetBinCenter(event->GetMaximumBin()); - // Double_t max_ampl = event->GetBinContent(event->GetMaximumBin()); - - for (Int_t k = 1; k <= event->GetNbinsX(); k++) { - Double_t y = 0; - for (Int_t i = 1; i <= event->GetNbinsX(); i++) { - //t = event->GetBinCenter(i);// * t_peak; - //h = (pow(t / fShapingTime,fShaperOrder) * exp(-1. * t / fShapingTime)); // with time compesation - h = fSpadicResponse->GetBinContent(i); - x = event->GetBinContent(k - i); - y += x * h; - } - spadicPulse->SetBinContent(k, y); // * T_0 / max_ampl); - //spadicPulse->SetBinContent(k, event->GetBinContent(k)); - } - spadicPulse->Scale(amplitude / spadicPulse->GetBinContent(spadicPulse->GetMaximumBin()) /*spadicPulse->Integral()*/); - ADC(spadicPulse); - delete event; -} - - -// ---- Exec ---------------------------------------------------------- -void CbmTrdSPADIC::Exec(Option_t*) -{ - LOG(info) << "================CbmTrdSPADIC==============="; - LOG(info) << "CbmTrdSPADIC::Exec : fPulseShape: " << (Bool_t) fPulseShape; - LOG(info) << "CbmTrdSPADIC::Exec : fBitResolution: " << fBitResolution; - LOG(info) << "CbmTrdSPADIC::Exec : fShaperOrder: " << fShaperOrder; - LOG(info) << "CbmTrdSPADIC::Exec : fShapingTime: " << fShapingTime << " µs"; - LOG(info) << "CbmTrdSPADIC::Exec : fmaxdEdx: " << fmaxdEdx << " GeV"; - LOG(info) << "CbmTrdSPADIC::Exec : fAdcBit: " << fAdcBit << " (GeV/bit)"; - LOG(info) << "CbmTrdSPADIC::Exec : fSelectionMask:"; - for (Int_t iBin = 0; iBin < fnBins; iBin++) { - LOG(info) << " " << (Bool_t) fSelectionMask[iBin]; - if ((1 + iBin) % 5 == 0 && iBin > 0 && (1 + iBin) < fnBins) { LOG(info) << " "; } - } - LOG(info) << ""; - Bool_t debug = false; - std::map<Int_t, std::map<Int_t, Int_t>> moduleDigiNotTriggerMap; //<ModuleAddress, <combiId, digiId> > - std::map<Int_t, std::list<std::pair<Int_t, Int_t>>> moduleDigiTriggerMap; //<ModuleAddress, <combiId, digiId> > - Int_t nDigis = fDigis->GetEntriesFast(); - - TH1D* spadicPulse = new TH1D("spadicPulse", "spadicPulse", fnBins, 0 - (1.8 / fnBins), - 1.8 - (1.8 / fnBins)); // 1/25MHz * 45Timebins = 1.8µs - TCanvas* c = nullptr; - if (debug) c = new TCanvas("c", "c", 800, 600); - for (Int_t iDigi = 0; iDigi < nDigis; iDigi++) { - CbmTrdDigi* digi = (CbmTrdDigi*) fDigis->At(iDigi); - - - Int_t digiAddress = digi->GetAddress(); - Int_t layerId = CbmTrdAddress::GetLayerId(digiAddress); - Int_t moduleId = CbmTrdAddress::GetModuleId(digiAddress); - Int_t moduleAddress = CbmTrdAddress::GetModuleAddress(digiAddress); - fModuleInfo = (CbmTrdParModDigi*) fDigiPar->GetModulePar(CbmTrdAddress::GetModuleAddress(digiAddress)); - if (!fModuleInfo) { - printf("digi %3i digiAddress %i layer %i and modId %i Sec%i Row:%i " - "Col%i not found\n", - iDigi, digiAddress, layerId, moduleId, CbmTrdAddress::GetSectorId(digi->GetAddress()), - CbmTrdAddress::GetRowId(digi->GetAddress()), CbmTrdAddress::GetColumnId(digi->GetAddress())); - continue; - } - Int_t secRow = CbmTrdAddress::GetRowId(digi->GetAddress()); - Int_t iSector = CbmTrdAddress::GetSectorId(digi->GetAddress()); - Int_t globalRow = 0; - globalRow = fModuleInfo->GetModuleRow(iSector, secRow); - Int_t iCol = CbmTrdAddress::GetColumnId(digi->GetAddress()); - - Int_t combiId = globalRow * (fModuleInfo->GetNofColumns() + 1) + iCol; - - if (digi->GetCharge() >= fMinimumChargeTH) { - digi->SetTriggerType(1); - digi->SetStopType(0); - moduleDigiTriggerMap[moduleAddress].push_back(std::make_pair(combiId, iDigi)); - } - else { - moduleDigiNotTriggerMap[moduleAddress][combiId] = iDigi; - } - } - CbmTrdDigi* digi = nullptr; - for (std::map<Int_t, std::list<std::pair<Int_t, Int_t>>>::iterator iModule = moduleDigiTriggerMap.begin(); - iModule != moduleDigiTriggerMap.end(); ++iModule) { - (*iModule).second.sort(CbmDigiSorter); - Int_t moduleAddress = (*iModule).first; - for (std::list<std::pair<Int_t, Int_t>>::iterator iDigi = (*iModule).second.begin(); - iDigi != (*iModule).second.end(); iDigi++) { - Int_t combiId = (*iDigi).first; - Int_t digiId = (*iDigi).second; - digi = (CbmTrdDigi*) fDigis->At(digiId); - if (fPulseShape) { - CR_RC_Shaper(digi, spadicPulse); - Float_t pulse[fnBins] = {0.0}; - for (Int_t k = 1; k <= spadicPulse->GetNbinsX(); k++) { - pulse[k - 1] = spadicPulse->GetBinContent(k); - } - digi->SetPulseShape(pulse); - if (debug) { - //printf("%.6E - %.6E => %.1f%% \n", digi->GetCharge(), spadicPulse->GetBinContent(spadicPulse->GetMaximumBin()), 100.*(digi->GetCharge() - spadicPulse->GetBinContent(spadicPulse->GetMaximumBin())) / digi->GetCharge()); - c->cd(); - spadicPulse->GetYaxis()->SetRangeUser(0 - 0.01 * fmaxdEdx, fmaxdEdx + 0.01 * fmaxdEdx); - spadicPulse->DrawCopy(); - } - } - else { - ADC(digi); - } - if (moduleDigiNotTriggerMap[moduleAddress].find(combiId - 1) != moduleDigiNotTriggerMap[moduleAddress].end()) { - digi = (CbmTrdDigi*) fDigis->At(moduleDigiNotTriggerMap[moduleAddress][combiId - 1]); - if (fPulseShape) { - CR_RC_Shaper(digi, spadicPulse); - Float_t pulse[fnBins] = {0.0}; - for (Int_t k = 1; k <= spadicPulse->GetNbinsX(); k++) { - pulse[k - 1] = spadicPulse->GetBinContent(k); - } - digi->SetPulseShape(pulse); - if (debug) { - c->cd(); - spadicPulse->SetLineColor(kRed); - spadicPulse->GetYaxis()->SetRangeUser(0 - 0.01 * fmaxdEdx, fmaxdEdx + 0.01 * fmaxdEdx); - spadicPulse->DrawCopy("same"); - } - } - else { - ADC(digi); - } - digi->SetStopType(0); - digi->SetTriggerType(2); - } - if (moduleDigiNotTriggerMap[moduleAddress].find(combiId + 1) != moduleDigiNotTriggerMap[moduleAddress].end()) { - digi = (CbmTrdDigi*) fDigis->At(moduleDigiNotTriggerMap[moduleAddress][combiId + 1]); - if (fPulseShape) { - CR_RC_Shaper(digi, spadicPulse); - Float_t pulse[fnBins] = {0.0}; - for (Int_t k = 1; k <= spadicPulse->GetNbinsX(); k++) { - pulse[k - 1] = spadicPulse->GetBinContent(k); - } - digi->SetPulseShape(pulse); - if (debug) { - c->cd(); - spadicPulse->SetLineColor(kGreen); - spadicPulse->GetYaxis()->SetRangeUser(0 - 0.01 * fmaxdEdx, fmaxdEdx + 0.01 * fmaxdEdx); - spadicPulse->DrawCopy("same"); - } - } - else { - ADC(digi); - } - digi->SetStopType(0); - digi->SetTriggerType(2); - } - if (fPulseShape) - if (debug) c->Update(); - } - } -} -ClassImp(CbmTrdSPADIC) diff --git a/core/detectors/trd/CbmTrdSPADIC.h b/core/detectors/trd/CbmTrdSPADIC.h deleted file mode 100644 index b7462dbd77f82462e94a7a1e8fc35b6b05a5d79e..0000000000000000000000000000000000000000 --- a/core/detectors/trd/CbmTrdSPADIC.h +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright (C) 2014-2020 Institut fuer Kernphysik, Westfaelische Wilhelms-Universitaet Muenster, Muenster - SPDX-License-Identifier: GPL-3.0-only - Authors: Cyrano Bergmann [committer], Florian Uhlig */ - -// ------------------------------------------------------------------------- -// ----- CbmTrdSPADIC header file ----- -// ----- Created 03/06/14 by Cyrano Bergmann ----- -// ------------------------------------------------------------------------- - - -#ifndef CBMTRDSPADIC_H -#define CBMTRDSPADIC_H - -#include "FairTask.h" // for FairTask, InitStatus - -#include <Rtypes.h> // for THashConsistencyHolder, ClassDef -#include <RtypesCore.h> // for Double_t, Int_t, Bool_t, Option_t - -class CbmTrdDigi; -class CbmTrdGeoHandler; -class CbmTrdParModDigi; -class CbmTrdParSetDigi; -class TClonesArray; -class TH1D; - -class CbmTrdSPADIC : public FairTask { - -public: - /** - * Default constructor. - */ - CbmTrdSPADIC(); - // CbmTrdSPADIC(Bool_t MultiHit, Bool_t NeighbourReadout, Bool_t RowClusterMerger, Double_t MinimumChargeTH); - - /** - * \brief Destructor. - */ - virtual ~CbmTrdSPADIC(); - - /** - * \brief Inherited from FairTask. - */ - virtual InitStatus Init(); - - /** - * \breif Inherited from FairTask. - */ - virtual void SetParContainers(); - - /** - * \breif Inherited from FairTask. - */ - virtual void Exec(Option_t* option); - - void SetTriggerThreshold(Double_t triggerthreshold); - void SetPulseShapeSim(Bool_t pulseShape); - void SetSelectionMask(Bool_t mask[45]); - void SetBitResolution(Int_t bit); - void SetMaxRange(Double_t maxRange); - -private: - void CR_RC_Shaper(CbmTrdDigi* digi, TH1D* spadicPulse); - void ADC(TH1D* spadicPulse); - void ADC(CbmTrdDigi* digi); - void InitSpadicResponseFunction(); - TH1D* fSpadicResponse; - Int_t fShaperOrder; - Double_t fShapingTime; - Int_t fPeakBin; - Int_t fBitResolution; - static const Int_t fnBins = 45; - Double_t fmaxdEdx; - Double_t fAdcBit; - Bool_t fPulseShape; - Bool_t fSelectionMask[fnBins]; - - //Bool_t CbmDigiSorter(std::pair< Int_t, Int_t> a, std::pair< Int_t, Int_t> b); - - TClonesArray* fDigis; /** Input array of CbmTrdDigi **/ - - CbmTrdParSetDigi* fDigiPar; //! - CbmTrdParModDigi* fModuleInfo; //! - - CbmTrdGeoHandler* fGeoHandler; //! - - Double_t fMinimumChargeTH; - - CbmTrdSPADIC(const CbmTrdSPADIC&); - CbmTrdSPADIC& operator=(const CbmTrdSPADIC&); - - ClassDef(CbmTrdSPADIC, 2); -}; -#endif diff --git a/core/detectors/trd/CbmTrdSpadic.cxx b/core/detectors/trd/CbmTrdSpadic.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f49e1670233b80d79fbf71fc6c04dcf311331f72 --- /dev/null +++ b/core/detectors/trd/CbmTrdSpadic.cxx @@ -0,0 +1,129 @@ +#include "CbmTrdSpadic.h" + +#include <RtypesCore.h> +#include <TH1.h> +#include <TMath.h> // for SpadicResponse function +#include <TRandom.h> + +#include <cstddef> +#include <cstdint> +#include <limits> +#include <vector> + + +const Double_t CbmTrdSpadic::fgClockCycleLength = CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC); + +// const Double_t CbmTrdSpadic::fgShapingTime = 142.0; +const Double_t CbmTrdSpadic::fgShapingTime = 120.0; +const Double_t CbmTrdSpadic::fgChargeToMaxAdcCal = 2.73; + +CbmTrdSpadic::CbmTrdSpadic() {} +CbmTrdSpadic::~CbmTrdSpadic() {} + +// ---- GetResponseFunc ---- +std::shared_ptr<TF1> CbmTrdSpadic::GetResponseFunc() +{ + auto funcSpadicResponse = std::make_shared<TF1>(TF1("funcSpadicResponse", Response, 0, (fgNrOfAdcSamples - 1), 6)); + funcSpadicResponse->SetParNames("Shaping time", "Shaping order", "Input charge", "Bin timeshift", "Nr of presamples", + "Charge Calibration"); + + // Set the default parameters + std::vector<Double_t> parvec = {fgShapingTime, fgShapingOrder, 0.0, + fgClockCycleLength / 2, fgNrOfPresamples, fgChargeToMaxAdcCal}; + funcSpadicResponse->SetParameters(parvec.data()); + + return funcSpadicResponse; +} + +// ---- Response ---- +Double_t CbmTrdSpadic::Response(Double_t* samplenr, Double_t* par) +{ + + // par[0] = shaping time of the first shaping station + // par[1] = shaping order + // par[2] = input charge + // par[3] = timeshift inside the 62.5 ns bin of a CC + // par[4] = number of presamples + // par[5] = charge calibration factor + + // histo comes in cc but spadicResponse is in ns + Double_t t = (samplenr[0] - par[4]) * fgClockCycleLength + par[3]; + + Double_t response = + t >= 0 ? ((par[2] * par[5]) * TMath::Power((t / par[0]), ((Int_t) par[1])) * TMath::Exp(-(t / par[0]))) : 0; + + return response; +} + +// ---- Response ---- +Double_t CbmTrdSpadic::Response(UInt_t samplenr) +{ + Double_t samplepos = samplenr; + + return Response(&samplepos, fvecResponsePars.data()); +} + +// ---- GetAnalogResponse ---- +std::vector<std::int16_t> CbmTrdSpadic::GetAnalogResponsePulse(Double_t inputCharge, Double_t binTimeshift) +{ + // If a timeshift should be taken into account, it has to be set before calling this function via SetParameter(eResponsePars::kBinTimeShift, yourTimeShiftHere); + std::vector<std::int16_t> pulse(CbmTrdSpadic::GetNrOfAdcSamples(), 0.0); + SetParameter(eResponsePars::kInputCharge, inputCharge); + + SetParameter(eResponsePars::kBinTimeshift, binTimeshift); + + for (UInt_t isample = fvecResponsePars.at(static_cast<size_t>(eResponsePars::kNrPresamples)); isample < pulse.size(); + isample++) { + + auto response = Response(isample) / fMaxAdcToMipCal; + // calibrate response to MIP + + // Add baseline lvl to the response + response += fBaselineLvl; + + // Add noise if requested (protect 0 against real numbers) + if (fNoiseLvl > 1e-20) response += GetNoise(fNoiseLvl); + + // Check the sample for potential clipping. Since, we also have analog clipping in the same region as the digital clipping we also check for it here. + // To deactivate simply set to an unreasonable high value + if (response > fClippingStart) response = fClippingStart; + pulse.at(isample) = response; + } + return pulse; +} + +// ---- GetNoise ---- +Int_t CbmTrdSpadic::GetNoise(Double_t sigmaNoise) +{ + Int_t noise = gRandom->Gaus(0, sigmaNoise); + return noise; +} + +// ---- GetAnalyticTimeshift ---- +Double_t CbmTrdSpadic::GetAnalyticTimeshift(Double_t absolutetime) +{ + Double_t timeshift = (static_cast<Int_t>(absolutetime * 10) % static_cast<Int_t>(GetClockCycle() * 10)) / 10.0; + + timeshift = timeshift >= 0 ? timeshift - (GetClockCycle() / 2) : 0; + + return timeshift; +} + +// ---- GetPeakingSamplePos ---- +UInt_t CbmTrdSpadic::GetPeakingSamplePos() +{ + UInt_t peakbin = + static_cast<UInt_t>(fvecResponsePars.at(static_cast<size_t>(eResponsePars::kShapingTime)) / fgClockCycleLength + + static_cast<UInt_t>(fvecResponsePars.at(static_cast<size_t>(eResponsePars::kNrPresamples)))); + return peakbin; +} + +// ---- MaxAdcToEnergyCal ---- +Float_t CbmTrdSpadic::MaxAdcToEnergyCal(Float_t maxadc) +{ + Float_t energy = maxadc * fMaxAdcToEnergyCal; + + return energy; +} + +ClassImp(CbmTrdSpadic) diff --git a/core/detectors/trd/CbmTrdSpadic.h b/core/detectors/trd/CbmTrdSpadic.h new file mode 100644 index 0000000000000000000000000000000000000000..5d44a40893a3a51a00ddeb1fda89f8911673d238 --- /dev/null +++ b/core/detectors/trd/CbmTrdSpadic.h @@ -0,0 +1,547 @@ +/** + * @file CbmTrdSpadic.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Software representation of the SPADIC v2.2+ + * @version 0.1 + * @date 2021-02-15 + * @todo include parameter loading and usage for all object dependent response + * functions. + * + * + */ + +#ifndef CBMTRDSPADIC_H +#define CBMTRDSPADIC_H + +#include "CbmTrdDefs.h" // for MIP dEdx value +#include "CbmTrdDigi.h" // for ClockCycle +#include "CbmTrdParSpadic.h" +#include "CbmTrddEdxUtils.h" // for MIP dEdx + +#include <Rtypes.h> // for THashConsistencyHolder, ClassDef +#include <RtypesCore.h> // for Double_t, Int_t, Bool_t, Option_t +#include <TF1.h> // for response functions +#include <TObject.h> // for TObject inheritence + +#include <cstdint> +#include <vector> + +#include <MessageTypes.h> +#include <cmath> + +class CbmTrdSpadic { + +public: + /** + * @brief Construct a new CbmTrdSpadic object + * Default and standard c'tor for a CbmTrdSpadic object + * + */ + CbmTrdSpadic(); + + /** + * @brief Copy construct a new CbmTrdSpadic object (not implemented!) + * + */ + CbmTrdSpadic(const CbmTrdSpadic&) = delete; + + /** + * @brief Assignment of CbmTrdSpadic objects (not implemented!) + * + * @return CbmTrdSpadic& + */ + CbmTrdSpadic& operator=(const CbmTrdSpadic&); + + /** + * @brief Destroy the Cbm Trd Spadic object + * + */ + virtual ~CbmTrdSpadic(); + + + /** + * @brief enum for response parameters + * + */ + enum class eResponsePars : size_t + { + kShapingTime = 0, + kShapingOrder, + kInputCharge, + kBinTimeshift, + kNrPresamples, + kChargeToMaxAdcCal, + kMipCal + }; + /** + * @brief Get the Parameter value + * + * @param partype + * @return Double_t + */ + Double_t GetParameter(eResponsePars partype) { return fvecResponsePars[static_cast<size_t>(partype)]; } + + static UInt_t GetNrChannels() { return NSPADICCH; } + + /** + * @brief Get a TF1 response function object. + * + * + * @return std::shared_ptr<TF1> + */ + static std::shared_ptr<TF1> GetResponseFunc(); + + /** + * @brief Get the Nr Of Adc Samples (Spadic default) + * + * @return constexpr UInt_t + */ + static constexpr UInt_t GetNrOfAdcSamples() { return fgNrOfAdcSamples; } + + /** + * @brief Get the Nr Of Preamples + * + * @return constexpr UInt_t + */ + static constexpr UInt_t GetNrOfPresamples() { return fgNrOfPresamples; } + + /** + * @brief Get the Shaping Order + * + * @return constexpr UInt_t + */ + static constexpr UInt_t GetShapingOrder() { return fgShapingOrder; } + + /** + * @brief Get the Shaping Time (Spadic default) + * + * @return Float_t + */ + static Float_t GetShapingTime() { return fgShapingTime; } + + /** + * @brief Get the Clock Cycle + * + * @return Double_t + */ + static Double_t GetClockCycle() { return fgClockCycleLength; } + + /** + * @brief Get the Charge To Max Adc Calibration value + * + * @return Double_t + */ + static Double_t GetChargeToMaxAdcCal() { return fgChargeToMaxAdcCal; } + + /** + * @brief Response of the SPADIC v2.2 to an input charge, for a given timesample. + * + * In the parameter array thinks like shaping time, order, input charge and so on * can and have to be passed. Use this function for fitting for exampl. + * Use SpadicResponse(UInt_t samplenr) to get the response for the paramters + * setted in the given CbmTrdSpadic object. + * + * @param samplenr + * @param par + * @return Double_t + */ + static Double_t Response(Double_t* samplenr, Double_t* par); + + /** + * @brief Get the Analog Response to a given input charge per adc time bin + * + * If fNoiseLvl is set to a value above 0 it is automatically added to the response. + * + * @param inputCharge [keV] and not calibrated to MIP see fgMaxAdcMipCalibration + * @param binTimeshift timeshift of the signal within a CC [ns] + * @return std::vector<std::int16_t> calibrated to keV and MIP + */ + std::vector<std::int16_t> GetAnalogResponsePulse(Double_t inputCharge, Double_t binTimeshift = 0.0); + + /** + * @brief Get a Noise value based on the width of the noise distribution in sigmas. + * + * @param sigmaNoise + * @return Int_t + */ + Int_t GetNoise(Double_t sigmaNoise); + + /** + * @brief Get the Baseline Lvl value + * + * @return UInt_t + */ + UInt_t GetBaselineLvl() { return fBaselineLvl; } + + /** + * @brief Check the passed pulse for samples in clipping and reduce the value of + * those to fClippingStart. + * + * @tparam Pulse + * @param pulse + */ + template<class Pulse> + void ApplyClipping(Pulse* pulse) + { + for (auto& sample : *pulse) { + if (sample > fClippingStart) sample = fClippingStart; + } + } + + /** + * @brief Get the Analytic Timeshift value ns precision + * Calculate the timeshift within the spadic response based on the idea that on + * an analytical base it is only related to the offset between the clock cycle + * and the absolute time. + * @param absolutetime + * @return Double_t + */ + Double_t GetAnalyticTimeshift(Double_t absolutetime); + + /** + * @brief Get the Dynamic Range value + * + * @return UInt_t + */ + UInt_t GetDynamicRange() { return fDynamicRange; } + + /** + * @brief Get the Peaking Sample Pos + * + * Returns the sample posisiton were the response function peaks, based + * on the number of presamples and shaping time. + * @return UInt_t + */ + UInt_t GetPeakingSamplePos(); + + /** + * @brief Get the Clipping Start value + * + * @return Int_t + */ + Int_t GetClippingStart() { return fClippingStart; } + + /** + * @brief Get the Adc Noise Level value + * + * @return Float_t + */ + Float_t GetAdcNoiseLevel() { return fNoiseLvl; } + + /** + * @brief Get the Max Adc To Energy Cal value + * + * @return Float_t + */ + Float_t GetMaxAdcToEnergyCal() { return fMaxAdcToEnergyCal; } + + /** + * @brief Get the MaxAdc to Mip Calibration value + * + * @return Double_t + */ + Double_t GetMipCalibration() { return fMaxAdcToMipCal; } + + + /** + * @brief Get the Module Thickness value + * + * @return Float_t + */ + Float_t GetModuleThickness() { return fModuleThickness; } + + /** + * @brief Get the Use Baseline Avg flag + * + * The spadic either simply delievers n presamples or an average baseline as a single presample. + * + * @return true + * @return false + */ + bool GetUseBaselineAvg() { return fDoUseBaselineAvg; } + + /** + * @brief Return energy [keV (MC input GeV)] for a given max adc value, based on max adc to energy + * calibration. + * + * @param maxadc + * @return Float_t + */ + Float_t MaxAdcToEnergyCal(Float_t maxadc); + + + /** + * @brief Get the Trigger Decision + * Get the trigger decision for the spadic. Currently this is based on the & + * differential trigger approach. + * @todo Write a trigger base and derived class to allow for easy interchange + * between different trigger modes. This part can than be dropped. + * @tparam Pulse + * @param pulse + * @param multitriggersample + * @return CbmTrdDigi::eTriggerType + */ + template<class precision> + CbmTrdDigi::eTriggerType GetTriggerDecision(std::vector<precision>* pulse, UInt_t* sndtriggersample = nullptr) + { + if (pulse->empty()) return CbmTrdDigi::eTriggerType::kNTrg; + + if (sndtriggersample) *sndtriggersample = 0; + Int_t slopeFst = 0; + Int_t slopeSnd = 0; + bool selftrigger = false; + bool falling = false; + bool multihit = false; + + + // Loop from the pulse beginning to last sample which could release a trigger. + // Since, we need two positive sloapes in a row, the last two samples can not release a trigger alone + for (auto sampleIt = pulse->begin(); sampleIt < pulse->end() - 2; ++sampleIt) { + slopeFst = *(sampleIt + 1) - *sampleIt; + if (slopeFst < fTriggerSlopeConditionFst && !selftrigger) continue; + + slopeSnd = *(sampleIt + 1) - *sampleIt; + if (slopeSnd < 0 && !selftrigger) continue; + + if (!selftrigger) { + if (slopeFst >= 2 * fTriggerSlopeConditionFst) selftrigger = true; + if (slopeFst >= fTriggerSlopeConditionFst && slopeSnd >= fTriggerSlopeConditionSnd) selftrigger = true; + } + else { + if (falling) { + if (slopeFst >= 2 * fTriggerSlopeConditionFst) multihit = true; + if (slopeFst >= fTriggerSlopeConditionFst && slopeSnd >= fTriggerSlopeConditionSnd) multihit = true; + if (sndtriggersample) *sndtriggersample = sampleIt - pulse->begin(); + } + if (slopeFst < 0 && slopeSnd < 0) falling = true; + } + if (multihit) break; + } + CbmTrdDigi::eTriggerType triggerType = CbmTrdDigi::eTriggerType::kNeighbor; + if (selftrigger && !multihit) triggerType = CbmTrdDigi::eTriggerType::kSelf; + if (selftrigger && multihit) triggerType = CbmTrdDigi::eTriggerType::kMulti; + + return triggerType; + } + /** + * @brief Set the Dynamic Range value + * + * @return UInt_t + */ + void SetDynamicRange(UInt_t value) { fDynamicRange = value; } + + /** + * @brief Set the Clipping Start value + * + * @param value + */ + void SetClippingStart(Int_t value) { fClippingStart = value; } + + void SetNoiseLevel(Double_t value) { fNoiseLvl = value; } + + /** + * @brief Set the Trigger Slope Condition value + * + * @param value + */ + void SetFstTriggerSlopeCondition(Double_t value) { fTriggerSlopeConditionFst = value; } + + /** + * @brief Set the Trigger Slope Condition value + * + * @param value + */ + void SetSndTriggerSlopeCondition(Double_t value) { fTriggerSlopeConditionSnd = value; } + + /** + * @brief Set the Max Adc To Energy Cal value + * + * @param value + */ + void SetMaxAdcToEnergyCal(Double_t value) { fMaxAdcToEnergyCal = value; } + + /** + * @brief Set the max adc to mip calibration value + * + * @param value + */ + void SetMipCalibration(Double_t value) { fMaxAdcToMipCal = value; } + + + /** + * @brief Set the Module Thickness value + * + * @param value + */ + void SetModuleThickness(Double_t value) { fModuleThickness = value; } + + /** + * @brief Set the Baseline Lvl value + * + * @param value + */ + void SetBaselineLvl(UInt_t value) { fBaselineLvl = value; } + + /** + * @brief Set the Use Baseline Average flag + * + * @param value + */ + void SetUseBaselineAverage(bool value = true) { fDoUseBaselineAvg = value; } + + /** + * @brief Response of the SPADIC v2.2 to an input charge, for a given timesample. + * + * Return the spadic response based on the parameters setted in this + * CbmTrdSpadic object. + * + * @param samplenr + * @return Double_t + */ + Double_t Response(UInt_t samplenr); + + void SetParameter(eResponsePars ipar, Double_t value) { fvecResponsePars.at(static_cast<size_t>(ipar)) = value; } + +private: + /** + * @brief Clockcycle length of SPADIC v2.2 + * + */ + static const Double_t fgClockCycleLength; + + /** + * @brief Vector for the response parameters. Order based on eResponsePars. + * The given values here correspond to the design/default values for SPADIC v2.2 + * - Shaping time = 142 ns (measured value from desy2019/lab2020) + * (design value = 120 ns). + * - Shaping order for the signal shaper. + * The default value (=1) corresponds to SPADIC v2.2 standard settings. + * - Input charge, default = 0 ADC units, charge to which the Spadic responses + * - Bin timeshift = ClockCycleLength / 2 ns shift placed at the sample center + * - Number of presamples = 2 standard value of presamples before the signal + * response starts + */ + std::vector<Double_t> fvecResponsePars = {fgShapingTime, fgShapingOrder, 0.0, + fgClockCycleLength / 2, fgNrOfPresamples, fgChargeToMaxAdcCal}; + + /** + * @brief Number of ADC samples. + * + * Number of ADC samples available. + * Default (32) corresponds to the maximum number of samples for SPADIC v2.2 + */ + static constexpr UInt_t fgNrOfAdcSamples = 32; + + /** + * @brief Spadic shaping time. + * + * Shaping time of the Spadic signal shaper, value corresponds to the best + * knowledge from measurements (status 23.02.2021 PR) please update if newer + * results are available + * + */ + static const Double_t fgShapingTime; + + /** + * @brief Spadic Shaping order + * + * Default value of the Spadic shaping order = 1 (status 23.02.2021 PR) + */ + static constexpr UInt_t fgShapingOrder = 1; + + /** + * @brief Number of presamples in the ADC signal in front of the actual signal + * + * Default Spadic value = 2 (status 23.02.2021 PR) please update if this changes. + * Default Spadic value = 1 (status 16.06.2021 PR) please update if this changes. + */ + static constexpr UInt_t fgNrOfPresamples = 1; + + /** + * @brief Calibration factor for input charges + * + * Charge calibration for fit response to max adc, i.e. this scales the response * for a given input charge to match the corresponding max adc value. + * Default Spadic value = 2.73 extracted from fits to desy2019 and lab data + * (status 23.02.2021 PR) please update if this changes. + */ + static const Double_t fgChargeToMaxAdcCal; + + /** + * @brief Dynamic range of the spadic + * The Spadic uses a 9-Bit ADC + */ + UInt_t fDynamicRange = std::pow(2, 9); + + /** + * @brief Value where a analog and or digital clipping appears + * By default it is set to the dynamic range of Spadic. + */ + Int_t fClippingStart = fDynamicRange; + + /** + * @brief Slope trigger condition for a two stage differential triggger. + * + * This defines the min diff between the first two consecutive rising samples in + * the pulse, to mark the pulse with CbmTrdDigi::eTriggerType::kSelf. + * An analytical MIP pulse with a conservative shaping time of 300 ns (keep in mind + * that a pulse is not a delta input) has a diff of 16 at the first relevant step. + * Based on response definition status March 2021 - PR. + * + */ + Int_t fTriggerSlopeConditionFst = 15; + + /** + * @brief Slope trigger condition for a two stage differential triggger. + * + * This defines the min diff between the second pair of two consecutive rising + * samples in the pulse, to mark the pulse with CbmTrdDigi::eTriggerType::kSelf. + * An analytical MIP pulse with a conservative shaping time of 300 ns (keep in mind + * that a pulse is not a delta input) has a diff of 10 at the second (this) + * relevant step. Based on response definition status March 2021 - PR. + * Remark: There is an ignore switch for this condition if the slope of the first + * check exceeds the condition by 2. Since, a 120 ns shaping time pulse will have + * the combination of 30 and 5 as slopes. + */ + Int_t fTriggerSlopeConditionSnd = 9; + + /** + * @brief Thickness of the module [cm] this spadic is mounted on. + * Should be setted during runtime from parameters. For the time being the + * default 1.2 cm should be fine, since all modules with spadics have the same + * thickness. + * @todo connect this to the parameters in runtime usage. + */ + Float_t fModuleThickness = 1.20; + + /** + * @brief Baseline level of the current Spadic + * Used for MaxAdcToMip calibration and baseline placement in Analogue Response + */ + // UInt_t fBaselineLvl = 10; + UInt_t fBaselineLvl = 0; + + /** + * @brief Calibration for MIP to 7% of MaxAdc dynamic range. + * 0.65 = charge from PRF broad distribution on central pad + * fModuleThickness * CbmTrdMipDeDx() = mean deposited mip energy per chamber + * fgChargeToMaxAdcCal = Factor between input charge for spadic response and max + * adc value handled in response function + * 0.08 * (fDynamicRange - 10) = 8% of the dynamic range with 10 ADU as baseline + * approximation + */ + Float_t fMaxAdcToMipCal = (CbmTrddEdxUtils::MipDeDx() * fModuleThickness * CbmTrddEdxUtils::MeanChargeCentrPadPRF()) + / (CbmTrddEdxUtils::MipCaliTarget() * (fDynamicRange - fBaselineLvl)); + // Float_t fMaxAdcToMipCal = 1; + + /** @brief Calibration value to calculate energy in keV based on the max adc value. Default = Simulation calibration. */ + Float_t fMaxAdcToEnergyCal = fMaxAdcToMipCal; + + /** @brief Noise level for signal response simulation [gaus sigmas] */ + Float_t fNoiseLvl = 1; + + /** @brief Flag wether we have n standard presamples or the average baseline in a single presamples */ + bool fDoUseBaselineAvg = false; + +public: + ClassDef(CbmTrdSpadic, 2); +}; +#endif diff --git a/core/detectors/trd/CbmTrddEdxUtils.cxx b/core/detectors/trd/CbmTrddEdxUtils.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a853a68467dda77fa3de8aa202ae07c1562dcb9c --- /dev/null +++ b/core/detectors/trd/CbmTrddEdxUtils.cxx @@ -0,0 +1,30 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +#include "CbmTrddEdxUtils.h" + +#include <RtypesCore.h> + +#include <iostream> // for cout + +#include <cmath> // for Sqrt/Pow/Log + +CbmTrddEdxUtils::CbmTrddEdxUtils() {} +CbmTrddEdxUtils::~CbmTrddEdxUtils() {} + +// ---- GetMipNormedBB ---- +Double_t CbmTrddEdxUtils::GetMipNormedBB(Double_t betaGamma) +{ + const Double_t beta = betaGamma / std::sqrt(1. + betaGamma * betaGamma); + + Double_t nominator = (4.4 - std::pow(beta, 2.26) - std::log(0.004 + 1 / std::pow(betaGamma, 0.95))); + + Double_t denominator = std::pow(beta, 2.26); + + Double_t bb = 0.2 * nominator / denominator; + + return bb; +} + +ClassImp(CbmTrddEdxUtils) diff --git a/core/detectors/trd/CbmTrddEdxUtils.h b/core/detectors/trd/CbmTrddEdxUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..2d4399322ded67984c8d6de5b8c6a41a87120d2d --- /dev/null +++ b/core/detectors/trd/CbmTrddEdxUtils.h @@ -0,0 +1,92 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +/** + * @file CbmTrddEdxUtils.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Class containing definitions and functions correlated to the dEdx behavior of the CbmTrd + * @version 0.1 + * @date 2021-04-08 + * + * + */ + +#ifndef CBMTRDDEDXUTILS_H +#define CBMTRDDEDXUTILS_H + +#include <Rtypes.h> +#include <RtypesCore.h> + + +class CbmTrddEdxUtils { +public: + /** + * @brief Construct a new CbmTrd dEdx Utils object + * + */ + CbmTrddEdxUtils(); + + /** + * @brief Copy constructor (not implemented!) + * + */ + CbmTrddEdxUtils(const CbmTrddEdxUtils&) = delete; + + /** + * @brief Assignment operator (not implemented!) + * + * @return CbmTrddEdxUtils& + */ + CbmTrddEdxUtils& operator=(const CbmTrddEdxUtils&); + + /** + * @brief Destroy the CbmTrd dEdx Utils object + * + */ + virtual ~CbmTrddEdxUtils(); + + /** + * @brief Mip De Dx kev/cm for XeC02 8020 see https://cbm-wiki.gsi.de/foswiki/bin/view/TRD/ TrdParameterList + * + * @return Double_t + */ + static Double_t MipDeDx() { return 5.0; } + + /** + * @brief Mean number of primary electron per cm created by a MIP (current value corresponds to GEANT3 PR20210408 - see e.g. https://www.uni-frankfurt.de/96680075/Doktorarbeit_Etienne_Bechtel.pdf) + * + * @return Double_t + */ + static Double_t MipMeanPrimaryEles() { return 20.5; } + + /** + * @brief Target percentage of the dynamic range for the MIP energy deposition on the central pad. + * + * @return Double_t + */ + static Double_t MipCaliTarget() { return 0.07; } + + /** + * @brief Get the Mip normalized Bethe-Bloch dEdx value + * Returns Q/Q_MIP based on a given parametrization of the Bethe-Bloch function + * In the current status it returns the values for the ALEPH/ALICE-TRD parametrization + * see https://arxiv.org/pdf/1709.02743.pdf + * @param betaGamma + * @return Double_t + */ + static Double_t GetMipNormedBB(Double_t betaGamma); + + /** + * @brief Mean charge fraction on the central pad assuming a flat distrubtion all over the pad. + * + * @return Double_t + */ + static Double_t MeanChargeCentrPadPRF() { return 0.65; } + + // protected: + // private: +public: + ClassDef(CbmTrddEdxUtils, 2) +}; +#endif // CBMTRDDEDEXUTILS_H diff --git a/fles/mcbm2018/CMakeLists.txt b/fles/mcbm2018/CMakeLists.txt index 0a1d9a427387e8f451360eaaac87071f101fe8a9..d94505ba4aedcc019f1c05e86fc1f0304e07248a 100644 --- a/fles/mcbm2018/CMakeLists.txt +++ b/fles/mcbm2018/CMakeLists.txt @@ -25,7 +25,6 @@ Set(INCLUDE_DIRECTORIES ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/unpacker ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/monitor ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/tasks - ${CBMDETECTORBASE_DIR}/trd # required for parameter handling of the trd ${CBMDETECTORBASE_DIR}/psd ${CBMDETECTORBASE_DIR}/sts diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoTrdR.cxx b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoTrdR.cxx index a966225905301912591b900bb5ddf8ccc8fc4280..9fe20417ce622aab4127253ee3b4bc5fff95ced6 100644 --- a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoTrdR.cxx +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoTrdR.cxx @@ -423,8 +423,9 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::CreateHistogram(ECbmTrdUnpackerHistograms iH break; case kRawHitType: histName += "RawHitTypes"; - newHisto = new TH1I(histName.Data(), histName.Data(), ((Int_t) Spadic::TriggerType::kSandN + 1), - ((Int_t) Spadic::TriggerType::kGlobal - 0.5), ((Int_t) Spadic::TriggerType::kSandN) + 0.5); + newHisto = + new TH1I(histName.Data(), histName.Data(), ((Int_t) Spadic::eTriggerType::kSandN + 1), + ((Int_t) Spadic::eTriggerType::kGlobal - 0.5), ((Int_t) Spadic::eTriggerType::kSandN) + 0.5); break; case kRawPulserDeltaT: histName += "RawPulserDeltaT"; @@ -453,9 +454,9 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::CreateHistogram(ECbmTrdUnpackerHistograms iH histName += "DigiDeltaT"; newHisto = new TH1I(histName.Data(), histName.Data(), 6000, -10, ((6e7) - 10)); // FIXME this should be more flexibel and made available for all modules of a given geometry - fLastDigiTimeVec = std::vector<std::uint64_t>(((CbmTrdParModDigi*) fDigiPar->GetModulePar(5))->GetNofColumns() - * ((CbmTrdParModDigi*) fDigiPar->GetModulePar(5))->GetNofRows(), - 0); + fLastDigiTimeVec = std::vector<size_t>(((CbmTrdParModDigi*) fDigiPar->GetModulePar(5))->GetNofColumns() + * ((CbmTrdParModDigi*) fDigiPar->GetModulePar(5))->GetNofRows(), + 0); newHisto->SetXTitle("#Delta t [ns]"); newHisto->SetYTitle("Counts"); break; @@ -465,9 +466,9 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::CreateHistogram(ECbmTrdUnpackerHistograms iH new TProfile(histName.Data(), histName.Data(), parDigiModule->GetNofColumns() * parDigiModule->GetNofRows(), -0.5, parDigiModule->GetNofColumns() * parDigiModule->GetNofRows() - 0.5); // FIXME this should be more flexibel and made available for all modules of a given geometry - fLastDigiTimeVec = std::vector<std::uint64_t>(((CbmTrdParModDigi*) fDigiPar->GetModulePar(5))->GetNofColumns() - * ((CbmTrdParModDigi*) fDigiPar->GetModulePar(5))->GetNofRows(), - 0); + fLastDigiTimeVec = std::vector<size_t>(((CbmTrdParModDigi*) fDigiPar->GetModulePar(5))->GetNofColumns() + * ((CbmTrdParModDigi*) fDigiPar->GetModulePar(5))->GetNofRows(), + 0); newHisto->SetXTitle("Pad-Channel"); newHisto->SetYTitle("Hit frequency [kHz]"); break; @@ -522,7 +523,8 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::CreateHistogram(ECbmTrdUnpackerHistograms iH break; case kDigiTriggerType: histName += "DigiTriggerType"; - newHisto = new TH1I(histName.Data(), histName.Data(), CbmTrdDigi::kNTrg, -0.5, (CbmTrdDigi::kNTrg - 0.5)); + newHisto = new TH1I(histName.Data(), histName.Data(), static_cast<Int_t>(CbmTrdDigi::eTriggerType::kNTrg), -0.5, + (static_cast<Int_t>(CbmTrdDigi::eTriggerType::kNTrg) - 0.5)); break; case kDigiHitFrequency: histName += "DigiHitFrequency"; @@ -565,6 +567,10 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::FillHistograms(CbmTrdDigi const& digi) Bool_t isOkFill = kTRUE; Int_t channelAddress = digi.GetAddressChannel(); Int_t histoBaseId = digi.GetAddressModule() << (Int_t(std::log2(std::double_t(kEndDefinedHistos))) + 1); + + // Get the digi triggertype + auto triggertype = static_cast<CbmTrdDigi::eTriggerType>(digi.GetTriggerType()); + //Digi position monitoring if (fIsActiveHistoVec[kDigiDistributionMap] || fIsActiveHistoVec[kDigiDistributionMapSt] || fIsActiveHistoVec[kDigiDistributionMapNt]) { @@ -580,18 +586,18 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::FillHistograms(CbmTrdDigi const& digi) ((TH2I*) fHistoArray.At(histoBaseId + kDigiDistributionMap))->Fill(column, row); } if (fIsActiveHistoVec[kDigiDistributionMapSt]) { - if (digi.GetAddressModule() == 5 && digi.GetTriggerType() == CbmTrdDigi::kSelf) + if (digi.GetAddressModule() == 5 && triggertype == CbmTrdDigi::eTriggerType::kSelf) ((TH2I*) fHistoArray.At(histoBaseId + kDigiDistributionMapSt))->Fill(column, row); } if (fIsActiveHistoVec[kDigiDistributionMapNt]) { - if (digi.GetAddressModule() == 5 && digi.GetTriggerType() == CbmTrdDigi::kNeighbor) + if (digi.GetAddressModule() == 5 && triggertype == CbmTrdDigi::eTriggerType::kNeighbor) ((TH2I*) fHistoArray.At(histoBaseId + kDigiDistributionMapNt))->Fill(column, row); } } // "DigiRelativeTinTimeslice" if (fIsActiveHistoVec[kDigiRelativeTimeMicroslice]) { - std::uint64_t digiTime = digi.GetTime(); - std::uint64_t deltaT = digiTime - (fSpadicEpoch * fdMsSizeInCC * 62.5); // in clockcycles + size_t digiTime = digi.GetTime(); + size_t deltaT = digiTime - (fSpadicEpoch * fdMsSizeInCC * 62.5); // in clockcycles ((TH1D*) fHistoArray.At(histoBaseId + kDigiRelativeTimeMicroslice))->Fill(deltaT); } // "kDigiChargeSpectrum" @@ -600,12 +606,12 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::FillHistograms(CbmTrdDigi const& digi) } // "kDigiChargeSpectrumSt" if (fIsActiveHistoVec[kDigiChargeSpectrumSt]) { - if (digi.GetTriggerType() == CbmTrdDigi::kSelf) + if (triggertype == CbmTrdDigi::eTriggerType::kSelf) ((TH1I*) fHistoArray.At(histoBaseId + kDigiChargeSpectrumSt))->Fill(digi.GetCharge()); } // "kDigiChargeSpectrumNt" if (fIsActiveHistoVec[kDigiChargeSpectrumNt]) { - if (digi.GetTriggerType() == CbmTrdDigi::kNeighbor) + if (triggertype == CbmTrdDigi::eTriggerType::kNeighbor) ((TH1I*) fHistoArray.At(histoBaseId + kDigiChargeSpectrumNt))->Fill(digi.GetCharge()); } // "kDigiChargeSpectrumNt" @@ -617,7 +623,7 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::FillHistograms(CbmTrdDigi const& digi) // "kDigiDeltaT" // DigiPulserDeltaT // "kDigiMeanHitFrequency" // FIXME this works currently with only one module if (fIsActiveHistoVec[kDigiDeltaT] || fIsActiveHistoVec[kDigiMeanHitFrequency] || fIsActiveHistoVec[kDigiPulserDeltaT]) { - std::uint64_t dt = ((std::uint64_t) digi.GetTime() - fLastDigiTimeVec.at(channelAddress)); + size_t dt = ((size_t) digi.GetTime() - fLastDigiTimeVec.at(channelAddress)); if (dt > 0) { // "kDigiDeltaT" if (fIsActiveHistoVec[kDigiDeltaT]) { ((TH1I*) fHistoArray.At(histoBaseId + kDigiDeltaT))->Fill(dt); } @@ -636,7 +642,7 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::FillHistograms(CbmTrdDigi const& digi) Int_t pulserChannelAddress(663); // status 03/27/2020 Int_t pulserModule(5); // status 03/27/2020 if (channelAddress == pulserChannelAddress && digi.GetAddressModule() == pulserModule - && digi.GetTriggerType() == CbmTrdDigi::kSelf) { + && triggertype == CbmTrdDigi::eTriggerType::kSelf) { ((TH1I*) fHistoArray.At(histoBaseId + kDigiPulserDeltaT))->Fill(dt); } } @@ -652,7 +658,7 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::FillHistograms(CbmTrdDigi const& digi) if (tsCounter == 0) ((TProfile*) fHistoArray.At(histoBaseId + kDigiHitFrequency))->Reset(); } } - fLastDigiTimeVec.at(channelAddress) = (std::uint64_t) digi.GetTime(); + fLastDigiTimeVec.at(channelAddress) = (size_t) digi.GetTime(); } } return isOkFill; @@ -665,31 +671,31 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::FillHistograms(CbmTrdRawMessageSpadic const& // "RawMessage_Signalshape_filtered" if (fIsActiveHistoVec[kRawMessage_Signalshape_filtered]) { if (raw.GetHitType() < 2 && !raw.GetMultiHit()) { - for (unsigned int i = 0; i < raw.GetSamples().size(); i++) { - ((TH2I*) fHistoArray.At(kRawMessage_Signalshape_filtered))->Fill(i, raw.GetSamples()[i]); + for (unsigned int i = 0; i < raw.GetSamples()->size(); i++) { + ((TH2I*) fHistoArray.At(kRawMessage_Signalshape_filtered))->Fill(i, raw.GetSamples()->at(i)); } } } // "RawMessage_Signalshape_all" if (fIsActiveHistoVec[kRawMessage_Signalshape_all]) { - for (unsigned int i = 0; i < raw.GetSamples().size(); i++) { - //fHistoMap.at(HistName.Data())->Fill(i, raw.GetSamples()[i]); - ((TH2I*) fHistoArray.At(kRawMessage_Signalshape_all))->Fill(i, raw.GetSamples()[i]); + for (unsigned int i = 0; i < raw.GetSamples()->size(); i++) { + //fHistoMap.at(HistName.Data())->Fill(i, raw.GetSamples()->at(i)); + ((TH2I*) fHistoArray.At(kRawMessage_Signalshape_all))->Fill(i, raw.GetSamples()->at(i)); } } // "kRawMessage_Signalshape_St" if (fIsActiveHistoVec[kRawMessage_Signalshape_St]) { - for (unsigned int i = 0; i < raw.GetSamples().size(); i++) { - if (raw.GetHitType() == (Int_t) Spadic::TriggerType::kSelf - || raw.GetHitType() == (Int_t) Spadic::TriggerType::kSandN) - ((TH2I*) fHistoArray.At(kRawMessage_Signalshape_St))->Fill(i, raw.GetSamples()[i]); + for (unsigned int i = 0; i < raw.GetSamples()->size(); i++) { + if (raw.GetHitType() == (Int_t) Spadic::eTriggerType::kSelf + || raw.GetHitType() == (Int_t) Spadic::eTriggerType::kSandN) + ((TH2I*) fHistoArray.At(kRawMessage_Signalshape_St))->Fill(i, raw.GetSamples()->at(i)); } } // "kRawMessage_Signalshape_Nt" if (fIsActiveHistoVec[kRawMessage_Signalshape_Nt]) { - for (unsigned int i = 0; i < raw.GetSamples().size(); i++) { - if (raw.GetHitType() == (Int_t) Spadic::TriggerType::kNeigh) - ((TH2I*) fHistoArray.At(kRawMessage_Signalshape_Nt))->Fill(i, raw.GetSamples()[i]); + for (unsigned int i = 0; i < raw.GetSamples()->size(); i++) { + if (raw.GetHitType() == (Int_t) Spadic::eTriggerType::kNeigh) + ((TH2I*) fHistoArray.At(kRawMessage_Signalshape_Nt))->Fill(i, raw.GetSamples()->at(i)); } } // "RawDistributionMapModule5" @@ -711,7 +717,7 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::FillHistograms(CbmTrdRawMessageSpadic const& return isOkFill; } - +// ---- CbmMcbm2018UnpackerAlgoTrdR::ResetHistograms() ---- Bool_t CbmMcbm2018UnpackerAlgoTrdR::ResetHistograms() { /* @@ -738,9 +744,8 @@ Bool_t CbmMcbm2018UnpackerAlgoTrdR::SetDigiOutputPointer(std::vector<CbmTrdDigi> } } -Bool_t -CbmMcbm2018UnpackerAlgoTrdR::SetRawOutputPointer(std::vector<CbmTrdRawMessageSpadic>* const pVector, - std::vector<std::pair<std::uint64_t, std::uint64_t>>* const qVector) +Bool_t CbmMcbm2018UnpackerAlgoTrdR::SetRawOutputPointer(std::vector<CbmTrdRawMessageSpadic>* const pVector, + std::vector<std::pair<size_t, size_t>>* const qVector) { Bool_t ret = 1; if (nullptr == fTrdRawMessageVector) { fTrdRawMessageVector = pVector; } @@ -764,15 +769,17 @@ std::shared_ptr<CbmTrdDigi> CbmMcbm2018UnpackerAlgoTrdR::MakeDigi(CbmTrdRawMessa (Float_t) raw.GetMaxAdc() + 256; // REMARK raw.GetMaxADC returns a the value in the range of -256 til 255. However, the digiCharge is stored as unsigned. // TODO make Settable - // Int_t digiTriggerType = raw.GetHitType() ; // Spadic::TriggerType this does not work 03/27/2020 - PR digiTriggerType is not Spadic::TriggerType! - Int_t digiTriggerType = raw.GetHitType(); - if (digiTriggerType == 1) digiTriggerType = 0; // Shift self trigger to digi selftrigger - if (digiTriggerType == 2) digiTriggerType = 1; // Shift neighbour trigger to digi neighbour - if (digiTriggerType == 3) digiTriggerType = 0; // Hide spadic kSandN in Self + // Int_t digiTriggerType = raw.GetHitType() ; // Spadic::eTriggerType this does not work 03/27/2020 - PR digiTriggerType is not Spadic::eTriggerType! + Int_t rawTriggerType = raw.GetHitType(); + auto digiTriggerType = CbmTrdDigi::eTriggerType::kNTrg; + if (rawTriggerType == 1) digiTriggerType = CbmTrdDigi::eTriggerType::kSelf; // Shift self trigger to digi selftrigger + if (rawTriggerType == 2) + digiTriggerType = CbmTrdDigi::eTriggerType::kNeighbor; // Shift neighbour trigger to digi neighbour + if (rawTriggerType == 3) digiTriggerType = CbmTrdDigi::eTriggerType::kSelf; // Hide spadic kSandN in Self Int_t digiErrClass = 0; - std::uint64_t spadicHwAddress(0); + size_t spadicHwAddress(0); spadicHwAddress = (raw.GetElinkId()) + (CbmTrdParAsic::kCriIdPosition * raw.GetCriId()) + (CbmTrdParAsic::kCrobIdPosition * raw.GetCrobId()); Int_t asicAddress(0); diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoTrdR.h b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoTrdR.h index cc62700574a707457af350ead9178cfc5643f92f..c1b91aac9612ab928eb213083a13244f18a89a63 100644 --- a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoTrdR.h +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoTrdR.h @@ -24,9 +24,6 @@ #include "TObjArray.h" #include "TProfile.h" #include "TString.h" -//#include "CbmTrdRawToDigiR.h" -/// TODO: include the relevant functions of CbmTrdRawToDigiR into the unpacker-algo. -/// as first step one can copy CbmTrdRawToDigiR.h and CbmTrdRawToDigiR.cxx to the same folder as this file. /** * @class CbmMcbm2018UnpackerAlgoTrdR @@ -144,7 +141,7 @@ public: * @return kTRUE if fTrdRawMessageVector was nullptr before. kFALSE else. **/ Bool_t SetRawOutputPointer(std::vector<CbmTrdRawMessageSpadic>* const pVector, - std::vector<std::pair<std::uint64_t, std::uint64_t>>* const qVector = nullptr); + std::vector<std::pair<size_t, size_t>>* const qVector = nullptr); void SetRefGeoTag(TString geoTag) { fRefGeoTag = geoTag; } void SetFirstChannelsElinkEven(bool isEven) { fIsFirstChannelsElinkEven = isEven; } @@ -191,14 +188,14 @@ private: std::vector<CbmTrdRawMessageSpadic>* fTrdRawMessageVector; /// vector< pair< fulltime, word > > - std::vector<std::pair<std::uint64_t, std::uint64_t>>* fSpadicInfoMsgVector; + std::vector<std::pair<size_t, size_t>>* fSpadicInfoMsgVector; //std::map< TString, std::shared_ptr<TH1> > fHistoMap ; /// Stores all Histograms. std::vector<bool> fIsActiveHistoVec; TObjArray fHistoArray; - std::vector<std::uint64_t> fLastDigiTimeVec; + std::vector<size_t> fLastDigiTimeVec; /** * @brief Instance of RawToDigi class. @@ -234,7 +231,7 @@ private: CbmTrdParSetGas* fGasPar; ///< CbmTrdParameter container CbmTrdParSetGain* fGainPar; ///< CbmTrdParameter container - std::map<std::uint64_t, Int_t> fSpadicMap; + std::map<size_t, Int_t> fSpadicMap; ///< Map to retrieve asic address from CriId/CrobId/ElinkId (see CbmTrdHardwareSetupR) std::map<Int_t, std::vector<Int_t>> fAsicChannelMap; diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskTrdR.cxx b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskTrdR.cxx index 5d7e6b084733421e9da82c82de34810baa296fde..655ffeface45a11ba1ac51f17c42870e8ca48932 100644 --- a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskTrdR.cxx +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskTrdR.cxx @@ -60,7 +60,7 @@ Bool_t CbmMcbm2018UnpackerTaskTrdR::Init() /// Register RawMessage output vector, if DebugWrite is enabled. if (fbDebugWriteOutput) { fTrdRawMessageVector = new std::vector<CbmTrdRawMessageSpadic>(); - fSpadicInfoMsgVector = new std::vector<std::pair<std::uint64_t, std::uint64_t>>(); + fSpadicInfoMsgVector = new std::vector<std::pair<size_t, size_t>>(); if (fTrdRawMessageVector && fSpadicInfoMsgVector) { ioman->RegisterAny("CbmTrdSpadicRawMessages", fTrdRawMessageVector, kTRUE); ioman->RegisterAny("CbmTrdSpadicInfoMessages", fSpadicInfoMsgVector, kTRUE); diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskTrdR.h b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskTrdR.h index b356cf6974df3452907d9c298584ecd730ef089e..bd86e06791388d168ab9be3645b2489e20a1c30f 100644 --- a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskTrdR.h +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskTrdR.h @@ -126,7 +126,7 @@ private: std::vector<CbmTrdRawMessageSpadic>* fTrdRawMessageVector; /// vector< pair< fulltime, word > > - std::vector<std::pair<std::uint64_t, std::uint64_t>>* fSpadicInfoMsgVector; + std::vector<std::pair<size_t, size_t>>* fSpadicInfoMsgVector; /// Processing algo CbmMcbm2018UnpackerAlgoTrdR* fUnpackerAlgo; diff --git a/macro/run/run_unpack_online.C b/macro/run/run_unpack_online.C new file mode 100644 index 0000000000000000000000000000000000000000..9147cfe15965511b018261fccfe4f2630c08e7af --- /dev/null +++ b/macro/run/run_unpack_online.C @@ -0,0 +1,237 @@ +/** @file run_unpack_tsa.C + ** @author Volker Friese <v.friese@gsi.de> + ** @since May 2021 + **/ + + +// --- Includes needed for IDE +#include <FairSource.h> + +#include <RtypesCore.h> + +#include <memory> +#include <vector> +#if !defined(__CLING__) +#include <FairLogger.h> +#include <FairRootFileSink.h> +#include <FairRunOnline.h> +#include <Logger.h> + +#include <TStopwatch.h> +#include <TSystem.h> +#endif + +std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename); +std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline = false); + + +/** @brief Macro for CBM reconstruction + ** @author Volker Friese <v.friese@gsi.de> + ** @since 14 November 2020 + ** @param input Name of input file (w/o extension .raw.root) + ** @param nTimeSlices Number of time-slices to process + ** @param firstTimeSlice First time-slice (entry) to be processed + ** @param output Name of output file (w/o extension .rec.root) + ** @param sEvBuildRaw Option for raw event building + ** @param setup Name of predefined geometry setup + ** @param paramFile Parameter ROOT file (w/o extension .par.root) + ** @param useMC Option to provide the trackfinder with MC information + ** + ** This macro performs from the digis in a time-slice. It can be used + ** for simulated data (result of run_digi.C) or real data after unpacking. + ** + ** The macro covers both time-based reconstruction and event-based + ** reconstruction using raw events build from digis. This can be selected + ** by the forth argument. If left empty, no raw event builder will be + ** employed and reconstruction will be time-based. The option "Ideal" + ** selects the ideal raw event builder, which associates digis to events + ** based on the MC truth. The option "Real" selects a real raw event builder + ** (latest version, for older versions use "Real2018" or "Real2019"). + ** + ** + ** The file names must be specified without extensions. The convention is + ** that the raw (input) file is [input].raw.root. The output file + ** will be [input].rec.root if not specified by the user. The parameter file + ** has the extension .par.root. It is assumed to be [input].par.root if + ** not specified by the user. + ** + ** If no argument is specified, the input will be set to "test". This allows + ** to execute the macro chain (run_tra_file.C, run_digi.C and run_reco.C) + ** from the ROOT prompt without user intervention. + ** + **/ +void run_unpack_online(std::string publisher = "localhost", Int_t serverHttpPort = 8080, Int_t serverRefreshRate = 100, + const char* setupName = "mcbm_beam_2021_03", UInt_t runid = 2, std::string outpath = "") +{ + + // ======================================================================== + // Adjust this part according to your requirements + + // --- Logger settings ---------------------------------------------------- + TString logLevel = "INFO"; + TString logVerbosity = "LOW"; + // ------------------------------------------------------------------------ + + // ----- Environment -------------------------------------------------- + TString myName = "run_unpack_online"; // this macro's name for screen output + TString srcDir = gSystem->Getenv("VMCWORKDIR"); // top source directory + // ------------------------------------------------------------------------ + + // ----- Output filename ---------------------------------------------- + TDatime datetime; + // Get the current time and date to label the output data. We add ".tsa" to run the default translations for the .digi and .mon output file + std::string infile = + "mTrd_Testrun-" + std::to_string(datetime.GetDate()) + "_" + std::to_string(datetime.GetTime()) + ".tsa"; + std::string outfilename = outpath + infile; + outfilename.replace(outfilename.find(".tsa"), 4, ".digi.root"); + // ------------------------------------------------------------------------ + + // ----- CbmSetup ----------------------------------------------------- + auto cbmsetup = CbmSetup::Instance(); + cbmsetup->LoadSetup(setupName); + // ------------------------------------------------------------------------ + + // ----- UnpackerConfigs ---------------------------------------------- + + // ---- TRD ---- + TString trdsetuptag = ""; + cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag); + auto trdconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), runid); + std::string parfilesbasepath = Form("%s/parameters/trd", srcDir.Data()); + trdconfig->SetParFilesBasePath(parfilesbasepath); + trdconfig->SetMonitor(GetTrdMonitor(outfilename)); + // Get the spadic configuration true = avg baseline active / false plain sample 0 + trdconfig->SetSpadicObject(GetTrdSpadic(true)); + // ------------- + + // ------------------------------------------------------------------------ + + // In general, the following parts need not be touched + // ======================================================================== + + + // ----- Timer -------------------------------------------------------- + TStopwatch timer; + timer.Start(); + // ------------------------------------------------------------------------ + + + // ----- CbmSourceTsArchive ------------------------------------------- + auto source = new CbmSourceTsArchive(publisher.data()); + source->SetSourceType(Source_Type::kONLINE); + auto unpack = source->GetRecoUnpack(); + unpack->SetUnpackConfig(trdconfig); + // ------------------------------------------------------------------------ + + + // ----- FairRunAna --------------------------------------------------- + auto run = new FairRunOnline(source); + // auto sink = new FairRootFileSink(outfilename.data()); + // run->SetSink(sink); + // ------------------------------------------------------------------------ + + + // ----- HttpServer for online monitoring ----------------------------- + run->ActivateHttpServer(serverRefreshRate, serverHttpPort); + run->GetHttpServer()->GetSniffer()->SetScanGlobalDir(kFALSE); + run->SetAutoFinish(kFALSE); + // ------------------------------------------------------------------------ + + + // ----- Logger settings ---------------------------------------------- + FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data()); + FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data()); + // ------------------------------------------------------------------------ + + + // ----- Run initialisation ------------------------------------------- + std::cout << std::endl; + std::cout << "-I- " << myName << ": Initialise run" << std::endl; + run->Init(); + // ------------------------------------------------------------------------ + + + // ----- Start run ---------------------------------------------------- + std::cout << std::endl << std::endl; + std::cout << "-I- " << myName << ": Starting run" << std::endl; + // run->Run(-1, 0); + run->Run(0, 50); + // ------------------------------------------------------------------------ + + + // ----- Finish ------------------------------------------------------- + timer.Stop(); + std::cout << "Macro finished successfully after CpuTime = " << timer.CpuTime() << " s RealTime = " << timer.RealTime() + << " s." << std::endl; + // ------------------------------------------------------------------------ + +} // End of main macro function + + +/** + * @brief Get the Trd Monitor. Extra function to keep default macro part more silent. + * @return std::shared_ptr<CbmTrdUnpackMonitor> +*/ +std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename) +{ + // ----- Output filename and path ------------------------------------- + std::string outpath = ""; + std::string filename = ""; + auto filenamepos = treefilename.find_last_of("/"); + if (filenamepos != treefilename.npos) { + outpath = treefilename.substr(0, filenamepos); + filename = treefilename.substr(filenamepos++); + } + if (outpath.empty()) outpath = gSystem->GetWorkingDirectory(); + std::string mydir = "/qa"; + outpath += mydir; + + auto currentdir = gSystem->GetWorkingDirectory(); + + if (!gSystem->cd(outpath.data())) gSystem->MakeDirectory(outpath.data()); + else + gSystem->cd(currentdir.data()); + + std::string outfilename = outpath + filename; + auto filetypepos = outfilename.find(".digi.root"); + if (filetypepos != outfilename.npos) outfilename.replace(filetypepos, 10, ".mon.trd.root"); + else + outfilename += ".mon.trd.root"; + // ------------------------------------------------------------------------ + + std::vector<CbmTrdUnpackMonitor::eDigiHistos> digihistovec = { + CbmTrdUnpackMonitor::eDigiHistos::kMap, CbmTrdUnpackMonitor::eDigiHistos::kMap_St, + CbmTrdUnpackMonitor::eDigiHistos::kMap_Nt, CbmTrdUnpackMonitor::eDigiHistos::kCharge, + CbmTrdUnpackMonitor::eDigiHistos::kCharge_St, CbmTrdUnpackMonitor::eDigiHistos::kCharge_Nt, + CbmTrdUnpackMonitor::eDigiHistos::kTriggerType, CbmTrdUnpackMonitor::eDigiHistos::kDigiDeltaT}; + + std::vector<CbmTrdUnpackMonitor::eRawHistos> rawhistovec = { + CbmTrdUnpackMonitor::eRawHistos::kSignalshape, CbmTrdUnpackMonitor::eRawHistos::kSignalshape_St, + CbmTrdUnpackMonitor::eRawHistos::kSignalshape_Nt, CbmTrdUnpackMonitor::eRawHistos::kElinkId, + CbmTrdUnpackMonitor::eRawHistos::kSampleDistStdDev, CbmTrdUnpackMonitor::eRawHistos::kSample0perChannel, + CbmTrdUnpackMonitor::eRawHistos::kHitType}; + + std::vector<CbmTrdUnpackMonitor::eOtherHistos> otherhistovec = {CbmTrdUnpackMonitor::eOtherHistos::kSpadic_Info_Types, + CbmTrdUnpackMonitor::eOtherHistos::kMs_Flags}; + + auto monitor = std::make_shared<CbmTrdUnpackMonitor>(); + monitor->SetActiveHistos(digihistovec); + monitor->SetActiveHistos(rawhistovec); + monitor->SetActiveHistos(otherhistovec); + monitor->SetWriteToFile(outfilename.data()); + + return monitor; +} + +/** + * @brief Get the Trd Spadic + * @return std::shared_ptr<CbmTrdSpadic> +*/ +std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline) +{ + auto spadic = std::make_shared<CbmTrdSpadic>(); + spadic->SetUseBaselineAverage(useAvgBaseline); + spadic->SetMaxAdcToEnergyCal(1); + + return spadic; +} diff --git a/macro/run/run_unpack_tsa.C b/macro/run/run_unpack_tsa.C new file mode 100644 index 0000000000000000000000000000000000000000..b10652c5a771655352c8a85bf693a856ee262f7a --- /dev/null +++ b/macro/run/run_unpack_tsa.C @@ -0,0 +1,252 @@ +/** @file run_unpack_tsa.C + ** @author Volker Friese <v.friese@gsi.de> + ** @since May 2021 + **/ + + +// --- Includes needed for IDE +#include <RtypesCore.h> + +#include <cstdint> +#include <memory> +#include <string> +#include <vector> +#if !defined(__CLING__) +#include "CbmTrdRawMessageSpadic.h" +#include "CbmTrdSpadic.h" + +#include <FairLogger.h> +#include <FairRootFileSink.h> +#include <FairRunOnline.h> +#include <Logger.h> + +#include <TStopwatch.h> +#include <TSystem.h> +#endif + +std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename); +std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline = false); + + +/** @brief Macro for CBM reconstruction + ** @author Volker Friese <v.friese@gsi.de> + ** @since 14 November 2020 + ** @param input Name of input file (w/o extension .raw.root) + ** @param nTimeSlices Number of time-slices to process + ** @param firstTimeSlice First time-slice (entry) to be processed + ** @param output Name of output file (w/o extension .rec.root) + ** @param sEvBuildRaw Option for raw event building + ** @param setup Name of predefined geometry setup + ** @param paramFile Parameter ROOT file (w/o extension .par.root) + ** @param useMC Option to provide the trackfinder with MC information + ** + ** This macro performs from the digis in a time-slice. It can be used + ** for simulated data (result of run_digi.C) or real data after unpacking. + ** + ** The macro covers both time-based reconstruction and event-based + ** reconstruction using raw events build from digis. This can be selected + ** by the forth argument. If left empty, no raw event builder will be + ** employed and reconstruction will be time-based. The option "Ideal" + ** selects the ideal raw event builder, which associates digis to events + ** based on the MC truth. The option "Real" selects a real raw event builder + ** (latest version, for older versions use "Real2018" or "Real2019"). + ** + ** + ** The file names must be specified without extensions. The convention is + ** that the raw (input) file is [input].raw.root. The output file + ** will be [input].rec.root if not specified by the user. The parameter file + ** has the extension .par.root. It is assumed to be [input].par.root if + ** not specified by the user. + ** + ** If no argument is specified, the input will be set to "test". This allows + ** to execute the macro chain (run_tra_file.C, run_digi.C and run_reco.C) + ** from the ROOT prompt without user intervention. + ** + **/ +void run_unpack_tsa(std::string infile = "test.tsa", UInt_t runid = 0, const char* setupName = "mcbm_beam_2021_03", + std::int32_t nevents = -1, std::string outpath = "") +{ + + // ======================================================================== + // Adjust this part according to your requirements + + // --- Logger settings ---------------------------------------------------- + TString logLevel = "INFO"; + TString logVerbosity = "LOW"; + // ------------------------------------------------------------------------ + + // ----- Environment -------------------------------------------------- + TString myName = "run_unpack_tsa"; // this macro's name for screen output + TString srcDir = gSystem->Getenv("VMCWORKDIR"); // top source directory + // ------------------------------------------------------------------------ + + + // ----- Potentially hardcode the infile ------------------------------ + + // std::string infile = srcDir + "/input/mcbm_run399_first20Ts.tsa"; + + // ------------------------------------------------------------------------ + + + // ----- Output filename ---------------------------------------------- + std::string outfilename = infile; + auto filenamepos = infile.find_last_of("/"); + filenamepos++; + std::string filename = infile.substr(filenamepos); + if (filename.find("*") != infile.npos) filename = std::to_string(runid) + ".tsa"; + if (filename.find(";") != infile.npos) filename = std::to_string(runid) + "_merged" + ".tsa"; + if (outpath.empty()) { outpath = infile.substr(0, filenamepos); } + outfilename = outpath + filename; + outfilename.replace(outfilename.find(".tsa"), 4, ".digi.root"); + // ------------------------------------------------------------------------ + + + // ----- CbmSetup ----------------------------------------------------- + auto cbmsetup = CbmSetup::Instance(); + cbmsetup->LoadSetup(setupName); + // ------------------------------------------------------------------------ + + // ----- UnpackerConfigs ---------------------------------------------- + + // ---- TRD ---- + TString trdsetuptag = ""; + cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag); + // auto trdconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), runid); + auto trdconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), 3); + // trdconfig->SetDebugState(); + trdconfig->SetDoWriteOutput(); + trdconfig->SetDoWriteOptOutA(CbmTrdRawMessageSpadic::GetBranchName()); + // trdconfig->SetDoWriteOptOutB("SpadicInfoMessages"); // SpadicInfoMessages + + std::string parfilesbasepath = Form("%s/parameters/trd", srcDir.Data()); + trdconfig->SetParFilesBasePath(parfilesbasepath); + trdconfig->SetMonitor(GetTrdMonitor(outfilename)); + // Get the spadic configuration true = avg baseline active / false plain sample 0 + trdconfig->SetSpadicObject(GetTrdSpadic(true)); + // ------------- + + // ------------------------------------------------------------------------ + + // In general, the following parts need not be touched + // ======================================================================== + + + // ----- Timer -------------------------------------------------------- + TStopwatch timer; + timer.Start(); + // ------------------------------------------------------------------------ + + + // ----- CbmSourceTsArchive ------------------------------------------- + auto source = new CbmSourceTsArchive(infile.data()); + auto unpack = source->GetRecoUnpack(); + unpack->SetUnpackConfig(trdconfig); + // ------------------------------------------------------------------------ + + + // ----- FairRunAna --------------------------------------------------- + auto run = new FairRunOnline(source); + auto sink = new FairRootFileSink(outfilename.data()); + run->SetSink(sink); + // ------------------------------------------------------------------------ + + + // ----- Logger settings ---------------------------------------------- + FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data()); + FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data()); + // ------------------------------------------------------------------------ + + + // ----- Run initialisation ------------------------------------------- + std::cout << std::endl; + std::cout << "-I- " << myName << ": Initialise run" << std::endl; + run->Init(); + // ------------------------------------------------------------------------ + + + // ----- Start run ---------------------------------------------------- + std::cout << std::endl << std::endl; + std::cout << "-I- " << myName << ": Starting run" << std::endl; + if (nevents < 0) run->Run(-1, 0); + else + run->Run(0, nevents); + // ------------------------------------------------------------------------ + + + // ----- Finish ------------------------------------------------------- + timer.Stop(); + std::cout << "Macro finished successfully after CpuTime = " << timer.CpuTime() << " s RealTime = " << timer.RealTime() + << " s." << std::endl; + // ------------------------------------------------------------------------ + +} // End of main macro function + + +/** + * @brief Get the Trd Monitor. Extra function to keep default macro part more silent. + * @return std::shared_ptr<CbmTrdUnpackMonitor> +*/ +std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename) +{ + + // ----- Output filename and path ------------------------------------- + std::string outpath = ""; + std::string filename = ""; + auto filenamepos = treefilename.find_last_of("/"); + if (filenamepos != treefilename.npos) { + outpath = treefilename.substr(0, filenamepos); + filename = treefilename.substr(filenamepos++); + } + if (outpath.empty()) outpath = gSystem->GetWorkingDirectory(); + std::string mydir = "/qa"; + outpath += mydir; + + auto currentdir = gSystem->GetWorkingDirectory(); + + if (!gSystem->cd(outpath.data())) gSystem->MakeDirectory(outpath.data()); + else + gSystem->cd(currentdir.data()); + + std::string outfilename = outpath + filename; + auto filetypepos = outfilename.find(".digi.root"); + if (filetypepos != outfilename.npos) outfilename.replace(filetypepos, 10, ".mon.trd.root"); + else + outfilename += ".mon.trd.root"; + // ------------------------------------------------------------------------ + + std::vector<CbmTrdUnpackMonitor::eDigiHistos> digihistovec = { + CbmTrdUnpackMonitor::eDigiHistos::kMap, CbmTrdUnpackMonitor::eDigiHistos::kMap_St, + CbmTrdUnpackMonitor::eDigiHistos::kMap_Nt, CbmTrdUnpackMonitor::eDigiHistos::kCharge, + CbmTrdUnpackMonitor::eDigiHistos::kCharge_St, CbmTrdUnpackMonitor::eDigiHistos::kCharge_Nt, + CbmTrdUnpackMonitor::eDigiHistos::kTriggerType, CbmTrdUnpackMonitor::eDigiHistos::kDigiDeltaT}; + + std::vector<CbmTrdUnpackMonitor::eRawHistos> rawhistovec = { + CbmTrdUnpackMonitor::eRawHistos::kSignalshape, CbmTrdUnpackMonitor::eRawHistos::kSignalshape_St, + CbmTrdUnpackMonitor::eRawHistos::kSignalshape_Nt, CbmTrdUnpackMonitor::eRawHistos::kElinkId, + CbmTrdUnpackMonitor::eRawHistos::kSampleDistStdDev, CbmTrdUnpackMonitor::eRawHistos::kSample0perChannel, + CbmTrdUnpackMonitor::eRawHistos::kHitType}; + + std::vector<CbmTrdUnpackMonitor::eOtherHistos> otherhistovec = {CbmTrdUnpackMonitor::eOtherHistos::kSpadic_Info_Types, + CbmTrdUnpackMonitor::eOtherHistos::kMs_Flags}; + + auto monitor = std::make_shared<CbmTrdUnpackMonitor>(); + monitor->SetActiveHistos(digihistovec); + monitor->SetActiveHistos(rawhistovec); + monitor->SetActiveHistos(otherhistovec); + monitor->SetWriteToFile(outfilename.data()); + + return monitor; +} + +/** + * @brief Get the Trd Spadic + * @return std::shared_ptr<CbmTrdSpadic> +*/ +std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline) +{ + auto spadic = std::make_shared<CbmTrdSpadic>(); + spadic->SetUseBaselineAverage(useAvgBaseline); + spadic->SetMaxAdcToEnergyCal(1.0); + + return spadic; +} diff --git a/reco/CMakeLists.txt b/reco/CMakeLists.txt index b83fe2e79d84399470fa823f9123931acde7260d..c31e7d8f51a63f8f8254872194ba42ed57bfb2af 100644 --- a/reco/CMakeLists.txt +++ b/reco/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(global) add_subdirectory(KF) add_subdirectory(L1) add_subdirectory(littrack) +add_subdirectory(steer) add_subdirectory(tracking) add_subdirectory(qa) diff --git a/reco/L1/CMakeLists.txt b/reco/L1/CMakeLists.txt index c183c708432b8c8a68a1e3aae749e95125d87b3f..2344dcd91db4d463d4051eabe2d49fdf4a9a0729 100644 --- a/reco/L1/CMakeLists.txt +++ b/reco/L1/CMakeLists.txt @@ -40,7 +40,7 @@ ${CBMDATA_DIR} ${CBMDETECTORBASE_DIR}/sts ${CBMROOT_SOURCE_DIR}/mvd - ${CBMDETECTORBASE_DIR}/trd + ${CBMDETECTORBASE_DIR}/trd ${CBMDETECTORBASE_DIR}/much ${CBMDETECTORBASE_DIR}/tof ) diff --git a/reco/base/CMakeLists.txt b/reco/base/CMakeLists.txt index 1193800963e6e1c8b08b4af33c5cf5a3b827310f..fc222c674bfc02f261521db48c4ea1582ca8a275 100644 --- a/reco/base/CMakeLists.txt +++ b/reco/base/CMakeLists.txt @@ -78,6 +78,15 @@ set(LINKDEF ${LIBRARY_NAME}LinkDef.h) # --------------------------------------------------------- +# ----- Install files without source file -------------- +Install(FILES + CbmRecoUnpackConfig.tmpl + CbmRecoUnpackAlgo.tmpl + DESTINATION include +) +# --------------------------------------------------------- + + # ----- Let cmake do the job --------------------------- include_directories( ${INCLUDE_DIRECTORIES}) include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES}) diff --git a/reco/base/CbmRecoUnpackAlgo.tmpl b/reco/base/CbmRecoUnpackAlgo.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..f453e8be93bc72efca22c794f297c64930aa243a --- /dev/null +++ b/reco/base/CbmRecoUnpackAlgo.tmpl @@ -0,0 +1,395 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +/** + * @file CbmRecoUnpackAlgo.tmpl + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Baseclass for the Trd unpacker algorithms + * @version 0.1 + * @date 2021-04-21 + * + * @copyright Copyright (c) 2021 + * + * This is the base class for the algorithmic part of the tsa data unpacking + * processes of the CbmTrd. + * The actual translation from tsa to digi happens in the derived classes. + * + * +*/ + +#ifndef CbmRecoUnpackAlgo_TMPL +#define CbmRecoUnpackAlgo_TMPL + +#include "Timeslice.hpp" // timeslice +#include <MicrosliceDescriptor.hpp> + +#include <FairParGenericSet.h> // for par container vector +#include <FairTask.h> // for Bool_t +#include <Logger.h> // for log output + +#include <Rtypes.h> // for types +#include <RtypesCore.h> +#include <tuple> +#include <type_traits> + +#include <algorithm> +#include <cstddef> +#include <cstdint> // for types +#include <memory> +#include <vector> + + +template<class TOutput, class TOptOutA = std::nullptr_t, class TOptOutB = std::nullptr_t> +class CbmRecoUnpackAlgo { + +public: + /** @brief Create the Cbm Trd Unpack AlgoBase object */ + CbmRecoUnpackAlgo(std::uint8_t flesSubsystemId, std::string name) : fFlesSubsystemId(flesSubsystemId), fName(name) {}; + + /** @brief Destroy the Cbm Trd Unpack Task object */ + virtual ~CbmRecoUnpackAlgo() {}; + + /** @brief Copy constructor - not implemented **/ + CbmRecoUnpackAlgo(const CbmRecoUnpackAlgo&) = delete; + + /** @brief Assignment operator - not implemented **/ + CbmRecoUnpackAlgo& operator=(const CbmRecoUnpackAlgo&) = delete; + +protected: + // Output vectors + /** @brief Default return vector for Unpack function. */ + std::vector<TOutput> fOutputVec = {}; + + /** @brief Opt output vector connected to the framework. */ + std::vector<TOptOutA>* fOptOutAVec = {}; + + /** @brief Opt output vectors connected to the framework. */ + std::vector<TOptOutB>* fOptOutBVec = {}; + + // Parameter storage members + /** @brief SubsystemId as defined by fles and encoded in the timeslices. To be set in the derived classes. Ensures, that only data of the asics connected to the given unpacker are passed to it by the Task/Device. */ + std::uint8_t fFlesSubsystemId; + + /** @brief Vector with the parameter containers and the paths to the connected ascii files of the TRD */ + std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>> fParContVec = {}; + + /** @brief Base path to the trd parameter files. */ + std::string fParFilesBasePath = ""; + + /** + * @brief Time offset for the system + * @todo This should be module and channel dependent and included into the asic parameters + */ + std::int32_t fSystemTimeoffset = 0; + + /** @brief Check if we are looking at the first timeslice and if so extract the required TS parameters */ + bool fIsFirstTs = true; + + /** @brief The unpacker algo ignores the overlapp microslices if true.*/ + bool fDoIgnoreOverlappMs = true; + + /** @brief Number of microslices per timeslice */ + std::uint32_t fNrMsPerTs = 0; + + /** @brief Number of core microslices per timeslice */ + std::uint32_t fNrCoreMsPerTs = 0; + + /** @brief Number of overlapp microslices per timeslice */ + std::uint32_t fNrOverlappMsPerTs = 0; + + /** @brief Name of the unpacker class, used for logging output */ + std::string fName = ""; + + /** @brief Full length of the TS [ns], currently automatically calculated with fMsLength and fNrMsPerTs */ + size_t fTsLength = 0; + + /** @brief Core length of the TS [ns], currently automatically calculated with fMsLength and fNrCoreMsPerTs */ + size_t fTsCoreLength = 0; + + /** @brief counter of processed timeslices */ + size_t fNrProcessedTs = 0; + + /** @brief counter of created raw messages */ + size_t fNrCreatedDigis = 0; + + /** @brief counter of created raw messages */ + size_t fNrCreatedRawMsgs = 0; + + /** @brief counter of created raw messages */ + size_t fNrCreatedInfoMsgs = 0; + + /** @brief counter of created raw messages */ + size_t fNrEpochMsgs = 0; + + /** @brief counter for inf/error flags from the µSlices */ + size_t fNrCrcValidFlags = 0; + /** @brief counter for inf/error flags from the µSlices */ + size_t fNrOverflowFlimFlags = 0; + /** @brief counter for inf/error flags from the µSlices */ + size_t fNrOverflowUserFlags = 0; + /** @brief counter for inf/error flags from the µSlices */ + size_t fNrDataErrorFlags = 0; + + /** @brief Time of the last succesful digest hit message */ + size_t fLastFulltime = 0; + + /** @brief Additional explicit finish function of the derived algo implementations. */ + virtual void finish() = 0; + + /** + * @brief Get the Timeslice Params and transfer them to the member variables + * + * @param ts + */ + void getTimesliceParams(const fles::Timeslice* ts) + { + // Get microslice length and "number of" information + fNrCoreMsPerTs = ts->num_core_microslices(); + fNrMsPerTs = ts->num_microslices(0); + fNrOverlappMsPerTs = fNrMsPerTs - fNrCoreMsPerTs; + + + LOG(debug4) << fName << "::getTimesliceParams :"; + LOG(debug4) << "Timeslice parameters: each TS has " << fNrCoreMsPerTs << " Core MS and " << fNrOverlappMsPerTs + << " Overlap MS, for a TS core duration of " << fTsCoreLength << " ns and a full duration of " + << fTsLength << " ns"; + + // deactivate this function after it has been run once. + fIsFirstTs = false; + } + + /** + * @brief Forward the parameters stored in the containers to the member variables. + * + * @retval Bool_t initOk If not kSUCCESS, task will be set inactive. + */ + Bool_t initParContainers() + { + LOG(debug4) << fName << "::Init - InitParContainers"; + + auto initOk = kTRUE; + std::vector<std::shared_ptr<FairParGenericSet>> requested = {}; + std::vector<bool> reqs = {}; + + + for (auto pair : fParContVec) { + auto parcontainer = pair.second; + initOk = initParSet(parcontainer.get()); + // Check if a required container is missing after we went through all passed containers. + if (!initOk) { + LOG(error) << fName << "::InitParContainers() initParSet failed for the required paramater container " + << parcontainer->ClassName() << ", please check!"; + return kFALSE; + } + } + return kTRUE; + } + + /** + * @brief Handles the distribution of the hidden derived classes to their explicit functions. + * + * @param parset + * @return Bool_t + */ + virtual Bool_t initParSet(FairParGenericSet* parset) = 0; + + /** + * @brief Set the Derived Ts Parameters + * + * In this function parameters required by the explicit algo connected to the timeslice can be set. + * + * @param itimeslice + * @return true + * @return false + */ + virtual bool setDerivedTsParameters(size_t itimeslice) = 0; + + + /** + * @brief Intialisation at begin of run. Special inits of the derived algos. + * + * @retval Bool_t initOk + */ + virtual Bool_t init() = 0; + + /** @brief Sort a vector timewise vector type has to provide GetTime() */ + template<class vecobj> + void timesort(std::vector<vecobj>* vec) + { + std::sort(vec->begin(), vec->end(), + [](const vecobj& a, const vecobj& b) -> bool { return a.GetTime() < b.GetTime(); }); + } + + /** + * @brief Unpack a given microslice. To be implemented in the derived unpacker algos. + * + * @param ts timeslice pointer + * @param icomp index to the component to be unpacked + * @param imslice index of the microslice to be unpacked + * @return true + * @return false + * + * @remark The content of the µslice can only be accessed via the timeslice. Hence, we need to pass the pointer to the full timeslice + */ + virtual bool unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice) = 0; + +public: + // Runtime functions + + /** + * @brief Add a parameter container and the path to its ascii input. Note that all containers have to be derived from FairParGenericSet. + * @param pair + */ + void AddParContainer(std::pair<std::string, std::shared_ptr<FairParGenericSet>> pair) + { + fParContVec.emplace_back(pair); + } + + /** + * @brief Action at end of run. + * + */ + void Finish() + { + LOG(info) << fName << "::Finish. Unpacked \n " << fNrProcessedTs << " Timeslices with \n " << fNrCreatedRawMsgs + << " Raw Messages,\n " << fNrCreatedDigis << " Digis,\n " << fNrEpochMsgs << " Epoch Messages,\n " + << fNrCreatedInfoMsgs << " Info Messages.\n "; + + LOG(info) << fName << "::Finish. \n Number of CrcValidFlags " << fNrCrcValidFlags + << " \n Number of OverflowFlimFlags " << fNrOverflowFlimFlags << " \n Number of OverflowUserFlags " + << fNrOverflowUserFlags << " \n Number of DataErrorFlags " << fNrDataErrorFlags; + + // Additional explicit finish of the derived class used during runtime. + finish(); + } + + /** + * @brief Get the Fles Subsystem Id stored in fFlesSubsystemId + * + * @return std::uint8_t + */ + std::uint8_t GetFlesSubsystemId() { return fFlesSubsystemId; } + + /** + * @brief Get the Name of the (derived) object + * + * @return std::string + */ + std::string GetName() { return fName; } + + // Getters + /** + * @brief Get a given output vector connected to the tree, if called after calling InitUnpacker(). + * + * @return std::vector<TOptOutA>* + */ + std::vector<TOptOutA>* GetOptOutAVec() { return fOptOutAVec; } + + /** + * @brief Get a given output vector connected to the tree, if called after calling InitUnpacker(). + * + * @return std::vector<TOptOutA>* + */ + std::vector<TOptOutA>* GetOptOutBVec() { return fOptOutBVec; } + + /** + * @brief Get the requested parameter containers. To be defined in the derived classes! + * Return the required parameter containers together with the paths to the ascii + * files to. + * + * @param[in] std::string geoTag as used in CbmSetup + * @param[in] std::uint32_t runId for runwise defined parameters + * @return fParContVec + */ + virtual std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* + GetParContainerRequest(std::string geoTag, std::uint32_t runId) = 0; + + /** + * @brief Intialisation at begin of run. + * + * Runs for all types of algos. In case you need a specialised init function add it as protected function and call it in this Init function. + * + * @retval Bool_t initOk If not kTRUE, task will be set inactive. + */ + Bool_t Init() + { + LOG(info) << fName << "::Init()"; + + auto initOk = kTRUE; + + initOk &= init(); + + initOk &= initParContainers(); + + return initOk; + } + + // Setters + /** + * @brief Set the Do Ignore Overlapp µslices flag + * + * @param value + */ + void SetDoIgnoreOverlappMs(bool value = false) { fDoIgnoreOverlappMs = value; } + + /** @brief Set the optional output A vector @param vec */ + void SetOptOutAVec(std::vector<TOptOutA>* vec) { fOptOutAVec = vec; } + + /** @brief Set the optional output B vector @param vec */ + void SetOptOutBVec(std::vector<TOptOutB>* vec) { fOptOutBVec = vec; } + + /** + * @brief Set the base path to the parameter containers. + * + * @param value + */ + void SetParFilesBasePath(std::string value) { fParFilesBasePath = value; } + + /** + * @brief Actual unpacking function + * + * @param option + * @return true + * @return false + */ + std::vector<TOutput> Unpack(const fles::Timeslice* ts, std::uint16_t icomp) + { + bool unpackOk = true; + + // Clear the default return vector + fOutputVec.clear(); + + /// On first TS, extract the TS parameters from header (by definition stable over time). + if (fIsFirstTs) getTimesliceParams(ts); + + // Get the index of the current timeslice + auto currTsIdx = ts->index(); + // Get the number of the current timeslice (the index increases currently via nthTimeslice* fNrCoreMsPerTs) + size_t itimeslice = currTsIdx / fNrCoreMsPerTs; + + // Set further parameters required by the explicit algorithm + setDerivedTsParameters(itimeslice); + + auto nrMsToLoop = fDoIgnoreOverlappMs ? fNrCoreMsPerTs : fNrMsPerTs; + + /// Loop over choosen microslices (all or core only) + for (UInt_t imslice = 0; imslice < nrMsToLoop; imslice++) { + unpackOk &= unpack(ts, icomp, imslice); + if (!unpackOk) { + /** @todo add potential counter for corrupted microslices */ + continue; + } + } + + + // Sort the optional output vectors according to the time. (Digi vector is handled by CbmRecoUnpack) + ++fNrProcessedTs; + return fOutputVec; + } + +public: + ClassDef(CbmRecoUnpackAlgo, 2) +}; + +#endif // CbmRecoUnpackAlgo_H diff --git a/reco/base/CbmRecoUnpackConfig.tmpl b/reco/base/CbmRecoUnpackConfig.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..fc70bdb20bf35c9edf17f156d6f400d6cd6d2e8a --- /dev/null +++ b/reco/base/CbmRecoUnpackConfig.tmpl @@ -0,0 +1,252 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +/** + * @file CbmRecoUnpackConfig.tmpl + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Configuration class for an unpacker algorithm + * @version 0.1 + * @date 2021-04-21 + * + * @copyright Copyright (c) 2021 + * + * This is the common steering task to run unpacking processes in a FairRun for the + * CbmTrd. + * + * + * + * +*/ + +#ifndef CbmRecoUnpackConfig_tmpl +#define CbmRecoUnpackConfig_tmpl + +#include "CbmRecoUnpackAlgo.tmpl" + +#include <FairLogger.h> +#include <FairParAsciiFileIo.h> +#include <FairRootManager.h> +#include <Logger.h> + +#include <Rtypes.h> +#include <RtypesCore.h> + +#include <cstdint> +#include <memory> +#include <vector> + +template<class TAlgo, class TOutput, class TOptOutA = std::nullptr_t, class TOptOutB = std::nullptr_t> +class CbmRecoUnpackConfig { + +public: + /** + * @brief Create a Cbm Reco Unpack Config object + */ + CbmRecoUnpackConfig(std::string name) : fName(name) {}; + + /** + * @brief Destroy the Cbm Trd Unpack Task object + * + */ + virtual ~CbmRecoUnpackConfig() {}; + + /** @brief Copy constructor - not implemented **/ + CbmRecoUnpackConfig(const CbmRecoUnpackConfig&) = delete; + + /** @brief Assignment operator - not implemented **/ + CbmRecoUnpackConfig& operator=(const CbmRecoUnpackConfig&) = delete; + +protected: + // Output vectors + /** @brief Pointer to the output vectors connected to the framework. */ + std::vector<TOutput>* fOutputVec = nullptr; + + /** @brief Name for the branch of the output, set together with the write output flag. */ + std::string fOutputBranchName = ""; + + /** @brief Pointer to the opt output vectors connected to the framework. */ + std::vector<TOptOutA>* fOptOutAVec = nullptr; + + /** @brief Name for the branch of the output, set together with the write output flag. */ + std::string fOptoutABranchName = ""; + + /** @brief Pointer to the opt output vectors connected to the framework. */ + std::vector<TOptOutB>* fOptOutBVec = nullptr; + + /** @brief Name for the branch of the output, set together with the write output flag. */ + std::string fOptoutBBranchName = ""; + + /** @brief Pointer to the algorithm to be used for data connected to this config */ + std::shared_ptr<TAlgo> fAlgo = nullptr; + + // Runtime parameters + std::string fParFilesBasePath = ""; + + /** @brief Name of the (derived) class for debugging statements */ + std::string fName = ""; + + /** @brief Do debug printouts. Call SetDebugState() to activate*/ + bool fDoLog = false; + + /** @brief Decision if the output is supposed to be stored to a branch. */ + bool fDoWriteOutput = false; + + /** @brief Decision if the opt output A is supposed to be stored to a branch. */ + bool fDoWriteOptOutA = false; + + /** @brief Decision if the opt output B is supposed to be stored to a branch. */ + bool fDoWriteOptOutB = false; + + /** @brief Decision if the info msgs are supposed to be stored to a branch. */ + bool fIsMC = false; + + + /** @brief Use this function to implement additional actions to be called once per TS, e.g. needed if more than the default output vector is used. */ + virtual void reset() { return; }; + + +public: + // Getters + /** @brief Get the name of the given derived config */ + std::string GetName() { return fName; } + + /** + * @brief Get a given output vector connected to the tree, if called after calling InitUnpacker(). + * + * @return std::vector<TOutput>* + */ + std::vector<TOutput>* GetOutputVec() { return fOutputVec; } + + /** + * @brief Get a given output vector connected to the tree, if called after calling InitUnpacker(). + * + * @return std::vector<TOptOutA>* + */ + std::vector<TOptOutA>* GetOptOutAVec() { return fOptOutAVec; } + + /** + * @brief Get a given output vector connected to the tree, if called after calling InitUnpacker(). + * + * @return std::vector<TOptOutA>* + */ + std::vector<TOptOutB>* GetOptOutBVec() { return fOptOutBVec; } + + /** + * @brief Get the ready to run Unpacker. To be defined in the derived classes. + * In this function also all initialization steps of the unpacker algorithms have to happen. + * @return std::shared_ptr<CbmRecoUnpackAlgo> + */ + std::shared_ptr<CbmRecoUnpackAlgo<TOutput, TOptOutA, TOptOutB>> GetUnpacker() { return fAlgo; }; + + void Init(FairRootManager* ioman) + { + if (fDoWriteOutput) { + fOutputVec = new std::vector<TOutput>(); + ioman->RegisterAny(TOutput::GetBranchName(), fOutputVec, kTRUE); + LOG(info) << fName << "::registerBranchToTree(" << TOutput::GetBranchName() << ")"; + } + + if (fDoWriteOptOutA) { + fOptOutAVec = new std::vector<TOptOutA>(); + ioman->RegisterAny(fOptoutABranchName.data(), fOptOutAVec, kTRUE); + LOG(info) << fName << "::registerBranchToTree(" << fOptoutABranchName.data() << ")"; + } + + if (fDoWriteOptOutB) { + fOptOutBVec = new std::vector<TOptOutB>(); + ioman->RegisterAny(fOptoutBBranchName.data(), fOptOutBVec, kTRUE); + LOG(info) << fName << "::registerBranchToTree(" << fOptoutBBranchName.data() << ")"; + } + } + + /** @brief Prepare the Unpacker algorithm for the run, to be implemented in the derived classes. */ + virtual void InitUnpacker() = 0; + + /** @brief Reset called once per ReadEvent() */ + void Reset() + { + // Clear the default vector + if (fOutputVec) fOutputVec->clear(); + if (fOptOutAVec) fOptOutAVec->clear(); + if (fOptOutBVec) fOptOutBVec->clear(); + // Use this function if you need to do more things in your derived config. + reset(); + }; + + // Setters + /** + * @brief Set the Do Write Digis flag, without activation the digis are not written to the sink + * @param value + */ + void SetDoWriteOutput(bool value = true) { fDoWriteOutput = value; } + + /** + * @brief Set the Do Write OptOutput A flag, without activation the opt out is not written to the sink + * @param branchname name of the branch in the output tree + * @param value bool + */ + void SetDoWriteOptOutA(std::string branchname, bool value = true) + { + fOptoutABranchName = branchname; + fDoWriteOptOutA = value; + } + + /** + * @brief Set the Do Write OptOutput B flag, without activation the opt out is not written to the sink + * @param branchname name of the branch in the output tree + * @param value bool + */ + void SetDoWriteOptOutB(std::string branchname, bool value = true) + { + fOptoutBBranchName = branchname; + fDoWriteOptOutB = value; + } + + /** + * @brief Set the Debug State, influences the log messages. + * + * @param value + */ + void SetDebugState(bool value = true) { fDoLog = value; } + + /** + * @brief Set the is MC flag. Activates the Match branch. + * + * @param value + */ + void SetIsMC(bool value = true) { fIsMC = value; } + + /** + * @brief Set the Par Files Base Path (absolute directory path were the files are stored) + * + * @param value + */ + void SetParFilesBasePath(std::string value) { fParFilesBasePath = value; } + +protected: + /** + * @brief Initialise the parameter containers requested by the algorithm + * + * @return Bool_t initOk + */ + virtual Bool_t initParContainers(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec) + { + if (fDoLog) LOG(info) << GetName() << "::Init - initParContainers"; + + // Now get the actual ascii files and init the containers with the asciiIo + for (auto& pair : *reqparvec) { + auto filepath = pair.first; + auto parset = pair.second; + FairParAsciiFileIo asciiInput; + if (asciiInput.open(filepath.data())) { parset->init(&asciiInput); } + } + return kTRUE; + } + +public: + ClassDef(CbmRecoUnpackConfig, 2) +}; + + +#endif // CbmRecoUnpackConfig_tmpl diff --git a/reco/detectors/trd/CMakeLists.txt b/reco/detectors/trd/CMakeLists.txt index 71cdd58f5173525345133058452dc480664f1c95..2509f10e188fea5a6b2eef463943fca14d333a38 100644 --- a/reco/detectors/trd/CMakeLists.txt +++ b/reco/detectors/trd/CMakeLists.txt @@ -1,7 +1,13 @@ +# Create a library called "libTrdReco" which includes the source files given in +# the array . +# The extension is already found. Any number of sources could be listed here. + Set(INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/qa ${CMAKE_CURRENT_SOURCE_DIR}/pid + ${CMAKE_CURRENT_SOURCE_DIR}/rawToDigiMethods + ${CMAKE_CURRENT_SOURCE_DIR}/unpack ${CBMDETECTORBASE_DIR}/trd @@ -9,15 +15,14 @@ Set(INCLUDE_DIRECTORIES ${CBMBASE_DIR}/draw ${CBMROOT_SOURCE_DIR}/reco/base - + ${CBMDATA_DIR} ${CBMDATA_DIR}/base ${CBMDATA_DIR}/trd ${CBMDATA_DIR}/global -${CBMROOT_SOURCE_DIR}/rich/reco - ${CBMROOT_SOURCE_DIR}/reco/L1/vectors + ) Include_Directories( ${INCLUDE_DIRECTORIES}) @@ -25,6 +30,7 @@ Include_Directories( ${INCLUDE_DIRECTORIES}) Set(SYSTEM_INCLUDE_DIRECTORIES ${BASE_INCLUDE_DIRECTORIES} ${Boost_INCLUDE_DIR} + ${IPC_INCLUDE_DIRECTORY} # for fles infos for unpacker ) Include_Directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES}) @@ -38,6 +44,7 @@ set(LINK_DIRECTORIES link_directories( ${LINK_DIRECTORIES}) set(SRCS + CbmTrdTrackFinderIdeal.cxx CbmTrdTrackFitterIdeal.cxx CbmTrdClusterFinder.cxx @@ -46,6 +53,12 @@ CbmTrdModuleRec.cxx CbmTrdModuleRecR.cxx CbmTrdModuleRecT.cxx +unpack/CbmTrdUnpackConfig.cxx +unpack/CbmTrdUnpackAlgoBaseR.cxx +unpack/CbmTrdUnpackAlgoR.cxx +unpack/CbmTrdUnpackAlgoLegacy2020R.cxx +unpack/CbmTrdUnpackMonitor.cxx + qa/CbmTrdClusterizerFastQa.cxx qa/CbmTrdHitDensityQa.cxx qa/CbmTrdHitProducerClusterQa.cxx @@ -59,7 +72,12 @@ pid/CbmTrdElectronsTrainAnn.cxx pid/CbmTrdSetTracksPidWkn.cxx pid/CbmTrdSetTracksPidModWkn.cxx pid/CbmTrdSetTracksPidLike.cxx -pid/CbmTrdSetTracksPidANN.cxx +pid/CbmTrdSetTracksPidANN.cxx + +rawToDigiMethods/CbmTrdRawToDigiBaseR.cxx +rawToDigiMethods/CbmTrdRawToDigiMaxAdcR.cxx +rawToDigiMethods/CbmTrdRawToDigiFitR.cxx +rawToDigiMethods/CbmTrdRawToDigiLookUpCorrR.cxx ) IF (SSE_FOUND) @@ -76,7 +94,13 @@ ENDIF (SSE_FOUND) set(LINKDEF CbmTrdRecoLinkDef.h) Set(LIBRARY_NAME CbmTrdReco) Set(DEPENDENCIES - CbmRecoBase CbmBase CbmData Base CbmTrdBase TMVA + CbmRecoBase + CbmBase + CbmData + Base + CbmTrdBase + TMVA + fles_ipc # for unpacker ) GENERATE_LIBRARY() diff --git a/reco/detectors/trd/CbmTrdClusterFinder.cxx b/reco/detectors/trd/CbmTrdClusterFinder.cxx index f313f9f9be93aa71083538b0a4baadfba9b11084..9602bb039ea947298b98b20e7a7a94280b96c8a8 100644 --- a/reco/detectors/trd/CbmTrdClusterFinder.cxx +++ b/reco/detectors/trd/CbmTrdClusterFinder.cxx @@ -148,7 +148,7 @@ CbmTrdModuleRec* CbmTrdClusterFinder::AddModule(const CbmTrdDigi* digi) { Int_t address = digi->GetAddressModule(); CbmTrdModuleRec* module(NULL); - if (digi->GetType() == CbmTrdDigi::kFASP) module = fModules[address] = new CbmTrdModuleRecT(address); + if (digi->GetType() == CbmTrdDigi::eCbmTrdAsicType::kFASP) module = fModules[address] = new CbmTrdModuleRecT(address); else module = fModules[address] = new CbmTrdModuleRecR(address); @@ -186,7 +186,7 @@ CbmTrdModuleRec* CbmTrdClusterFinder::AddModule(const CbmTrdDigi* digi) module->SetChmbPar(pChmb); // try to load Gain parameters for module - if (digi->GetType() == CbmTrdDigi::kFASP) { + if (digi->GetType() == CbmTrdDigi::eCbmTrdAsicType::kFASP) { const CbmTrdParModGain* pGain(NULL); if (!fGainPar || !(pGain = (const CbmTrdParModGain*) fGainPar->GetModulePar(address))) { //LOG(warn) << GetName() << "::AddModule : No Gain params for modAddress "<< address <<". Using default."; diff --git a/reco/detectors/trd/CbmTrdHitProducer.cxx b/reco/detectors/trd/CbmTrdHitProducer.cxx index 27f373d88c8ac8acbc83b9f47b2bd91a37689257..904d9d3177c536b07e97205791ed2b20b4938654 100644 --- a/reco/detectors/trd/CbmTrdHitProducer.cxx +++ b/reco/detectors/trd/CbmTrdHitProducer.cxx @@ -191,7 +191,7 @@ void CbmTrdHitProducer::processCluster(const Int_t clusterIdx) for (Int_t iDigi = 0; iDigi < cluster->GetNofDigis(); iDigi++) { const CbmTrdDigi* digi = CbmDigiManager::Instance()->Get<CbmTrdDigi>(cluster->GetDigi(iDigi)); - if (digi->GetType() == CbmTrdDigi::kSPADIC && digi->GetCharge() <= 0) continue; + if (digi->GetType() == CbmTrdDigi::eCbmTrdAsicType::kSPADIC && digi->GetCharge() <= 0) continue; digivec.emplace_back(digi); } diff --git a/reco/detectors/trd/CbmTrdModuleRecR.cxx b/reco/detectors/trd/CbmTrdModuleRecR.cxx index c0ab5c033bf570ee0d8aececefd85e066c82cd47..a804d8aa9a6c63c46e1dbc14634865b98019b6c9 100644 --- a/reco/detectors/trd/CbmTrdModuleRecR.cxx +++ b/reco/detectors/trd/CbmTrdModuleRecR.cxx @@ -71,42 +71,14 @@ void CbmTrdModuleRecR::Clear(Option_t* opt) Int_t CbmTrdModuleRecR::FindClusters() { - std::deque<std::tuple<Int_t, Bool_t, const CbmTrdDigi*>>::iterator - mainit; // subiterator for the deques in each module; searches for - // main-trigger to then add the neighbors - std::deque<std::tuple<Int_t, Bool_t, const CbmTrdDigi*>>::iterator FNit; // last - // iterator to - // find the FN - // digis which - // correspond - // to the main - // trigger or - // the - // adjacent - // main - // triggers - std::deque<std::tuple<Int_t, Bool_t, const CbmTrdDigi*>>::iterator start; // marker to - // erase - // already - // processed - // entries - // from the - // map to - // reduce the - // complexity - // of the - // algorithm - std::deque<std::tuple<Int_t, Bool_t, const CbmTrdDigi*>>::iterator stop; // marker to - // erase - // already - // processed - // entries - // from the - // map to - // reduce the - // complexity - // of the - // algorithm + std::deque<std::tuple<Int_t, Bool_t, const CbmTrdDigi*>>::iterator mainit; + // subiterator for the deques in each module; searches for main-trigger to then add the neighbors + std::deque<std::tuple<Int_t, Bool_t, const CbmTrdDigi*>>::iterator FNit; + // last iterator to find the FN digis which correspond to the main trigger or the adjacent main triggers + std::deque<std::tuple<Int_t, Bool_t, const CbmTrdDigi*>>::iterator start; + // marker to erase already processed entries from the map to reduce the complexity of the algorithm + std::deque<std::tuple<Int_t, Bool_t, const CbmTrdDigi*>>::iterator stop; + // marker to erase already processed entries from the map to reduce the complexity of the algorithm // reset time information; used to erase processed digis from the map Double_t time = 0; @@ -114,7 +86,7 @@ Int_t CbmTrdModuleRecR::FindClusters() Double_t timediff = -1000; Int_t Clustercount = 0; - Double_t interval = CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC); + Double_t interval = CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC); Bool_t print = false; // iterator for the main trigger; searches for an unprocessed main triggered @@ -159,9 +131,10 @@ Int_t CbmTrdModuleRecR::FindClusters() } if (timediff < interval) stop = mainit; - Int_t triggerId = digi->GetTriggerType(); - Bool_t marked = std::get<1>(*mainit); - if (triggerId != CbmTrdDigi::kSelf || marked) continue; + Int_t triggerId = digi->GetTriggerType(); + CbmTrdDigi::eTriggerType triggertype = static_cast<CbmTrdDigi::eTriggerType>(triggerId); + Bool_t marked = std::get<1>(*mainit); + if (triggertype != CbmTrdDigi::eTriggerType::kSelf || marked) continue; // variety of neccessary address information; uses the "combiId" for the // comparison of digi positions @@ -254,12 +227,14 @@ Int_t CbmTrdModuleRecR::FindClusters() Int_t ch = d->GetAddressChannel(); Int_t col = ch % ncols; Int_t trigger = d->GetTriggerType(); + triggertype = static_cast<CbmTrdDigi::eTriggerType>(trigger); if (mergerow) { // multiple row processing // first buffering - if (ch == channel - ncols && !rowchange && trigger == CbmTrdDigi::kSelf && !std::get<1>(*FNit)) { + if (ch == channel - ncols && !rowchange && triggertype == CbmTrdDigi::eTriggerType::kSelf + && !std::get<1>(*FNit)) { rowchange = true; bufferbot[0] = charge; counterbot++; @@ -275,7 +250,8 @@ Int_t CbmTrdModuleRecR::FindClusters() counterbot++; std::get<2>(botdigi) = d; } - if (ch == channel + ncols && !rowchange && trigger == CbmTrdDigi::kSelf && !std::get<1>(*FNit)) { + if (ch == channel + ncols && !rowchange && triggertype == CbmTrdDigi::eTriggerType::kSelf + && !std::get<1>(*FNit)) { rowchange = true; buffertop[0] = charge; countertop++; @@ -318,7 +294,7 @@ Int_t CbmTrdModuleRecR::FindClusters() // logical implementation of the trigger logic in the same row as the // main trigger - if (ch == lowcol - 1 && trigger == CbmTrdDigi::kSelf && !std::get<1>(*FNit)) { + if (ch == lowcol - 1 && triggertype == CbmTrdDigi::eTriggerType::kSelf && !std::get<1>(*FNit)) { cluster.push_back(std::make_pair(digiid, d)); lowcol = ch; dmain++; @@ -327,7 +303,7 @@ Int_t CbmTrdModuleRecR::FindClusters() std::cout << " time: " << newtime << " charge: " << charge << " col: " << col << " row: " << ch / ncols << " trigger: " << trigger << std::endl; } - if (ch == highcol + 1 && trigger == CbmTrdDigi::kSelf && !std::get<1>(*FNit)) { + if (ch == highcol + 1 && triggertype == CbmTrdDigi::eTriggerType::kSelf && !std::get<1>(*FNit)) { cluster.push_back(std::make_pair(digiid, d)); highcol = ch; dmain++; @@ -336,7 +312,8 @@ Int_t CbmTrdModuleRecR::FindClusters() std::cout << " time: " << newtime << " charge: " << charge << " col: " << col << " row: " << ch / ncols << " trigger: " << trigger << std::endl; } - if (ch == highcol + 1 && trigger == CbmTrdDigi::kNeighbor && !std::get<1>(*FNit) && !sealtopcol) { + if (ch == highcol + 1 && triggertype == CbmTrdDigi::eTriggerType::kNeighbor && !std::get<1>(*FNit) + && !sealtopcol) { cluster.push_back(std::make_pair(digiid, d)); sealtopcol = true; dmain++; @@ -345,7 +322,8 @@ Int_t CbmTrdModuleRecR::FindClusters() std::cout << " time: " << newtime << " charge: " << charge << " col: " << col << " row: " << ch / ncols << " trigger: " << trigger << std::endl; } - if (ch == lowcol - 1 && trigger == CbmTrdDigi::kNeighbor && !std::get<1>(*FNit) && !sealbotcol) { + if (ch == lowcol - 1 && triggertype == CbmTrdDigi::eTriggerType::kNeighbor && !std::get<1>(*FNit) + && !sealbotcol) { cluster.push_back(std::make_pair(digiid, d)); sealbotcol = true; dmain++; @@ -373,28 +351,28 @@ Int_t CbmTrdModuleRecR::FindClusters() dmain++; std::get<1>(*FNit) = true; } - if (rowchange && ch == lowrow - 1 && lowrow != channel && trigger == CbmTrdDigi::kSelf + if (rowchange && ch == lowrow - 1 && lowrow != channel && triggertype == CbmTrdDigi::eTriggerType::kSelf && !std::get<1>(*FNit)) { cluster.push_back(std::make_pair(digiid, d)); lowrow = ch; dmain++; std::get<1>(*FNit) = true; } - if (rowchange && ch == highrow + 1 && highrow != channel && trigger == CbmTrdDigi::kSelf + if (rowchange && ch == highrow + 1 && highrow != channel && triggertype == CbmTrdDigi::eTriggerType::kSelf && !std::get<1>(*FNit)) { cluster.push_back(std::make_pair(digiid, d)); highrow = ch; dmain++; std::get<1>(*FNit) = true; } - if (rowchange && ch == highrow + 1 && highrow != channel && trigger == CbmTrdDigi::kNeighbor + if (rowchange && ch == highrow + 1 && highrow != channel && triggertype == CbmTrdDigi::eTriggerType::kNeighbor && !std::get<1>(*FNit) && !sealtoprow) { cluster.push_back(std::make_pair(digiid, d)); sealtoprow = true; dmain++; std::get<1>(*FNit) = true; } - if (rowchange && ch == lowrow - 1 && lowrow != channel && trigger == CbmTrdDigi::kNeighbor + if (rowchange && ch == lowrow - 1 && lowrow != channel && triggertype == CbmTrdDigi::eTriggerType::kNeighbor && !std::get<1>(*FNit) && !sealbotrow) { cluster.push_back(std::make_pair(digiid, d)); sealbotrow = true; @@ -567,7 +545,7 @@ CbmTrdHit* CbmTrdModuleRecR::MakeHit(Int_t clusterId, const CbmTrdCluster* /*clu // return new ((*fHits)[nofHits]) CbmTrdHit(fModAddress, global, // cluster_pad_dposV, 0, clusterId,0, 0, - // totalCharge/1e6,time,Double_t(CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC))); + // totalCharge/1e6,time,Double_t(CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC))); return new ((*fHits)[nofHits]) CbmTrdHit(fModAddress, global, cluster_pad_dposV, 0, clusterId, totalCharge / 1e6, time, Double_t(8.5)); // TODO: move to parameter file diff --git a/reco/detectors/trd/CbmTrdModuleRecT.cxx b/reco/detectors/trd/CbmTrdModuleRecT.cxx index 9f261055c70716178f0fba48a2c6c864c8910bc6..b42345d770df47b377d2c33e01cf4f4d661d7e88 100644 --- a/reco/detectors/trd/CbmTrdModuleRecT.cxx +++ b/reco/detectors/trd/CbmTrdModuleRecT.cxx @@ -550,7 +550,8 @@ CbmTrdHit* CbmTrdModuleRecT::MakeHit(Int_t ic, const CbmTrdCluster* cl, std::vec // process time profile for (Int_t idx(1); idx <= n0; idx++) { - Double_t dtFEE = fgDT[0] * (vs[idx] - fgDT[1]) * (vs[idx] - fgDT[1]) / CbmTrdDigi::Clk(CbmTrdDigi::kFASP); + Double_t dtFEE = + fgDT[0] * (vs[idx] - fgDT[1]) * (vs[idx] - fgDT[1]) / CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP); if (vxe[idx] > 0) vx[idx] += dy / fDigiPar->GetPadSizeY(0); fgT->SetPoint(idx - 1, vx[idx], vt[idx] - dtFEE); } @@ -595,13 +596,13 @@ CbmTrdHit* CbmTrdModuleRecT::MakeHit(Int_t ic, const CbmTrdCluster* cl, std::vec cvs->SaveAs(Form("cl_%02d_A%d.gif", ic, ia)); } - Int_t nofHits = fHits->GetEntriesFast(); - CbmTrdHit* hit = - new ((*fHits)[nofHits]) CbmTrdHit(fModAddress, global, globalErr, - 0., // sxy chi, - ic, - e, // energy - CbmTrdDigi::Clk(CbmTrdDigi::kFASP) * (t0 + time) - tdrift + 30.29, edt); + Int_t nofHits = fHits->GetEntriesFast(); + CbmTrdHit* hit = new ((*fHits)[nofHits]) + CbmTrdHit(fModAddress, global, globalErr, + 0., // sxy chi, + ic, + e, // energy + CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP) * (t0 + time) - tdrift + 30.29, edt); hit->SetClassType(); hit->SetMaxType(tM); if (ovf) hit->SetOverFlow(); diff --git a/reco/detectors/trd/CbmTrdRecoLinkDef.h b/reco/detectors/trd/CbmTrdRecoLinkDef.h index ffebba4dbb20acdc746bcb5a0d958f170279c73a..70fa9bb3fb8ee6ae8e112bc7b41e81ee64d8bd5a 100644 --- a/reco/detectors/trd/CbmTrdRecoLinkDef.h +++ b/reco/detectors/trd/CbmTrdRecoLinkDef.h @@ -27,10 +27,25 @@ #pragma link C++ class CbmTrdRecoQa + ; #pragma link C++ class CbmTrdTracksPidQa + ; +#pragma link C++ class CbmRecoUnpackAlgo < CbmTrdDigi, CbmTrdRawMessageSpadic, std::pair < size_t, size_t>> + ; +#pragma link C++ class CbmRecoUnpackConfig < CbmTrdUnpackAlgoBaseR, CbmTrdDigi, CbmTrdRawMessageSpadic, \ + std::pair < size_t, size_t>> + ; + +#pragma link C++ class CbmTrdUnpackAlgoBaseR + ; +#pragma link C++ class CbmTrdUnpackAlgoR + ; +#pragma link C++ class CbmTrdUnpackAlgoLegacy2020R + ; +#pragma link C++ class CbmTrdUnpackConfig + ; +#pragma link C++ class CbmTrdUnpackMonitor + ; + #pragma link C++ class CbmTrdElectronsTrainAnn + ; #pragma link C++ class CbmTrdSetTracksPidWkn + ; #pragma link C++ class CbmTrdSetTracksPidModWkn + ; #pragma link C++ class CbmTrdSetTracksPidLike + ; #pragma link C++ class CbmTrdSetTracksPidANN + ; +#pragma link C++ class CbmTrdRawToDigiBaseR + ; +#pragma link C++ class CbmTrdRawToDigiMaxAdcR + ; +#pragma link C++ class CbmTrdRawToDigiFitR + ; +#pragma link C++ class CbmTrdRawToDigiLookUpCorrR + ; + #endif diff --git a/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiBaseR.cxx b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiBaseR.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8678e27bb2216355753aeee40f82bab902dd45d3 --- /dev/null +++ b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiBaseR.cxx @@ -0,0 +1,72 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +#include "CbmTrdRawToDigiBaseR.h" + +#include "CbmTrdDigi.h" +#include "CbmTrdRawMessageSpadic.h" + +#include <Rtypes.h> + + +//---- CbmTrdRawToDigiBaseR ---- +CbmTrdRawToDigiBaseR::CbmTrdRawToDigiBaseR() : TObject() {} + +// ---- GetBaseline ---- +Float_t CbmTrdRawToDigiBaseR::GetBaseline(const std::vector<std::int16_t>* samples) +{ + // The spadic 2.2 has a functionality that an average baseline can be written to the first sample. So first we have to check if this is active. + if (fSpadic->GetUseBaselineAvg()) return samples->at(0); + else { + Float_t baseline = 0.0; + auto itend = samples->begin() + fNrOfPresamples; + if (itend > samples->end()) itend = samples->end(); + for (auto isample = samples->begin(); isample < itend; isample++) { + baseline += *isample; + } + baseline /= fNrOfPresamples; + + return baseline; + } +} + +// ---- GetDigiTriggerType ---- +CbmTrdDigi::eTriggerType CbmTrdRawToDigiBaseR::GetDigiTriggerType(Spadic::eTriggerType tt) +{ + auto digiTriggerType = CbmTrdDigi::eTriggerType::kNTrg; + // Shift self trigger to digi selftrigger + // Shift neighbour trigger to digi neighbour + // Hide spadic kSandN in Self + switch (tt) { + case Spadic::eTriggerType::kGlobal: digiTriggerType = CbmTrdDigi::eTriggerType::kNTrg; break; + case Spadic::eTriggerType::kSelf: digiTriggerType = CbmTrdDigi::eTriggerType::kSelf; break; + case Spadic::eTriggerType::kNeigh: digiTriggerType = CbmTrdDigi::eTriggerType::kNeighbor; break; + case Spadic::eTriggerType::kSandN: digiTriggerType = CbmTrdDigi::eTriggerType::kSelf; break; + } + return digiTriggerType; +} + +// ---- MakeDigi ---- +std::unique_ptr<CbmTrdDigi> CbmTrdRawToDigiBaseR::MakeDigi(const std::vector<std::int16_t>* samples, Int_t padChNr, + Int_t uniqueModuleId, ULong64_t time, + CbmTrdDigi::eTriggerType triggerType, Int_t errClass) +{ + // Get the timeshift and set the member, which is required for some of the rtd methods + fCurrentTimeshift = GetBinTimeShift(samples); + + // In this case of CbmTrdRawToDigi GetCharge calls GetBinTimeshift, since the information is needed. The shift is stored in fCurrentTimeshift + // Hence, the order of charge and time assignement here makes a difference! + auto maxadc = GetMaxAdcValue(samples); + + // Get energy from maxadc value + auto energy = fSpadic->MaxAdcToEnergyCal(maxadc); + + // In simulation since we often start at time = 0 there is a non negligible chance that a time < 0 is extracted. Since, this is not allowed in the code we set it to 0 for these cases + time = time > fCurrentTimeshift ? time - fCurrentTimeshift : 0; + + auto digi = std::unique_ptr<CbmTrdDigi>(new CbmTrdDigi(padChNr, uniqueModuleId, energy, time, triggerType, errClass)); + return digi; +} + +ClassImp(CbmTrdRawToDigiBaseR) diff --git a/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiBaseR.h b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiBaseR.h new file mode 100644 index 0000000000000000000000000000000000000000..5bc582d4a8240c1e65dbecc335ac09454cd31562 --- /dev/null +++ b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiBaseR.h @@ -0,0 +1,154 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + + +/** + * @file CbmTrdRawToDigiBaseR.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Base class for extracting of information from raw signals to digi level + * @version 0.1 + * @date 2021-02-18 + * + * @copyright Copyright (c) 2021 + * + * Abstract base class for specified extraction methods of input charge and in-bin + * time-shifts. The actual methods are implemented in the derived classes. + * + */ + +#ifndef CBMTRDRAWTODIGIBASER_H +#define CBMTRDRAWTODIGIBASER_H + +#include "CbmTrdDigi.h" // for MakeDigi +#include "CbmTrdRawMessageSpadic.h" +#include "CbmTrdSpadic.h" + +#include <Rtypes.h> // for types and classdef +#include <RtypesCore.h> +#include <TObject.h> // for TObject inheritance + +#include <cstdint> +#include <memory> // for shared_ptr + +class CbmTrdRawToDigiBaseR : public TObject { +public: + /** + * @brief Construct a new CbmTrdRawToDigiBaseR object + * + */ + CbmTrdRawToDigiBaseR(); + + /** @brief Destructor **/ + virtual ~CbmTrdRawToDigiBaseR() { ; } + + + /** + * @brief Get digi from input values. Implemented in the derived classes. + * + * Get digi from the input values. The methods how a timeshift within the bins + * is estimated and how the input charge to the asic is extracted are + * implemented in the derived classes + * + * @param samples Adc samples + * @param padChNr Channel number of the pad + * @param uniqueModuleId unique Id of the module + * @param time Absolute time [ns]. + * @param triggerType SPADIC trigger type see CbmTrdTriggerType. + * @param errClass SPADIC signal error parametrization based on message type. + * @return std::shared_ptr<CbmTrdDigi> * + */ + + std::unique_ptr<CbmTrdDigi> MakeDigi(const std::vector<std::int16_t>* samples, Int_t padChNr, Int_t uniqueModuleId, + ULong64_t time, CbmTrdDigi::eTriggerType triggerType, Int_t errClass); + + /** + * @brief Get the Bin Time Shift value + * + * @param samples + * @return ULong64_t + */ + virtual ULong64_t GetBinTimeShift(const std::vector<std::int16_t>* samples) = 0; + + /** + * @brief Get the MaxAdc value + * + * @param samples + * @return Float_t + */ + virtual Float_t GetMaxAdcValue(const std::vector<std::int16_t>* samples) = 0; + + /** + * @brief Get the Baseline value + * + * The digi charge is an unsigned. Hence, we need to get the baseline to 0 + * + * @param samples + * @return Float_t + */ + Float_t GetBaseline(const std::vector<std::int16_t>* samples); + + /** + * @brief Get the spadic class + * + * @return std::shared_ptr<CbmTrdSpadic> + */ + std::shared_ptr<CbmTrdSpadic> GetSpadicObject() { return fSpadic; } + + /** + * @brief Get the Nr Of Presamples + * + * @return UInt_t + */ + UInt_t GetNrOfPresamples() { return fNrOfPresamples; } + + /** + * @brief Get the Digi Trigger Type from the raw message triggertype + * + * @param tt + * @return CbmTrdDigi::eTriggerType + */ + static CbmTrdDigi::eTriggerType GetDigiTriggerType(Spadic::eTriggerType tt); + + /** + * @brief Set the Nr Of Presamples + * + * @param value + */ + virtual void SetNrOfPresamples(UInt_t value) { fNrOfPresamples = value; } + + + /** + * @brief Set the spadic class + * + * @param spadic + */ + void SetSpadicObject(std::shared_ptr<CbmTrdSpadic> spadic) { fSpadic = spadic; } + +private: + /** + * @brief Copy constructor - not implemented! + * + */ + CbmTrdRawToDigiBaseR(const CbmTrdRawToDigiBaseR&) = delete; + +protected: + /** + * @brief Number of presamples before the signal starts (SPADIC default 2) + * + */ + UInt_t fNrOfPresamples = CbmTrdSpadic::GetNrOfPresamples(); + + /** + * @brief Bin timeshift for the current sample set in [ns] + * + */ + ULong64_t fCurrentTimeshift = 0; + + std::shared_ptr<CbmTrdSpadic> fSpadic = std::make_shared<CbmTrdSpadic>(); + +public: + ClassDef(CbmTrdRawToDigiBaseR, 2); +}; + +#endif diff --git a/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiFitR.cxx b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiFitR.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5b2fb4e0cc1098d68bc1db97a3beaed0882f37a9 --- /dev/null +++ b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiFitR.cxx @@ -0,0 +1,86 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +#include "CbmTrdRawToDigiFitR.h" + +#include "CbmTrdSpadic.h" + +#include <RtypesCore.h> +#include <TH1.h> + +#include <algorithm> + +//---- CbmTrdRawToDigiFitR ---- +CbmTrdRawToDigiFitR::CbmTrdRawToDigiFitR() : CbmTrdRawToDigiBaseR() { fixExtractionPars(); } + +// ---- GetCharge ---- +Float_t CbmTrdRawToDigiFitR::GetMaxAdcValue(const std::vector<std::int16_t>* /*samples*/) +{ + Double_t charge = fResponseFunc->GetParameter(static_cast<size_t>(CbmTrdSpadic::eResponsePars::kInputCharge)); + + return charge > 0 ? charge : 0; +} + +// ---- GetBinTimeShift ---- +ULong64_t CbmTrdRawToDigiFitR::GetBinTimeShift(const std::vector<std::int16_t>* samples) +{ + + fitResponse(samples); + + ULong64_t time = static_cast<ULong64_t>( + fResponseFunc->GetParameter(static_cast<size_t>(CbmTrdSpadic::eResponsePars::kBinTimeshift))); + return time; +} + +// ---- fixExtractionPars ---- +void CbmTrdRawToDigiFitR::fixExtractionPars() +{ + // Fix the parameters that are given by the spadic design + std::vector<CbmTrdSpadic::eResponsePars> pars = { + CbmTrdSpadic::eResponsePars::kNrPresamples, CbmTrdSpadic::eResponsePars::kShapingOrder, + CbmTrdSpadic::eResponsePars::kShapingTime, CbmTrdSpadic::eResponsePars::kChargeToMaxAdcCal}; + for (auto ipar : pars) + fixExtractionPar(ipar); + + // Limit the bin timeshift parameter to the clock cycle length + fResponseFunc->SetParLimits(static_cast<size_t>(CbmTrdSpadic::eResponsePars::kBinTimeshift), + (-CbmTrdSpadic::GetClockCycle() / 2.0), (CbmTrdSpadic::GetClockCycle()) / 2.0); +} + +// ---- fixExtractionPar ---- +void CbmTrdRawToDigiFitR::fixExtractionPar(CbmTrdSpadic::eResponsePars ipar) +{ + fResponseFunc->FixParameter(static_cast<size_t>(ipar), fResponseFunc->GetParameter(static_cast<size_t>(ipar))); +} + +// ---- fitResponse ---- +void CbmTrdRawToDigiFitR::fitResponse(const std::vector<std::int16_t>* samples) +{ + fResponseFunc->SetParameter(static_cast<size_t>(CbmTrdSpadic::eResponsePars::kInputCharge), 0.0); + fResponseFunc->SetParameter(static_cast<size_t>(CbmTrdSpadic::eResponsePars::kBinTimeshift), 0.0); + + TH1F hsignal("hsignal", "hsignal", samples->size(), 0, samples->size() - 1); + Int_t ibin = 0; + auto baseline = GetBaseline(samples); + for (auto isample : *samples) { + if (isample < fSpadic->GetClippingStart()) hsignal.SetBinContent(ibin, (isample - baseline)); + ibin++; + } + if (fFitRangeEnd > samples->size()) return; + // hsignal.Fit(fResponseFunc.get(), "SNQE I", "goff", fFitRangeStart, fFitRangeEnd); + + // Do not use + // E speed improvement + // M speed improvement + // I it does not make sense to integrate the bin, since, we use discretised values from the adc + + // Use + // C do not calculate chi2 to improve speed + // S store the result to a TFitResultsPtr + // Q we do want only minimal printout + // N do not store the graphics function + hsignal.Fit(fResponseFunc.get(), "SCNQ", "goff", fFitRangeStart, fFitRangeEnd); +} + +ClassImp(CbmTrdRawToDigiFitR) diff --git a/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiFitR.h b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiFitR.h new file mode 100644 index 0000000000000000000000000000000000000000..f6fd2a54dac5d02ef78bba9461b8b4352dbc94d1 --- /dev/null +++ b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiFitR.h @@ -0,0 +1,193 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +/** + * @file CbmTrdRawToDigiFitR.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Class for extracting information from raw signals to digi level + * @version 0.1 + * @date 2021-02-18 + * + * @copyright Copyright (c) 2021 + * + * This implemented a fit method to extract the input charge for a given + * Spadic response + * + */ + +#ifndef CbmTrdRawToDigiFitR_H +#define CbmTrdRawToDigiFitR_H + +#include "CbmTrdRawToDigiBaseR.h" + +#include <Rtypes.h> // for types and classdef +#include <RtypesCore.h> +#include <TObject.h> // for TObject inheritance + +#include <cstddef> +#include <cstdint> + +class CbmTrdRawToDigiFitR : public CbmTrdRawToDigiBaseR { + + +public: + /** @brief default Constructor with messages + **/ + CbmTrdRawToDigiFitR(); + + /** + * @brief Copy constructor - not implemented! + * + */ + CbmTrdRawToDigiFitR(const CbmTrdRawToDigiFitR&) = delete; + + /** + * @brief Assignment operator - not implemented! + * + * @return CbmTrdRawToDigiFitR + */ + CbmTrdRawToDigiFitR operator=(const CbmTrdRawToDigiFitR&); + + /** @brief Destructor **/ + virtual ~CbmTrdRawToDigiFitR() { ; } + + /** + * @brief Get the Bin Time Shift value + * + * @param samples + * @return ULong64_t + */ + ULong64_t GetBinTimeShift(const std::vector<std::int16_t>* /*samples*/); + + /** + * @brief Get the MaxAdc value + * + * @param samples + * @return Float_t + */ + Float_t GetMaxAdcValue(const std::vector<std::int16_t>* /*samples*/); + + /** + * @brief Get the Response Function object + * + * @return std::shared_ptr<TF1> + */ + std::shared_ptr<TF1> GetResponseFunc() { return fResponseFunc; } + + /** + * @brief Set the Nr Of Presamples + * + * @param value + */ + virtual void SetNrOfPresamples(UInt_t value) + { + fNrOfPresamples = value; + fResponseFunc->FixParameter(static_cast<size_t>(CbmTrdSpadic::eResponsePars::kNrPresamples), fNrOfPresamples); + } + + /** + * @brief Set the Shaping Order + * + * @param value + */ + virtual void SetShapingOrder(std::uint8_t value) + { + fResponseFunc->FixParameter(static_cast<size_t>(CbmTrdSpadic::eResponsePars::kShapingOrder), value); + } + + /** + * @brief Set and fix the Shaping Time + * + * @param value + */ + virtual void SetShapingTime(Double_t value) + { + fResponseFunc->FixParameter(static_cast<size_t>(CbmTrdSpadic::eResponsePars::kShapingTime), value); + } + + /** + * @brief Set and fix the Bin Timeshift value + * + * @param value + */ + virtual void SetBinTimeshift(Double_t value) + { + fResponseFunc->FixParameter(static_cast<size_t>(CbmTrdSpadic::eResponsePars::kBinTimeshift), value); + } + + /** + * @brief Set the Charge Calibration + * + * @param value + */ + virtual void SetChargeToMaxAdcCal(Double_t value) + { + fResponseFunc->FixParameter(static_cast<size_t>(CbmTrdSpadic::eResponsePars::kChargeToMaxAdcCal), value); + } + + /** + * @brief Set the Fit Range + * + * @param start + * @param end + */ + void SetFitRange(UInt_t start, UInt_t end) + { + fFitRangeStart = start; + fFitRangeEnd = end; + } + + +private: + /** + * @brief Perform the fit of the input signal + * + * @param samples + */ + void fitResponse(const std::vector<std::int16_t>* samples); + + /** + * @brief Response function + * + * Spadic obejct internal response function. + * Use the Getter to access the function and set/fix/etc. parameters. + * + */ + std::shared_ptr<TF1> fResponseFunc = CbmTrdSpadic::GetResponseFunc(); + + /** + * @brief Fix the extraction parameters to the default values + * + * Fix NrPresamples, ShapingOrder and ShapingTime to the default values + * Can still be overwritten by the setter functions + */ + void fixExtractionPars(); + + /** + * @brief Fix the passed extraction parameter (wrapper function) + * + */ + void fixExtractionPar(CbmTrdSpadic::eResponsePars ipar); + + // Data member + + /** + * @brief First sample that is used for the fit + * + */ + UInt_t fFitRangeStart = fNrOfPresamples; + + /** + * @brief Last sample that is used for the fit + * + */ + UInt_t fFitRangeEnd = 10; + + +protected: +public: + ClassDef(CbmTrdRawToDigiFitR, 2); +}; + +#endif diff --git a/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiLookUpCorrR.cxx b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiLookUpCorrR.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8b28be1481bc2fac1ca1c6c9ffe1316042352f17 --- /dev/null +++ b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiLookUpCorrR.cxx @@ -0,0 +1,199 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +#include "CbmTrdRawToDigiLookUpCorrR.h" + +#include "CbmTrdSpadic.h" + +#include <FairLogger.h> + +#include <RtypesCore.h> +#include <TFile.h> +#include <TH2.h> + +#include <algorithm> +#include <iostream> +#include <map> +#include <memory> +#include <stdexcept> +#include <utility> + +//---- CbmTrdRawToDigiLookUpCorrR ---- +CbmTrdRawToDigiLookUpCorrR::CbmTrdRawToDigiLookUpCorrR(std::string infile, eLookUpModes mode) + : CbmTrdRawToDigiBaseR() + , fLookUpMode(mode) + , fLookUpFilename(infile) +{ + prepareLookUpTables(infile); +} + +// ---- Init ---- +bool CbmTrdRawToDigiLookUpCorrR::Init(std::string infile) +{ + bool initOk = true; + + fLookUpFilename = infile.empty() ? fLookUpFilename : infile; + + fMaxAdcLookUpMap.clear(); + fTimeshiftLookUpMap.clear(); + + prepareLookUpTables(fLookUpFilename); + + // Could be used for checks within prepareLookUpTables + return initOk; +} + + +// ---- GetBinTimeShift ---- +ULong64_t CbmTrdRawToDigiLookUpCorrR::GetBinTimeShift(const std::vector<std::int16_t>* samples) +{ + Int_t baseline = GetBaseline(samples); + fcorrFirstSample = samples->at(fFirstLookUpSamplePos) - baseline; + fcorrFirstSample = fcorrFirstSample > fSpadic->GetClippingStart() ? fSpadic->GetClippingStart() : fcorrFirstSample; + fcorrFirstSample = fcorrFirstSample < 0 ? 0 : fcorrFirstSample; + + fcorrSecondSample = samples->at(fSecondLookUpSamplePos) - baseline; + fcorrSecondSample = fcorrSecondSample > fSpadic->GetClippingStart() ? fSpadic->GetClippingStart() : fcorrSecondSample; + fcorrSecondSample = fcorrSecondSample < 0 ? 0 : fcorrSecondSample; + + auto timeshift = fTimeshiftLookUpMap[fcorrFirstSample][fcorrSecondSample]; + + return timeshift; +} + +// --- GetCharge ---- +Float_t CbmTrdRawToDigiLookUpCorrR::GetMaxAdcValue(const std::vector<std::int16_t>* /* samples*/) +{ + Double_t charge = 0.0; + + charge = fMaxAdcLookUpMap[fCurrentTimeshift][fcorrSecondSample]; + + + // Remark: Due to the fact, that we store the charge UInt_t in the Digi values below 0 are not allowed. + // In this case the above only appears if the baseline fluctuated above all values in the applied peaking range. This can only happen for forced neighbor triggers with a deposited charged that can not be separated from the baseline. + return charge; +} + +// ---- prepareLookUpTables ---- +void CbmTrdRawToDigiLookUpCorrR::prepareLookUpTables(std::string infile) +{ + switch (fLookUpMode) { + case eLookUpModes::kTwoSamplesDynamicAnalytic: createAnalyticLookUpTables(); break; + case eLookUpModes::kTwoSamplesFileInput: + if (infile.empty()) + LOG(fatal) << "CbmTrdRawToDigiLookUpCorrR::prepareLookUpTables: Look up mode that reqiures an input file " + "requested with empty infile name string!"; + loadLookUpTables(infile); + break; + } +} + +// ---- loadLookUpTables ---- +void CbmTrdRawToDigiLookUpCorrR::loadLookUpTables(std::string infile) +{ + auto oldFile = gFile; + + TFile file(infile.data(), "READ"); + if (file.IsOpen()) { + std::string hname = Form("Timeshift_Map_Fst%d_Snd%d", fFirstLookUpSamplePos, fSecondLookUpSamplePos); + TH2* hTimeshiftMap = (TH2*) file.Get(hname.data()); + if (!hTimeshiftMap) + LOG(fatal) << "CbmTrdRawToDigiLookUpCorrR::loadLookUpTables: Look up mode that reqiures Timeshift Map " + "histogram requested, but the map " + << hname << " was not found in the given file(" << infile << ")!"; + hname = Form("MaxAdc_Map_Fst%d_Snd%d", fFirstLookUpSamplePos, fSecondLookUpSamplePos); + TH2* hMaxAdcMap = (TH2*) file.Get(hname.data()); + if (!hMaxAdcMap) + LOG(fatal) << "CbmTrdRawToDigiLookUpCorrR::loadLookUpTables: Look up mode that reqiures MaxAdc Map " + "histogram requested, but the map " + << hname << " was not found in the given file(" << infile << ")!"; + + // TH2* hMaxAdcMap = (TH2*) file.Get("MAX ADC"); + // TH2* hAsymMap = (TH2*) file.Get("ASYM MAP"); + + if (hMaxAdcMap && hTimeshiftMap) { + auto h = hMaxAdcMap; + for (Int_t ibinx = 1; ibinx <= h->GetNbinsX(); ibinx++) { + for (Int_t ibiny = 1; ibiny <= h->GetNbinsY(); ibiny++) { + fMaxAdcLookUpMap[h->GetXaxis()->GetBinCenter(ibinx)][h->GetYaxis()->GetBinCenter(ibiny)] = + h->GetBinContent(ibinx, ibiny); + } + } + + h = hTimeshiftMap; + for (Int_t ibinx = 1; ibinx <= h->GetNbinsX(); ibinx++) { + for (Int_t ibiny = 1; ibiny <= h->GetNbinsY(); ibiny++) { + fTimeshiftLookUpMap[h->GetXaxis()->GetBinCenter(ibinx)][h->GetYaxis()->GetBinCenter(ibiny)] = + h->GetBinContent(ibinx, ibiny); + } + } + } + file.Close(); + } + else { + LOG(fatal) << "CbmTrdRawToDigiLookUpCorrR::loadLookUpTables: Look up mode that reqiures an input file " + "requested with a wrong file path! Filepath = " + << infile; + } + gFile = oldFile; +} + +// ---- loadLookUpTables ---- +void CbmTrdRawToDigiLookUpCorrR::createAnalyticLookUpTables() +{ + UInt_t chargeFirstSample = 0; + UInt_t chargeSecondSample = 0; + + for (Int_t timeshift = 0; timeshift < fSpadic->GetClockCycle(); timeshift += 1) { + fSpadic->SetParameter(CbmTrdSpadic::eResponsePars::kBinTimeshift, timeshift); + for (UInt_t maxAdc = 1; maxAdc < fSpadic->GetDynamicRange() * 2; maxAdc++) { + // Set the max adc related input charge for the spadic response + fSpadic->SetParameter(CbmTrdSpadic::eResponsePars::kInputCharge, maxAdc); + // Get the response for the sample positions + chargeFirstSample = fSpadic->Response(fFirstLookUpSamplePos); + // second sample position + chargeSecondSample = fSpadic->Response(fSecondLookUpSamplePos); + auto innerpair = std::make_pair(chargeSecondSample, timeshift); + auto innermap = fTimeshiftLookUpMap.find(chargeFirstSample); + if (innermap != fTimeshiftLookUpMap.end()) { innermap->second.emplace(innerpair); } + else { + std::map<UInt_t, ULong64_t> newinnermap = {}; + newinnermap.emplace(innerpair); + auto outerpair = std::make_pair(chargeFirstSample, newinnermap); + fTimeshiftLookUpMap.emplace(outerpair); + } + + + // fTimeshiftLookUpMap[chargeFirstSample][chargeSecondSample] = timeshift; + fMaxAdcLookUpMap[timeshift][chargeSecondSample] = maxAdc; + } + } + ULong64_t timeshift = 0; + std::vector<ULong64_t> timeshiftsvec = {}; + std::vector<UInt_t> emptyChargeVec = {}; + + // Fill up empty bins in the look up. Due to several effects, e.g. noise, real signals can produce other combinations of first and second sample charges than the pure analytical approach. Hence, we the look up also to deliver values for those combinations. + // Fill up the map, we assume here that the shift does behave steadily, i.e. empty bins after a 62 ns bin will be filled with 62 ns and vise versa empty bins after 0 ns bin will be filled with 0 ns. + for (auto& innermap : fTimeshiftLookUpMap) { + for (UInt_t secondsampleCharge = 0; secondsampleCharge < fSpadic->GetDynamicRange(); secondsampleCharge++) { + if (innermap.second.find(secondsampleCharge) == innermap.second.end()) + emptyChargeVec.emplace_back(secondsampleCharge); + else { + timeshift = innermap.second.find(secondsampleCharge)->second; + for (auto emptycharge : emptyChargeVec) { + auto pair = std::make_pair(emptycharge, timeshift); + innermap.second.emplace(pair); + } + emptyChargeVec.clear(); + } + } + for (auto emptycharge : emptyChargeVec) { + auto pair = std::make_pair(emptycharge, timeshift); + innermap.second.emplace(pair); + } + emptyChargeVec.clear(); + } +} + +ClassImp(CbmTrdRawToDigiLookUpCorrR) diff --git a/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiLookUpCorrR.h b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiLookUpCorrR.h new file mode 100644 index 0000000000000000000000000000000000000000..b09ec67a170793a8c07295a965810fd029c431ae --- /dev/null +++ b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiLookUpCorrR.h @@ -0,0 +1,260 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +/** + * @file CbmTrdRawToDigiLookUpCorrR.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Class for extracting information from raw signals to digi level + * @version 0.1 + * @date 2021-02-18 + * + * @copyright Copyright (c) 2021 + * + * This implements a look up table based method to extract the input charge + * for a given Spadic response. The look up is based on the correlation of two + * selected samples. + * It is the legacy version of the original CbmTrdRawToDigi class. + * + */ + +#ifndef CbmTrdRawToDigiLookUpCorrR_H +#define CbmTrdRawToDigiLookUpCorrR_H + +#include "CbmTrdRawToDigiBaseR.h" + +#include <Rtypes.h> // for types and classdef +#include <RtypesCore.h> +#include <TH2.h> +#include <TObject.h> // for TObject inheritance + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <string> + +class CbmTrdRawToDigiLookUpCorrR : public CbmTrdRawToDigiBaseR { + + +public: + enum class eLookUpModes : size_t + { + /** + * @brief Look up mode based on two samples and statistical filling. + * Look up mode based on two samples with maps based on statistical extraction + * stored in the passed infile. + * + */ + kTwoSamplesFileInput = 0, + + /** + * @brief Look up mode based on two samples and analytical on the fly filling. + * Look up mode based on two samples with maps based on analytical filling + * created dynamically when this mode is selected. + */ + kTwoSamplesDynamicAnalytic + }; + + /** + * @brief Construct a new CbmTrdRawToDigiLookUpCorrR + * + * @param infile + */ + CbmTrdRawToDigiLookUpCorrR(std::string infile = "", eLookUpModes mode = eLookUpModes::kTwoSamplesFileInput); + + /** + * @brief Copy constructor - not implemented! + * + */ + CbmTrdRawToDigiLookUpCorrR(const CbmTrdRawToDigiLookUpCorrR&) = delete; + + /** + * @brief Assignment operator - not implemented! + * + * @return CbmTrdRawToDigiLookUpCorrR + */ + CbmTrdRawToDigiLookUpCorrR operator=(const CbmTrdRawToDigiLookUpCorrR&); + + /** @brief Destructor **/ + virtual ~CbmTrdRawToDigiLookUpCorrR() { ; } + + /** + * @brief Initialise the method after all settings have been passed + * + * This initialises the method if none default settings are used. + * If it is not call after a change of settings, the defaults will still be used! + * + * @param infile + * @return true + * @return false + */ + bool Init(std::string infile = ""); + + /** + * @brief Create the Debug Histo File + * If called, the debug histos are written to a file which is written to disk. + */ + void CreateDebugHistoFile(); + + /** + * @brief Get the Bin Time Shift value + * + * Extract the bin time shift from the look up tables. The value is also stored + * in fCurrentTimeshift. + * @param samples + * @return ULong64_t + */ + ULong64_t GetBinTimeShift(const std::vector<std::int16_t>* samples); + + /** + * @brief Get the MaxAdc value + * + * @param samples + * @return Float_t + */ + Float_t GetMaxAdcValue(const std::vector<std::int16_t>* samples); + + /** + * @brief Get the defined Look Up Mode + * + * @return eLookUpModes + */ + eLookUpModes GetLookUpMode() { return fLookUpMode; } + + /** + * @brief Get the First Sample Pos + * + * @return UInt_t + */ + UInt_t GetFirstSamplePos() { return fFirstLookUpSamplePos; } + + /** + * @brief Get the Second Sample Pos + * + * @return UInt_t + */ + UInt_t GetSecondSamplePos() { return fSecondLookUpSamplePos; } + + /** + * @brief Set the Look Up Mode + * + * @param value + */ + void SetLookUpMode(eLookUpModes value, std::string infile = "") + { + fLookUpMode = value; + prepareLookUpTables(infile); + } + + /** + * @brief Set the position of the first look up sample + * + * @param value + */ + void SetFirstSamplePos(UInt_t value) { fFirstLookUpSamplePos = value; } + + /** + * @brief Set the position of the second look up sample + * + * @param value + */ + void SetSecondSamplePos(UInt_t value) { fSecondLookUpSamplePos = value; } + + /** + * @brief Set the Nr Of Presamples also resets the look up sample positions + * + * @param value + */ + virtual void SetNrOfPresamples(UInt_t value) + { + fNrOfPresamples = value; + SetFirstSamplePos(value + 1); + SetSecondSamplePos(value + 2); + } + + +private: +protected: + /** + * @brief Prepare the look up tables for the used look up mode + * + * @param infile + */ + void prepareLookUpTables(std::string infile); + + /** + * @brief Load the look up tables from the given file + * + * @param infile + */ + void loadLookUpTables(std::string infile); + + /** + * @brief Create a Analytical Look Up Tables + * + * Two of three look up modes are based on dynamically created look up tables + * based on analytical approaches. + */ + void createAnalyticLookUpTables(); + + /** + * @brief Used look up mode + * + */ + eLookUpModes fLookUpMode; + + + /** + * @brief Look up map for the max adc values for + * Keys correspond to charge[fCurrentTimeshift], + * charge[fSecondLookUpSamplePos] and the mapped value is the input charge in + * MIP calibrated max adc units + */ + std::map<Int_t, std::map<Int_t, Float_t>> fMaxAdcLookUpMap = {}; + + /** + * @brief Look up map for the bin time shift value + * Keys correspond to charge[fFirstLookUpSamplePos], + * charge[fSecondLookUpSamplePos] and the mapped value is the timeshift + */ + std::map<UInt_t, std::map<UInt_t, ULong64_t>> fTimeshiftLookUpMap = {}; + + /** + * @brief Position of the first sample used in the look up tables + * Default corresponds to the value used in the look ups in the parameters + * repository + */ + UInt_t fFirstLookUpSamplePos = fNrOfPresamples + 1; + + /** + * @brief Position of the second sample used in the look up tables + * Default corresponds to the value used in the look ups in the parameters + * repository + */ + // UInt_t fSecondLookUpSamplePos = fNrOfPresamples + 2; + UInt_t fSecondLookUpSamplePos = fNrOfPresamples + 5; + + /** + * @brief Baseline corrected sample value of the first used sample + * + */ + Int_t fcorrFirstSample = 0; + + /** + * @brief Baseline corrected sample value of the second used sample + * + */ + Int_t fcorrSecondSample = 0; + + /** + * @brief File name where the look up histos are stored + * + */ + std::string fLookUpFilename = ""; + + +public: + ClassDef(CbmTrdRawToDigiLookUpCorrR, 2); +}; + +#endif diff --git a/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiMaxAdcR.cxx b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiMaxAdcR.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b366b3f1c803c653b5d880d2acc383d4047cb596 --- /dev/null +++ b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiMaxAdcR.cxx @@ -0,0 +1,50 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +#include "CbmTrdRawToDigiMaxAdcR.h" + +#include <FairLogger.h> + +#include <algorithm> +#include <iostream> +#include <iterator> + +//---- CbmTrdRawToDigiMaxAdcR ---- +CbmTrdRawToDigiMaxAdcR::CbmTrdRawToDigiMaxAdcR() : CbmTrdRawToDigiBaseR() {} + +// --- GetCharge ---- +Float_t CbmTrdRawToDigiMaxAdcR::GetMaxAdcValue(const std::vector<std::int16_t>* samples) +{ + // Safety for corrupted input samples + if (samples->size() < fPeakingBinMin) { + LOG(error) << "CbmTrdRawToDigiMaxAdcR::GetCharge samples.size() = " << samples->size() + << " fPeakingBinMin = " << fPeakingBinMin; + return 0; + } + + // The signal should peak at the shaping time. + // The corresponding sample is the peaking time divided by the sample length. + auto itbegin = std::next(samples->begin(), fPeakingBinMin); + + // Check if the expected maximum position of the peaking bin exceeds the size of the vector + auto nsamples = samples->size(); + auto peakingBinMax = (nsamples - 1) > fPeakingBinMax ? fPeakingBinMax : nsamples; + auto itend = std::next(samples->begin(), peakingBinMax); + + // Get the maximum element + auto itmax = std::max_element(itbegin, itend); + + Float_t charge = static_cast<Float_t>(*itmax); + + // Correct for the baseline + charge -= GetBaseline(samples); + + + // Remark: Due to the fact, that we store the charge UInt_t in the Digi values below 0 are not allowed. + // In this case the above only appears if the baseline fluctuated above all values in the applied peaking range. This can only happen for forced neighbor triggers with a deposited charged that can not be separated from the baseline. + return charge > 0 ? charge : 0; +} + + +ClassImp(CbmTrdRawToDigiMaxAdcR) diff --git a/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiMaxAdcR.h b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiMaxAdcR.h new file mode 100644 index 0000000000000000000000000000000000000000..2268b22b6fe4e0de427b2cc54bb84d240544ef19 --- /dev/null +++ b/reco/detectors/trd/rawToDigiMethods/CbmTrdRawToDigiMaxAdcR.h @@ -0,0 +1,109 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +/** + * @file CbmTrdRawToDigiMaxAdcR.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Class for extracting information from raw signals to digi level + * @version 0.1 + * @date 2021-02-18 + * + * @copyright Copyright (c) 2021 + * + * This implemented the max adc method to extract the input charge for a given + * Spadic response + * + */ + +#ifndef CbmTrdRawToDigiMaxAdcR_H +#define CbmTrdRawToDigiMaxAdcR_H + +#include "CbmTrdDigi.h" // for MakeDigi +#include "CbmTrdRawToDigiBaseR.h" + +#include <Rtypes.h> // for types and classdef +#include <RtypesCore.h> +#include <TObject.h> // for TObject inheritance + +#include <cstddef> + +class CbmTrdRawToDigiMaxAdcR : public CbmTrdRawToDigiBaseR { + + +public: + /** @brief default Constructor with messages + **/ + CbmTrdRawToDigiMaxAdcR(); + + /** + * @brief Copy constructor - not implemented! + * + */ + CbmTrdRawToDigiMaxAdcR(const CbmTrdRawToDigiMaxAdcR&) = delete; + + /** + * @brief Assignment operator - not implemented! + * + * @return CbmTrdRawToDigiMaxAdcR + */ + CbmTrdRawToDigiMaxAdcR operator=(const CbmTrdRawToDigiMaxAdcR&); + + /** @brief Destructor **/ + virtual ~CbmTrdRawToDigiMaxAdcR() { ; } + + /** + * @brief Get the Bin Time Shift value + * + * No method developed up to now to extract a time-shift together with the max + * adc charge esxtraction method. + * @param samples + * @return ULong64_t + */ + ULong64_t GetBinTimeShift(const std::vector<std::int16_t>* /*samples*/) { return 0; }; + + /** + * @brief Get the MaxAdc value + * + * @param samples + * @return Float_t + */ + Float_t GetMaxAdcValue(const std::vector<std::int16_t>* samples); + + /** + * @brief Set the peaking range in sample numbers + * + * Use this to define a peaking range for the max adc extraction. + * Presamples have to be included into the values! + * @param value + */ + void SetPeakingRange(size_t min, size_t max) + { + fPeakingBinMin = min; + fPeakingBinMax = max; + } + + +private: + /** + * @brief First sample to look for the max adc + * + */ + size_t fPeakingBinMin = fNrOfPresamples; + + /** + * @brief Last sample to look for the max adc + * Default value is set based on the Shaping time + 5 samples safety margin. + * @remark the peaking time strongly depends on the input signal. Effective range of + * the shaping time is between 120 and 240 ns. + */ + size_t fPeakingBinMax = + static_cast<size_t>(CbmTrdSpadic::GetShapingTime() / CbmTrdSpadic::GetClockCycle() + fNrOfPresamples + 5); + + +protected: +public: + ClassDef(CbmTrdRawToDigiMaxAdcR, 2); +}; + +#endif diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackAlgoBaseR.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoBaseR.cxx new file mode 100644 index 0000000000000000000000000000000000000000..eaac0c875dd3169f369f6f96e5b83324730386cc --- /dev/null +++ b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoBaseR.cxx @@ -0,0 +1,157 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +#include "CbmTrdUnpackAlgoBaseR.h" + +#include "CbmMcbm2020TrdTshiftPar.h" +#include "CbmTrdDigi.h" +#include "CbmTrdHardwareSetupR.h" // for channel address parameters +#include "CbmTrdParSetAsic.h" + +#include <FairParGenericSet.h> +#include <FairTask.h> +#include <Logger.h> + +#include <Rtypes.h> +#include <RtypesCore.h> + + +CbmTrdUnpackAlgoBaseR::CbmTrdUnpackAlgoBaseR(std::string name) : CbmRecoUnpackAlgo(fgkFlesSubsystemIdTrdR, name) {} + +CbmTrdUnpackAlgoBaseR::~CbmTrdUnpackAlgoBaseR() {} + +// ---- digestOutput ---- +void CbmTrdUnpackAlgoBaseR::digestOutput(std::unique_ptr<CbmTrdDigi> digi, CbmTrdRawMessageSpadic raw) +{ + ++fNrCreatedDigis; + + // If requested lets monitor something + if (fMonitor) { fMonitor->FillHistos(digi.get(), &raw); } + + // Save raw message: + if (fOptOutAVec) { fOptOutAVec->emplace_back(raw); } + + + // Save the digi + fOutputVec.emplace_back(*std::move(digi)); +} + +// ---- getAsicAddress ---- +std::uint32_t CbmTrdUnpackAlgoBaseR::getAsicAddress(std::uint32_t criid, std::uint32_t crobid, std::uint32_t elinkid) +{ + size_t spadicHwAddress = 0; + spadicHwAddress = elinkid + (CbmTrdParAsic::kCriIdPosition * criid) + (CbmTrdParAsic::kCrobIdPosition * crobid); + auto mapIt = fSpadicAddressMap.find(spadicHwAddress); // check if asic exists + if (mapIt == fSpadicAddressMap.end()) { + LOG(info) << fName + << "::makeDigi - No asic address " + "found for Spadic hardware address " + << spadicHwAddress; + return 0; + } + + return mapIt->second; +} + +// ---- getAsicAddress ---- +std::uint32_t CbmTrdUnpackAlgoBaseR::getChannelId(std::uint32_t asicaddress, std::uint32_t elinkid, + std::uint32_t elinkchannelid) +{ + // GetChannelId per eLink add NSPADICCH / 2 to the second(first) eLink in the case we start with odd(even) eLinks, since, our mapping is based on odd eLinks + auto asicChannelId = + (elinkid % 2) == fIsFirstChannelsElinkEven ? elinkchannelid : elinkchannelid + (CbmTrdSpadic::GetNrChannels() / 2); + + auto channelId = (fAsicChannelMap.find(asicaddress))->second.at(asicChannelId); + + return channelId; +} + +// ---- initParSet(FairParGenericSet* parset) ---- +Bool_t CbmTrdUnpackAlgoBaseR::initParSet(FairParGenericSet* parset) +{ + LOG(info) << fName << "::initParSet - for container " << parset->ClassName(); + if (parset->IsA() == CbmTrdParSetAsic::Class()) return initParSet(static_cast<CbmTrdParSetAsic*>(parset)); + + if (parset->IsA() == CbmTrdParSetDigi::Class()) return initParSet(static_cast<CbmTrdParSetDigi*>(parset)); + + if (parset->IsA() == CbmMcbm2020TrdTshiftPar::Class()) + return initParSet(static_cast<CbmMcbm2020TrdTshiftPar*>(parset)); + + // If we do not know the derived ParSet class we return false + LOG(error) + << fName << "::initParSet - for container " << parset->ClassName() + << " failed, since CbmTrdUnpackAlgoBaseR::initParSet() does not know the derived ParSet and what to do with it!"; + return kFALSE; +} + +// ---- initParSet(CbmTrdParSetAsic* parset) ---- +Bool_t CbmTrdUnpackAlgoBaseR::initParSet(CbmTrdParSetAsic* parset) +{ + LOG(debug) << fName << "::initParSetAsic - "; + CbmTrdHardwareSetupR hwSetup; + fSpadicAddressMap = hwSetup.CreateHwToSwAsicAddressTranslatorMap(parset); + if (fSpadicAddressMap.empty()) { + LOG(error) << fName << "::initParSetAsic - SpadicAddressMap creation failed, the map is empty"; + return kFALSE; + } + // at least check that the loaded map is not empty + + fAsicChannelMap = hwSetup.CreateAsicChannelMap(parset); + if (fAsicChannelMap.empty()) { + LOG(error) << fName << "::initParSetAsic - AsicChannelMap creation failed, the map is empty"; + return kFALSE; + } + + + LOG(info) << fName << "::initParSetAsic - Successfully initialized Spadic hardware address map"; + + return kTRUE; +} + +// ---- initParSet(CbmTrdParSetDigi* parset) ---- +Bool_t CbmTrdUnpackAlgoBaseR::initParSet(CbmTrdParSetDigi* parset) +{ + Bool_t initOk = kTRUE; + // The monitor needs the ParSetDigi to extract module informations and other stuff + if (fMonitor) { + LOG(info) << fName << "::initParSet(CbmTrdParSetDigi) - Forwarding ParSetDigi to the monitor"; + initOk &= fMonitor->Init(parset); + } + + return initOk; +} + +// ---- initParSet(CbmMcbm2020TrdTshiftPar* parset) ---- +Bool_t CbmTrdUnpackAlgoBaseR::initParSet(CbmMcbm2020TrdTshiftPar* parset) +{ + auto maptimeshifts = parset->GetTimeshiftsMap(); + fTimeshiftsMap.clear(); + fTimeshiftsMap.insert(maptimeshifts->begin(), maptimeshifts->end()); + LOG(info) << fName << "::initParSetTimeshift2020() - Parsing timeshift correction map to unpacker algo"; + + return (!fTimeshiftsMap.empty()); +} + +// ---- initR ---- +Bool_t CbmTrdUnpackAlgoBaseR::initR() +{ + auto initOk = kTRUE; + // Check if we have already a Spadic object. If not check if we have a raw to digi object, it has by default a Spadic object. If we do not have a rtd object we create a default spadic object on our own. + if (!fSpadic) { + // First we check if there is a spadic definition stored in the raw to digi method + if (fRTDMethod) fSpadic = fRTDMethod->GetSpadicObject(); + // If we still do not have spadic, we create it on our own + if (!fSpadic) fSpadic = std::make_shared<CbmTrdSpadic>(); + } + if (!fSpadic) { + LOG(error) << fName + << "::initR - We are missing a CbmTrdSpadic object, to extract the basic spadic functionalities!"; + initOk &= kFALSE; + } + if (fMonitor) fMonitor->SetSpadicObject(fSpadic); + + return initOk; +} + +ClassImp(CbmTrdUnpackAlgoBaseR) diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackAlgoBaseR.h b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoBaseR.h new file mode 100644 index 0000000000000000000000000000000000000000..f5dfc2e6274e6c65ca23dd9b384c6c66c39ee225 --- /dev/null +++ b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoBaseR.h @@ -0,0 +1,232 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +/** + * @file CbmTrdUnpackAlgoBaseR.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Baseclass for the TrdR unpacker algorithms + * @version 0.1 + * @date 2021-04-21 + * + * @copyright Copyright (c) 2021 + * + * This is the base class for the algorithmic part of the tsa data unpacking + * processes of the CbmTrd. + * The actual translation from tsa to digi happens in the derived classes. + * + * +*/ + +#ifndef CbmTrdUnpackAlgoBaseR_H +#define CbmTrdUnpackAlgoBaseR_H + +#include "CbmMcbm2020TrdTshiftPar.h" +#include "CbmRecoUnpackAlgo.tmpl" +#include "CbmTrdDigi.h" +#include "CbmTrdParSetAsic.h" +#include "CbmTrdRawMessageSpadic.h" +#include "CbmTrdRawToDigiBaseR.h" +#include "CbmTrdSpadic.h" +#include "CbmTrdUnpackMonitor.h" + +#include "Timeslice.hpp" // timeslice + +#include <FairTask.h> // for InitStatus + +#include <Rtypes.h> // for types +#include <RtypesCore.h> + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <utility> + +class CbmTrdUnpackAlgoBaseR : public CbmRecoUnpackAlgo<CbmTrdDigi, CbmTrdRawMessageSpadic, std::pair<size_t, size_t>> { +public: + /** @brief Create the Cbm Trd Unpack AlgoBase object */ + CbmTrdUnpackAlgoBaseR(std::string name); + + /** @brief Destroy the Cbm Trd Unpack Task object */ + virtual ~CbmTrdUnpackAlgoBaseR(); + + /** @brief Copy constructor - not implemented **/ + CbmTrdUnpackAlgoBaseR(const CbmTrdUnpackAlgoBaseR&) = delete; + + /** @brief Assignment operator - not implemented **/ + CbmTrdUnpackAlgoBaseR& operator=(const CbmTrdUnpackAlgoBaseR&) = delete; + + // Setters + /** @brief Set a predefined monitor @param monitor predefined unpacking monitor */ + void SetMonitor(std::shared_ptr<CbmTrdUnpackMonitor> monitor) { fMonitor = monitor; } + + /** + * @brief Set the Raw To Digi Method + * + * @param value + */ + void SetRawToDigiMethod(std::shared_ptr<CbmTrdRawToDigiBaseR> value) { fRTDMethod = value; } + + /** + * @brief Set the Spadic Object + * + * @param value + */ + void SetSpadicObject(std::shared_ptr<CbmTrdSpadic> value) { fSpadic = value; } + +protected: + /** + * @brief Handle the output created by the explicit algorithms. E.g. write to output vectors. + * + * @param digi + * @param raw + */ + void digestOutput(std::unique_ptr<CbmTrdDigi> digi, CbmTrdRawMessageSpadic raw); + + /** @brief Finish function for this algorithm base clase */ + void finish() + { + finishDerived(); + // Finish the monitor if we have one + if (fMonitor) fMonitor->Finish(); + } + + /** @brief Function that allows special calls during Finish in the derived algos */ + virtual void finishDerived() = 0; + + /** + * @brief Get the Asic Address (CbmAddress scheme) for the given hardware Ids + * + * @param criid + * @param crobid + * @param elinkid + * @return std::uint32_t + */ + virtual std::uint32_t getAsicAddress(std::uint32_t criid, std::uint32_t crobid, std::uint32_t elinkid); + + /** + * @brief Get the Channel Id (CbmAddress scheme) for the given hardware Ids + * + * @param asicaddress + * @param elinkid + * @param elinkchannelid + * @return std::uint32_t + */ + std::uint32_t getChannelId(std::uint32_t asicaddress, std::uint32_t elinkid, std::uint32_t elinkchannelid); + + /** + * @brief Additional initialisation function for all BaseR derived algorithms. + * + * @return Bool_t initOk + */ + virtual Bool_t init() { return initR(); } + + /** + * @brief Additional initialisation function for all BaseR derived algorithms. + * + * @return Bool_t initOk + */ + virtual Bool_t initR(); + + // Initialise par set, the base function handles the casting to distribute the pointers to their explicit functions + + /** + * @brief Handles the distribution of the hidden derived classes to their explicit functions. + * + * @param parset + * @return Bool_t initOk + */ + Bool_t initParSet(FairParGenericSet* parset); + + /** + * @brief Transfer parameters from ParSetAsic container to members. + * + * Currently we mainly transfer here the addressing, other parameters are yet to come. + * + * @param parset + * @return Bool_t initOk + */ + Bool_t initParSet(CbmTrdParSetAsic* parset); + + /** + * @brief Transfer parameters from ParSetDigi container to members. + * + * The monitor needs this to extract module informations, e.g. ncols and nrows. + * + * @param parset + * @return Bool_t initOk + */ + Bool_t initParSet(CbmTrdParSetDigi* parset); + + /** + * @brief Transfer parameters from CbmMcbm2020TrdTshiftPar container to members. + * + * These are mCBM 2020 specific parameters needed to correct in run timeshifts. + * + * @param parset + * @return Bool_t initOk + */ + Bool_t initParSet(CbmMcbm2020TrdTshiftPar* parset); + + /** + * @brief Pointer to the RawMsg vector connected to the framework, setted from the task/device + * @remark This could be templated if we want to use this class as reference for all systems + */ + std::vector<CbmTrdRawMessageSpadic>* fOutRawSpadicVec = nullptr; + + /** + * @brief Pointer to the Spadic info message vector connected to the framework, setted from the task/device + * @remark This could be templated if we want to use this class as reference for all systems + */ + std::vector<std::pair<size_t, size_t>>* fOutInfoSpadicVec = nullptr; + + // Monitoring + /** @brief Potential (online) monitor for the unpacking process */ + std::shared_ptr<CbmTrdUnpackMonitor> fMonitor = nullptr; + + // Parameter storage members + /** @brief Spadic software reprensentation object */ + std::shared_ptr<CbmTrdSpadic> fSpadic = nullptr; + + /** @brief raw to digi extraction method, set in the task */ + std::shared_ptr<CbmTrdRawToDigiBaseR> fRTDMethod = nullptr; + + /** @brief Map to retrieve asic address from CriId/CrobId/ElinkId (see CbmTrdHardwareSetupR) */ + std::map<size_t, Int_t> fSpadicAddressMap = {}; + + /** @brief Map to retrieve module channelId from asicAddress and asicChannel */ + std::map<Int_t, std::vector<Int_t>> fAsicChannelMap = {}; + + /** @brief Map containing the timeshift parameters for the correction of the µSlice timeshifts. The keys are the tsIdx, if no key is found, the shifts of the previous tsIdx are used again */ + std::map<size_t, std::vector<Int_t>> fTimeshiftsMap = {}; + + /** @brief Define if the first 16 channels (00..15) are found on the even (set true) or odd (false) eLinkId. + * Default for mCbm2020 is false thus, initialized as false */ + Bool_t fIsFirstChannelsElinkEven = kFALSE; + + /** @brief Number of rda frames outside of a SOM frame range */ + size_t fNrWildRda = 0; + + /** @brief Number of eom frames outside of a SOM frame range */ + size_t fNrWildEom = 0; + + /** @brief Number of wild null words, should only appear at the end of a µSlice */ + size_t fNrWildNul = 0; + + /** @brief Number of unknown words */ + size_t fNrUnknownWords = 0; + + /** @brief length of one ts_msb in [ns] */ + static constexpr std::uint16_t fTsMsbLength = 16000; + + /** @brief length of one ts_msb in [cc] */ + size_t fTsMsbLengthCC = fTsMsbLength / CbmTrdSpadic::GetClockCycle(); + + /** @brief Fles Subsystem Identifier for the TRD R data */ + static constexpr int fgkFlesSubsystemIdTrdR = static_cast<int>(fles::SubsystemIdentifier::TRD); + +private: + ClassDef(CbmTrdUnpackAlgoBaseR, 2) +}; + +#endif // CbmTrdUnpackAlgoBaseR_H diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackAlgoLegacy2020R.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoLegacy2020R.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7a592f93c2feabc377f50f545e2f87d25412bdcf --- /dev/null +++ b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoLegacy2020R.cxx @@ -0,0 +1,423 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +#include "CbmTrdUnpackAlgoLegacy2020R.h" + +#include "CbmTrdDigi.h" +#include "CbmTrdParManager.h" +#include "CbmTrdParSetAsic.h" +#include "CbmTrdRawMessageSpadic.h" + +#include <FairTask.h> +#include <Logger.h> + +#include <RtypesCore.h> +#include <typeinfo> + +#include <cstdint> +#include <memory> +#include <string> +#include <utility> + +CbmTrdUnpackAlgoLegacy2020R::CbmTrdUnpackAlgoLegacy2020R(/* args */) + : CbmTrdUnpackAlgoBaseR("CbmTrdUnpackAlgoLegacy2020R") +{ +} + +CbmTrdUnpackAlgoLegacy2020R::~CbmTrdUnpackAlgoLegacy2020R() {} + +// ---- GetParContainerRequest ---- +std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* +CbmTrdUnpackAlgoLegacy2020R::GetParContainerRequest(std::string geoTag, std::uint32_t runId) +{ + // Basepath for default Trd parameter sets (those connected to a geoTag) + std::string basepath = Form("%s/trd_%s", fParFilesBasePath.data(), geoTag.data()); + std::string temppath = ""; + + // Digest the runId information in case of runId = 0 we use the default fall back + std::string runpath = ""; + if (runId != 0) { runpath = ".run" + std::to_string(runId); } + + // Get .asic parameter container + temppath = basepath + runpath + ".asic" + ".par"; + fParContVec.emplace_back(std::make_pair(temppath, std::make_shared<CbmTrdParSetAsic>())); + + // Currently we need the ParSetDigi only for the monitor + if (fMonitor) { + temppath = basepath + runpath + ".digi" + ".par"; + auto pair = std::make_pair(temppath, std::make_shared<CbmTrdParSetDigi>()); + fParContVec.emplace_back(pair); + } + + + // We do not want to require the timeshift pars, since the unpacker has to be run without them to extract them. But if it is available we want to use it. + // Get timeshift correction parameters, currently only available for run 831 + if (runId == 831 && geoTag == "mcbm_beam_2020_03") { + temppath = Form("%s/mcbm2020_special/CbmMcbm2020TrdTshiftPar_run%d.par", fParFilesBasePath.data(), runId); + fParContVec.emplace_back(std::make_pair(temppath, std::make_shared<CbmMcbm2020TrdTshiftPar>())); + } + + + return &fParContVec; +} + +// ---- extractSample ---- +std::int16_t CbmTrdUnpackAlgoLegacy2020R::extractSample(const size_t word, const Spadic::MsMessageType msgType, + std::uint32_t isample, bool multihit) +{ + + switch (msgType) { + case Spadic::MsMessageType::kSOM: { + if (isample > 2) { + LOG(error) << fName << "::ExtractSample] SOM MSG - Idx " << isample << " Wrong sample index!"; + return -256; + } + break; + } + case Spadic::MsMessageType::kRDA: { + if (isample < 3 || isample > 31) { + LOG(error) << fName << "::ExtractSample] RDA MSG - Idx " << isample << " Wrong sample index!"; + return -256; + } + break; + } + default: + LOG(error) << fName << "::ExtractSample] Wrong Message Type!"; + return -256; + break; + } + + size_t mask = 0x1FF; + auto index = fExtractSampleIndicesVec.at(isample); + + mask = mask << (9 * (6 - index)); + size_t temp = word & mask; + temp = temp >> (6 - index) * 9; + if (fSpadic->GetUseBaselineAvg() && (isample == 0) && !(multihit)) { + /** When the average baseline feature of the spadic22 is activated, + * the value of samples[0] is always lower than -128, so we know it is 10------- + * Because of this it is possible to increase the precision by two bits, + * by cutting the two MSBs off and shifting everything two bits to the left. + * Here we need to undo this operation by shifting two bits righ + * and setting the MSB to 1 (negative sign) and the second msb to 0 (value < -128 ). + **/ + temp = temp >> 2; + temp ^= (-0 ^ temp) & (1 << 7); + temp ^= (-1 ^ temp) & (1 << 8); + } + struct { + signed int x : 9; + } s; + int16_t result = s.x = temp; + return result; +} + +// ---- extractEpoch ---- +size_t CbmTrdUnpackAlgoLegacy2020R::extractEpoch(const size_t word) +{ + size_t mask = 0x3FFFFFFF; + mask = mask << 32; + return ((word & mask) >> 32); +} + +// ---- finishDerived ---- +void CbmTrdUnpackAlgoLegacy2020R::finishDerived() +{ + LOG(info) << fName << fNrWildRda << " unexpected RDA words and\n " << fNrUnknownWords << " unknown words."; +} + + +// ---- getInfoType ---- +Spadic::MsInfoType CbmTrdUnpackAlgoLegacy2020R::getInfoType(const size_t msg) +{ + size_t mask = 0x000FFFFF; + + if (((msg & mask) >> 18) == 3) // BOM + { + return Spadic::MsInfoType::kBOM; + } + if (((msg & mask) >> 17) == 2) // MSB + { + return Spadic::MsInfoType::kMSB; + } + if (((msg & mask) >> 17) == 3) // BUF + { + return Spadic::MsInfoType::kBUF; + } + if (((msg & mask) >> 17) == 4) // UNU + { + return Spadic::MsInfoType::kUNU; + } + if (((msg & mask) >> 17) == 5) // MIS + { + return Spadic::MsInfoType::kMIS; + } + else { + LOG(error) << fName << "::GetInfoType] unknown type!"; + return Spadic::MsInfoType::kMSB; + } +} + + +// ---- getMessageType ---- +Spadic::MsMessageType CbmTrdUnpackAlgoLegacy2020R::getMessageType(const size_t msg) +{ + if ((msg >> 61) == 1) // SOM 001. .... + { + return Spadic::MsMessageType::kSOM; + } + else if ((msg >> 63) == 1) // RDA 1... .... + { + return Spadic::MsMessageType::kRDA; + } + else if ((msg >> 62) == 1) // Epoch 01.. .... + { + return Spadic::MsMessageType::kEPO; + } + else if ((msg >> 60) == 1) // Spadic Info Message 0001 .... + { + return Spadic::MsMessageType::kINF; + } + else if (msg == 0) // Last Word in a Microslice is 0 + { + return Spadic::MsMessageType::kNUL; + } + else // not a spadic message + { + return Spadic::MsMessageType::kUNK; + } +} + +// ---- getNrOfRdaWords ---- +std::uint8_t CbmTrdUnpackAlgoLegacy2020R::getNrOfRdaWords(std::uint8_t nsamples) +{ + auto nwords = (nsamples + 3) / 7; + return nwords > 5 ? 5 : nwords; +} + +// ---- makeRaw ---- +CbmTrdRawMessageSpadic CbmTrdUnpackAlgoLegacy2020R::makeRaw(const size_t word, fles::MicrosliceDescriptor msDesc) +{ + + ///Extract Metadata + uint8_t elinkId = 0, chId = 0, crobId = 0; + uint16_t criId = msDesc.eq_id; + // char crobId = msDesc.crob_id; // TODO this needs to be implemented into microslice! - PR 03.2020 + uint8_t hitType = 0, nSamples = 0; + bool multihit = false; + uint16_t timestamp = 0; + size_t mask = 0x3F; + mask = mask << 55; + elinkId = (char) ((word & mask) >> 55); + //extract chID + mask = 0xF; + mask = mask << 51; + chId = (char) ((word & mask) >> 51); + //extract timestamp + mask = 0xFFFF; + mask = mask << 35; + timestamp = (uint16_t)((word & mask) >> 35); + //extract hitType + mask = 0x3; + mask = mask << 33; + hitType = (uint8_t)((word & mask) >> 33); + //extract MultiHit + mask = 0x1; + mask = mask << 32; + multihit = (bool) ((word & mask) >> 32); + //extract nrSamples + mask = 0x1F; + mask = mask << 27; + nSamples = (uint8_t)((word & mask) >> 27); + nSamples += 1; //spadic counts from 0 to 31 + + // get the correct fulltime + size_t fulltime = timestamp + (fEpoch * fMsLengthCC); // this is in units of clock cycles + + + // put the first 3 samples, contained in som, into the message. + std::vector<std::int16_t> samples = {}; + for (std::uint32_t isample = 0; isample < nSamples && isample < 3; isample++) { + auto adcvalue = extractSample(word, Spadic::MsMessageType::kSOM, isample, multihit); + samples.emplace_back(adcvalue); + } + + // Create message + CbmTrdRawMessageSpadic retval(chId, elinkId, crobId, criId, hitType, nSamples, multihit, fulltime, samples); + return retval; +} + +void CbmTrdUnpackAlgoLegacy2020R::makeDigi(CbmTrdRawMessageSpadic raw) +{ + + // Extract the trigger type and translate it to the digi enum + auto rawTriggerType = static_cast<Spadic::eTriggerType>(raw.GetHitType()); + auto triggerType = CbmTrdRawToDigiBaseR::GetDigiTriggerType(rawTriggerType); + + // Get the digi error class (dummy for the time being) + Int_t errClass = 0; + + // Get the address of the originating spadic + size_t spadicHwAddress(0); + spadicHwAddress = (raw.GetElinkId()) + (CbmTrdParAsic::kCriIdPosition * raw.GetCriId()) + + (CbmTrdParAsic::kCrobIdPosition * raw.GetCrobId()); + Int_t asicAddress(0); + auto mapIt = fSpadicAddressMap.find(spadicHwAddress); // check if asic exists + if (mapIt == fSpadicAddressMap.end()) { + LOG(debug4) << fName + << "::makeDigi - No asic address " + "found for Spadic hardware address %lu" + << spadicHwAddress; + return; + } + asicAddress = mapIt->second; + + // Get the unique module id from the asic address + Int_t uniqueModuleId = asicAddress / 1000; + + // GetChannelId per eLink add NSPADICCH / 2 to the second(first) eLink in the case we start with odd(even) eLinks, since, our mapping is based on odd eLinks + auto asicChannelId = (raw.GetElinkId() % 2) == fIsFirstChannelsElinkEven + ? raw.GetChannelId() + : raw.GetChannelId() + (CbmTrdSpadic::GetNrChannels() / 2); + + + auto padChNr = (fAsicChannelMap.find(asicAddress))->second.at(asicChannelId); + + // Store the full time information to last full-time member for error message handling + fLastFulltime = raw.GetFullTime(); + + // Get the time information and apply the necessary correction + ULong64_t time = raw.GetTime(); + if (fTimeshiftsParVec) { + time = time - fTimeshiftsParVec->at(padChNr); + raw.SetTime(time); + } + time -= fSystemTimeoffset; + + auto digi = fRTDMethod->MakeDigi(raw.GetSamples(), padChNr, uniqueModuleId, time, triggerType, errClass); + + // Digest the output, i.e. write to return vector and optional pass to the monitor + digestOutput(std::move(digi), raw); +} + +// ---- setDerivedTsParameters ---- +bool CbmTrdUnpackAlgoLegacy2020R::setDerivedTsParameters(size_t itimeslice) +{ + auto timeshiftpair = fTimeshiftsMap.find(itimeslice); + if (timeshiftpair != fTimeshiftsMap.end()) { fTimeshiftsParVec = ×hiftpair->second; } + else + return false; + return true; +} + +// ---- unpack ---- +bool CbmTrdUnpackAlgoLegacy2020R::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice) +{ + + + bool unpackOk = true; + + auto msdesc = ts->descriptor(icomp, imslice); + + // Get the µslice size in bytes to calculate the number of completed words + auto mssize = msdesc.size; + + // Get the number of complete words in the input MS buffer. + std::uint32_t msNrWords = mssize / fBytesPerWord; + + const auto mspointer = ts->content(icomp, imslice); + const auto mscontent = reinterpret_cast<const size_t*>(mspointer); + + // Loop over all 64bit-Spadic-Words in the current µslice + for (std::uint32_t iword = 0; iword < msNrWords; iword++) { + // Access the actual word from the pointer + auto word = static_cast<size_t>(mscontent[iword]); + + // Get the type of the word + auto kWordtype = getMessageType(word); + + switch (kWordtype) { + case Spadic::MsMessageType::kSOM: { + CbmTrdRawMessageSpadic raw = makeRaw(word, msdesc); + auto nsamples = raw.GetNrSamples(); + /// If the new Message has more than 3 Samples, we need to read in the next words that contain the remaining samples. + if (nsamples > 3) { + std::uint32_t isample = 3; // first 3 samples are already handled in som + /// Loop over the rda words + for (uint8_t irda = 0; irda < getNrOfRdaWords(nsamples); irda++) { + ++iword; + word = static_cast<size_t>(mscontent[iword]); + auto kAddWordtype = getMessageType(word); + if (kAddWordtype != Spadic::MsMessageType::kRDA) { + LOG(error) << fName + << "::unpack() Incomplete Spadic " + "Message! RDA Word missing, Microslice corrupted."; + return kFALSE; + } + /// Loop over Samples. There are max 7 samples per word. + for (std::uint32_t iwordsample = 0; isample < nsamples && iwordsample < 7; isample++, iwordsample++) { + auto adcvalue = extractSample(word, kAddWordtype, isample); + raw.SetSample(adcvalue, isample); + } + } + } + ++fNrCreatedRawMsgs; + + // Message is completed here. Now lets Generate the digi and save raw message if needed. + makeDigi(raw); + + break; + } + case Spadic::MsMessageType::kRDA: { + // All rda words should be handled inside the kSOM case. Hence, this case should not appear and we have to count it as an error appearance. + LOG(error) << fName + << "::unpack() Unexpected RDA " + "Word. Microslice corrupted."; + fNrWildRda++; + return false; + break; + } + case Spadic::MsMessageType::kINF: { + /// Save info message if needed. + if (fOptOutBVec) { fOptOutBVec->emplace_back(std::make_pair(fLastFulltime, word)); } + fNrCreatedInfoMsgs++; + // TODO here we also want to call the monitoring class + // Spadic::MsInfoType infoType = getInfoType(word); + // "Spadic_Info_Types"; + // if (fIsActiveHistoVec[kSpadic_Info_Types]) { + // ((TH2I*) fHistoArray.At(kSpadic_Info_Types))->Fill(fLastFulltime, (Int_t) infoType); + // } + break; + } + case Spadic::MsMessageType::kNUL: { + if (iword != (msNrWords - 1)) // last word in Microslice is 0. + { + LOG(error) << fName + << "::unpack() Null Word but " + "not at end of Microslice."; + } + break; + } + case Spadic::MsMessageType::kUNK: { + LOG(error) << fName + << "::unpack() Unknown Word. " + "Microslice corrupted."; + ++fNrUnknownWords; + return false; + break; + } + case Spadic::MsMessageType::kEPO: { + fEpoch = extractEpoch(word); + fNrEpochMsgs++; + break; + } + default: + // We have varying msg types for different versions of the message format. Hence, to not produce compiler warnings we have a "default break;" here. + break; + } + } + return unpackOk; +} + +ClassImp(CbmTrdUnpackAlgoLegacy2020R) diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackAlgoLegacy2020R.h b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoLegacy2020R.h new file mode 100644 index 0000000000000000000000000000000000000000..b17b1b1e15461217c51bac284b398cdd8e575404 --- /dev/null +++ b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoLegacy2020R.h @@ -0,0 +1,171 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +/** + * @file CbmTrdUnpackAlgoLegacy2020R.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Unpacker algorithms for the TrdR 2020 data + * @version 0.1 + * @date 2021-04-21 + * + * @copyright Copyright (c) 2021 + * + * Implementation of the TrdR unpacker for the Spadic v2.2 data from 2020. + * See https://git.cbm.gsi.de/dschledt/dpb_design/-/blob/57fca5f2/project/spadicDPB_realMS/src/spadicDPB_realMS.vhd#L673 + * +*/ + +#ifndef CbmTrdUnpackAlgoLegacy2020R_H +#define CbmTrdUnpackAlgoLegacy2020R_H + +#include "CbmMcbm2020TrdTshiftPar.h" +#include "CbmTrdRawMessageSpadic.h" +#include "CbmTrdSpadic.h" +#include "CbmTrdUnpackAlgoBaseR.h" + +#include "Timeslice.hpp" // timeslice +#include <MicrosliceDescriptor.hpp> // fles subsystemId + +#include <FairTask.h> // for InitStatus + +#include <Rtypes.h> // for types +#include <RtypesCore.h> + +#include <cstddef> +#include <cstdint> + +class CbmTrdUnpackAlgoLegacy2020R : public CbmTrdUnpackAlgoBaseR { + +private: + /* data */ + +public: + /** @brief Create the Cbm Trd Unpack AlgoBase object */ + CbmTrdUnpackAlgoLegacy2020R(/* args */); + + /** @brief Destroy the Cbm Trd Unpack Task object */ + virtual ~CbmTrdUnpackAlgoLegacy2020R(); + + /** @brief Copy constructor - not implemented **/ + CbmTrdUnpackAlgoLegacy2020R(const CbmTrdUnpackAlgoLegacy2020R&) = delete; + + /** @brief Assignment operator - not implemented **/ + CbmTrdUnpackAlgoLegacy2020R& operator=(const CbmTrdUnpackAlgoLegacy2020R&) = delete; + + // Getters + /** + * @brief Get the requested parameter containers. + * Return the required parameter containers together with the paths to the ascii + * files to. + * + * @param[in] std::string geoTag as used in CbmSetup + * @param[in] std::uint32_t runId for runwise defined parameters + * @return fParContVec + */ + virtual std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* + GetParContainerRequest(std::string geoTag, std::uint32_t runId); + +protected: + /** + * @brief Extract the epoch time reference information from the epoch word + * + * @param word + * @return size_t + */ + size_t extractEpoch(const size_t word); + + /** + * @brief Extract the given sample from the given rda word + * + * @param word the 64bit Message Word + * @param sample Which sample to extract [0,31] + * @param multihit Set to true if current word belongs to a multihit message. + * @return The ADC value of the given sample, range [-255,255]. -256 if an error occurred. + */ + std::int16_t extractSample(const size_t word, const Spadic::MsMessageType msgType, std::uint32_t isample, + bool multihit = false); + + const std::vector<std::uint8_t> fExtractSampleIndicesVec = {4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, + 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0}; + + /** @brief Additional explicit finish function of this algo implementation. */ + void finishDerived(); + + /** @brief Identify the InfoType of a 64bit InfoMessage word inside a Microslice */ + Spadic::MsInfoType getInfoType(const size_t msg); + + /** @brief Identify the message type of a 64bit word inside a Microslice */ + Spadic::MsMessageType getMessageType(const size_t msg); + + /** + * @brief Get the Nr Of Rda Words required for the amount of ADC samples + * + * @param nsamples + * @return std::uint8_t + */ + std::uint8_t getNrOfRdaWords(std::uint8_t nsamples); + + /** + * @brief Create a CbmTrdRawMessageSpadic from the hit message input. + * + * @param word + * @param msDesc + * @return CbmTrdRawMessageSpadic + * + * @todo Check if we can get rid of the future obsolete microslice stuff. + */ + virtual CbmTrdRawMessageSpadic makeRaw(const size_t word, fles::MicrosliceDescriptor msDesc); + + /** + * @brief Create an actual digi from the raw message + * + * @param raw + * @return std::shared_ptr<CbmTrdDigi> + */ + void makeDigi(CbmTrdRawMessageSpadic raw); + + /** + * @brief Set the Derived Ts Parameters + * + * In this function parameters required by the explicit algo connected to the timeslice are set. + * + * @param itimeslice + * @return true + * @return false + */ + virtual bool setDerivedTsParameters(size_t itimeslice); + + /** + * @brief Unpack a given microslice. + * + * @param ts timeslice pointer + * @param icomp index to the component to be unpacked + * @param imslice index of the microslice to be unpacked + * @return true + * @return false + * + * @remark The content of the µslice can only be accessed via the timeslice. Hence, we need to pass the pointer to the full timeslice + */ + virtual bool unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice); + + // Parameter storage members + + /** @brief Vector containing the timeshift parameters for the correction of the µSlice timeshifts for a given tsIdx.*/ + std::vector<std::int32_t>* fTimeshiftsParVec = nullptr; + + /** @brief Time of the current epoch marker */ + size_t fEpoch = 0; + + /** @brief Microslice length [CC]. To be overwritten in the version specific unpackers. */ + size_t fMsLengthCC = 1.28e6 / CbmTrdSpadic::GetClockCycle(); + + // Constants + /** @brief Bytes per word stored in the microslices */ + static const std::uint8_t fBytesPerWord = 8; + +private: + ClassDef(CbmTrdUnpackAlgoLegacy2020R, 2) +}; + +#endif // CbmTrdUnpackAlgoLegacy2020R_H diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b24e3c8cdd5e4497cd4c3471f5211649edfc98e0 --- /dev/null +++ b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.cxx @@ -0,0 +1,522 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +#include "CbmTrdUnpackAlgoR.h" + +#include "CbmTrdParManager.h" +#include "CbmTrdParSetAsic.h" +#include "CbmTrdRawMessageSpadic.h" + +#include <FairTask.h> +#include <Logger.h> + +#include <RtypesCore.h> +#include <typeinfo> + +#include <algorithm> +#include <bitset> +#include <cstdint> +#include <memory> + +CbmTrdUnpackAlgoR::CbmTrdUnpackAlgoR(/* args */) : CbmTrdUnpackAlgoBaseR("CbmTrdUnpackAlgoR") {} + +CbmTrdUnpackAlgoR::~CbmTrdUnpackAlgoR() {} + + +// ---- GetParContainerRequest ---- +std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* +CbmTrdUnpackAlgoR::GetParContainerRequest(std::string geoTag, std::uint32_t runId) +{ + // Basepath for default Trd parameter sets (those connected to a geoTag) + std::string basepath = Form("%s/trd_%s", fParFilesBasePath.data(), geoTag.data()); + std::string temppath = ""; + + // Digest the runId information in case of runId = 0 we use the default fall back + std::string runpath = ""; + if (runId != 0) { runpath = ".run" + std::to_string(runId); } + + // Get .asic parameter container + temppath = basepath + runpath + ".asic" + ".par"; + fParContVec.emplace_back(std::make_pair(temppath, std::make_shared<CbmTrdParSetAsic>())); + + // Currently we need the ParSetDigi only for the monitor + if (fMonitor) { + temppath = basepath + runpath + ".digi" + ".par"; + auto pair = std::make_pair(temppath, std::make_shared<CbmTrdParSetDigi>()); + fParContVec.emplace_back(pair); + } + + + return &fParContVec; +} + +// ---- digestBufInfoFlags ---- +Spadic::MsInfoType CbmTrdUnpackAlgoR::digestBufInfoFlags(const std::uint32_t frame, std::uint16_t criId, + std::uint8_t crobId, std::uint16_t elinkId) +{ + auto flag = (frame >> 15) & 0x3; + Spadic::MsInfoType infotype; + if (flag == 1) infotype = Spadic::MsInfoType::kChannelBuf; + if (flag == 2) infotype = Spadic::MsInfoType::kOrdFifoBuf; + if (flag == 3) infotype = Spadic::MsInfoType::kChannelBufM; + + if (fMonitor) { + // ModuleId is the asic address after the first 3 digits + auto moduleid = getAsicAddress(criId, crobId, elinkId) / 1000; + fMonitor->FillHisto(infotype, moduleid); + } + return infotype; +} + +// ---- digestInfoMsg ---- +void CbmTrdUnpackAlgoR::digestInfoMsg(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId, + std::uint16_t elinkId) +{ + /// Save info message if needed. + if (fOptOutBVec) { fOptOutBVec->emplace_back(std::make_pair(fLastFulltime, frame)); } + fNrCreatedInfoMsgs++; + Spadic::MsInfoType infotype = getInfoType(frame, criId, crobId, elinkId); + // "Spadic_Info_Types"; + + if (fMonitor) { + // ModuleId is the asic address after the first 3 digits + auto moduleid = getAsicAddress(criId, crobId, elinkId) / 1000; + fMonitor->FillHisto(infotype, moduleid); + } +} + +// ---- digestInfoMsg ---- +void CbmTrdUnpackAlgoR::digestMsFlags(const std::uint16_t flags, std::uint16_t criId, std::uint8_t crobId) +{ + // ModuleId is the asic address after the first 3 digits + auto moduleid = getAsicAddress(criId, crobId, 0) / 1000; + + if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::CrcValid)) { + fNrCrcValidFlags++; + if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::CrcValid, moduleid); } + } + if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::OverflowFlim)) { + fNrOverflowFlimFlags++; + if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::OverflowFlim, moduleid); } + } + if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::OverflowUser)) { + fNrOverflowUserFlags++; + if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::OverflowUser, moduleid); } + } + if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::DataError)) { + fNrDataErrorFlags++; + if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::DataError, moduleid); } + } +} + +// ---- extractSample ---- +std::float_t CbmTrdUnpackAlgoR::extractAvgSample(size_t* adcbuffer, size_t* nadcbits) +{ + if (*nadcbits < 9) + LOG(error) << fName << "::extractAvgSample can not extract samples from a buffer with less than 9 bits"; + + *nadcbits -= 9; + + // The decoding of the average sample is kind of interesting: + // We get 9 bits in total iiiiiiiff. The 7 "i" bits refer to std integer bits, hence, + // covering a range of 0..128. + // The 2 "f" bits refer to values after a fix point refering to [0,0.25,0.5,0.75]. + // The sign we have to assume to be negative (bit-9 = 1) and also bit 8 of our std + // interger range we have to assume to be 0, such that the returned number is in + // between -256..-128. + + // Activate the 7 "i" bits + std::int16_t sample = 0x07f; + + // Write the content of the 7 "i" bits to temp + sample &= (*adcbuffer >> (*nadcbits + 2)); + + // Switch on the negative sign + sample |= 0xff00; + + return sample; +} + +// ---- extractSample ---- +std::int16_t CbmTrdUnpackAlgoR::extractSample(size_t* adcbuffer, size_t* nadcbits) +{ + if (*nadcbits < 9) + LOG(error) << fName << "::extractSample can not extract samples from a buffer with less than 9 bits"; + + // We want to access the bits stored at the positions between nadcbits and nadcbits - 9, so we can already here reduce nadcbits by 9 and than shift the adcbuffer by this value to the right and compare it with temp which has the 9 lsbs set to 1 + *nadcbits -= 9; + + std::int16_t temp = 0x1ff; + temp &= (*adcbuffer >> (*nadcbits)); + + // Now we have our 9 bits stored in temp, but for a std::int16_t this does not match in terms of the sign handling. + // So we check on bit 9 for the sign (temp & 0x0100) and if we have a negative value we manipulate bit 16-10 to 1 to get the correct negative number + + std::int16_t sample = (temp & 0x0100) ? (temp | 0xff00) : temp; + + return sample; +} + +// ---- finishDerived ---- +void CbmTrdUnpackAlgoR::finishDerived() +{ + LOG(info) << fName << " \n " << fNrWildRda << " unexpected RDA frames,\n " << fNrWildNul + << " unexpected NUL frames, \n " << fNrWildEom << " unexpected EOM frames, \n " << fNrElinkMis + << " SOM to RDA/EOM eLink mismatches, \n " << fNrNonMajorTsMsb << " non-major ts_msbs and \n " + << fNrUnknownWords << " unknown frames."; +} + +// ---- getInfoType ---- +Spadic::MsInfoType CbmTrdUnpackAlgoR::getInfoType(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId, + std::uint16_t elinkId) +{ + // Set first 20 bits to 1 for the mask + size_t mask = 0x000FFFFF; + + // 000011.................. : BOM word + // 0000010................. : MSB word + // 0000011................. : BUF word + // 0000100................. : UNU word + // 0000101................. : MIS word + + if (((frame & mask) >> 18) == 3) // BOM + { + return Spadic::MsInfoType::kBOM; + } + if (((frame & mask) >> 17) == 2) // MSB + { + return Spadic::MsInfoType::kMSB; + } + if (((frame & mask) >> 17) == 3) // BUF + { + digestBufInfoFlags(frame, criId, crobId, elinkId); + return Spadic::MsInfoType::kBUF; + } + if (((frame & mask) >> 17) == 4) // UNU + { + return Spadic::MsInfoType::kUNU; + } + if (((frame & mask) >> 17) == 5) // MIS + { + return Spadic::MsInfoType::kMIS; + } + else { + LOG(error) << fName << "::GetInfoType] unknown type!"; + return Spadic::MsInfoType::kMSB; + } +} + +// ---- getMessageType ---- +Spadic::MsMessageType CbmTrdUnpackAlgoR::getMessageType(const std::uint32_t frame) +{ + std::uint32_t checkframe = frame; + checkframe &= 0xffffff; + if ((checkframe >> 21) == 1) // SOM 001. .... + { + return Spadic::MsMessageType::kSOM; + } + else if ((checkframe >> 22) == 1) // RDA 01.. .... + { + return Spadic::MsMessageType::kRDA; + } + else if ((checkframe >> 20) == 1) // EOM 0001 .... + { + return Spadic::MsMessageType::kEOM; + } + else if ((checkframe >> 22) == 3) // TS_MSB 11.. .... + { + return Spadic::MsMessageType::kEPO; + } + else if (0 < (checkframe >> 18) && (checkframe >> 18) <= 3) { + return Spadic::MsMessageType::kINF; + } + else if (checkframe == 0) // Last Word in a Microslice is 0 + { + return Spadic::MsMessageType::kNUL; + } + else // not a spadic message + { + return Spadic::MsMessageType::kUNK; + } +} + +// ---- getTsMsb ---- +std::uint8_t CbmTrdUnpackAlgoR::getTsMsb(const std::uint32_t frame) +{ + // The epoch in form of the TS_MSBs is written 3 times into the frame to allow to check for bit flips and catch errors. It has the length of 6 bits and an offset of 4 + std::uint8_t tsmsb[3]; + for (uint iepoch = 0; iepoch < 3; ++iepoch) { + tsmsb[iepoch] = static_cast<std::uint8_t>((frame >> (4 + 6 * iepoch) & 0x3f)); + } + + // Check if the epoch at position 0 is at least compatible with one of the others. Since, we only have 3 that value is automatically the majority value. + if (tsmsb[0] == tsmsb[1] || tsmsb[0] == tsmsb[2]) return tsmsb[0]; + + // If we arrive here the epoch at position 0 is not compatible with the other two. So let's check if they are compatible with each other. If so we have again a majority epoch + if (tsmsb[1] == tsmsb[2]) return tsmsb[1]; + + LOG(debug) << fName + << "::checkMajorityTsMsb got a vector without a majority ts_msb, so please check what is going on here!"; + ++fNrNonMajorTsMsb; + + return tsmsb[0]; +} + +// ---- makeDigi ---- +void CbmTrdUnpackAlgoR::makeDigi(CbmTrdRawMessageSpadic raw) +{ + + // Extract the trigger type and translate it to the digi enum + auto rawTriggerType = static_cast<Spadic::eTriggerType>(raw.GetHitType()); + auto triggerType = CbmTrdRawToDigiBaseR::GetDigiTriggerType(rawTriggerType); + + // Get the digi error class (dummy for the time being) + Int_t errClass = 0; + + // Get the address of the originating spadic + auto asicAddress = getAsicAddress(raw.GetCriId(), raw.GetCrobId(), raw.GetElinkId()); + + // Get the unique module id from the asic address + Int_t uniqueModuleId = asicAddress / 1000; + + // Get the channel id on the module + auto padChNr = getChannelId(asicAddress, raw.GetElinkId(), raw.GetChannelId()); + + // Store the full time information to last full-time member for error message handling + fLastFulltime = raw.GetFullTime(); + + // Get the time information and apply the necessary correction + ULong64_t time = raw.GetTime(); + time -= fSystemTimeoffset; + + auto digi = fRTDMethod->MakeDigi(raw.GetSamples(), padChNr, uniqueModuleId, time, triggerType, errClass); + + // Digest the output, i.e. write to return vector and optional pass to the monitor + digestOutput(std::move(digi), raw); +} + +// ---- makeRaw ---- +CbmTrdRawMessageSpadic CbmTrdUnpackAlgoR::makeRaw(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId, + std::uint16_t elinkId, std::uint8_t istream) +{ + + auto chId = static_cast<std::uint8_t>(((frame >> 17) & 0xf)); + auto timestamp = static_cast<std::uint16_t>((frame >> 9) & 0xff); + bool multihit = ((frame >> 8) & 0x1); + auto hitType = static_cast<std::uint8_t>((frame >> 6) & 0x3); + std::uint8_t nsamples = 0; + // We directly start with the largest possible samples vector to only init it once + std::vector<std::int16_t> samples = std::vector<std::int16_t>(0); + + // get the correct fulltime in units of clock cycles + size_t fulltime = fMsStartTimeCC + (fNrTsMsbVec.at(istream) * fTsMsbLengthCC) + timestamp; + + // Create message + CbmTrdRawMessageSpadic retval(chId, elinkId, crobId, criId, hitType, nsamples, multihit, fulltime, samples); + return retval; +} + + +// ---- unpack ---- +bool CbmTrdUnpackAlgoR::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice) +{ + bool unpackOk = true; + + auto msdesc = ts->descriptor(icomp, imslice); + + // Get the µSlice start time and reset the ts_msb counter + fMsStartTimeCC = msdesc.idx / fSpadic->GetClockCycle(); + + // We only want to count on TS_MSB per Stream per TS_MSB package (each eLink sends its own TS_MSB frame) so we store the current TS_MSB and compare it to the incoming. + std::uint8_t currTsMsb = 0; + + // Reset the TS_MSB counter for the new µSlice we unpack + fNrTsMsbVec.clear(); + fNrTsMsbVec.resize(fStreamsPerWord); + + + // Get the µslice size in bytes to calculate the number of completed words + auto mssize = msdesc.size; + + + // Get the hardware ids from which the current µSlice is coming + std::uint8_t crobId = 0; + auto criId = msdesc.eq_id; + + // Digest the flags from the µSlice + digestMsFlags(msdesc.flags, criId, crobId); + + // Get the number of complete words in the input MS buffer. + std::uint32_t nwords = mssize / fBytesPerWord; + + const auto mspointer = ts->content(icomp, imslice); + + // We have 32 bit spadic frames in this readout version + const auto mscontent = reinterpret_cast<const size_t*>(mspointer); + + // Loop over all 64bit-Spadic-Words in the current µslice + for (std::uint32_t istream = 0; istream < fStreamsPerWord; istream++) { + for (std::uint32_t iword = 0; iword < nwords; ++iword) { + // Access the actual word from the pointer + size_t word = static_cast<size_t>(mscontent[iword]); + + // Access the actual frame[iframe] from the word. (see fStreamsPerWord) + std::uint32_t frame = (word >> (32 * istream)) & 0xffffffff; + + // Get the type of the frame + auto kWordtype = getMessageType(frame); + + // In case we saw any other word than an EPO(TS_MSB) reset the flag, such that we again increase by one if an EPO frame arrives + auto elinkId = (frame >> 24) & 0x3f; + + switch (kWordtype) { + case Spadic::MsMessageType::kEPO: { + auto tsmsb = getTsMsb(frame); + if (tsmsb > currTsMsb) fNrTsMsbVec.at(istream)++; + currTsMsb = tsmsb; + fNrEpochMsgs++; + break; + // FIXME in the kEPO msg we also have further flags that should be extracted + } + case Spadic::MsMessageType::kSOM: { + // Create the raw message and fill it with all information we can get from the SOM msg + CbmTrdRawMessageSpadic raw = makeRaw(frame, criId, crobId, elinkId, istream); + + // FIXME since we can not deduce the sample position from the messages we need in future some parameter handling here to place the samples at the correct position + // 6 adc bits are stored in the som message + size_t nadcbits = 6; + size_t nadcbitstotal = 6; + // Get the first bits from the adc signal + size_t adcbuffer = frame & 0x3f; + size_t isample = 0; + size_t irda = 0; + + // Now lets check if we have rda words following our som + iword++; + word = static_cast<size_t>(mscontent[iword]); + frame = (word >> (32 * istream)) & 0xffffffff; + + while (getMessageType(frame) == Spadic::MsMessageType::kRDA) { + // We have to count the number of rda frames for sample reconstruction in eom + irda++; + + // Ensure that we are on the correct eLink + elinkId = (frame >> 24) & 0x3f; + if (elinkId != raw.GetElinkId()) { + fNrElinkMis++; + LOG(debug) << fName << "::unpack() SOM eLinkId(" << static_cast<std::uint16_t>(raw.GetElinkId()) + << ") does not match the RDA eLinkId(" << elinkId << ")"; + } + + // We have 22 adc bits per RDA word lets add them to the buffer... + adcbuffer <<= 22; + adcbuffer |= static_cast<size_t>((frame & 0x3fffff)); + // and increase the adcbit counter by 22 bits + nadcbits += 22; + nadcbitstotal += 22; + // If we have 9 or more samples stored we can extract n samples + while (nadcbits >= 9) { + raw.IncNrSamples(); + // In case the avg baseline feature was used we need to take special care of sample 0 + if (isample == 0 && fSpadic->GetUseBaselineAvg()) + raw.SetSample(extractAvgSample(&adcbuffer, &nadcbits), isample); + else + raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample); + isample++; + } + iword++; + word = static_cast<size_t>(mscontent[iword]); + frame = (word >> (32 * istream)) & 0xffffffff; + } + + if (getMessageType(frame) == Spadic::MsMessageType::kEOM) { + // Ensure that we are on the correct eLink + elinkId = (frame >> 24) & 0x3f; + if (elinkId != raw.GetElinkId()) { + fNrElinkMis++; + LOG(debug) << fName << "::unpack() SOM eLinkId(" << static_cast<std::uint16_t>(raw.GetElinkId()) + << ") does not match the RDA eLinkId(" << elinkId << ")"; + } + + // Number of samples indicator = nsamples % 4 + std::uint8_t nsamplesindicator = (frame >> 18) & 0x3; + // Number of required samples as indicated + auto nreqsamples = (nadcbitstotal + 18) / 9; + std::uint8_t nn = nreqsamples % 4; + for (std::uint8_t itest = 0; itest < 3; itest++) { + if (nn == nsamplesindicator) break; + nreqsamples--; + nn = nreqsamples % 4; + } + + // Now extract from the above values the number of required adc bits from the eom + std::int8_t nrequiredbits = (nreqsamples - isample) * 9 - nadcbits; + adcbuffer <<= nrequiredbits; + + // The eom carries at maximum 18 adcbits + adcbuffer |= static_cast<size_t>((frame & 0x3ffff) >> (18 - nrequiredbits)); + nadcbits += nrequiredbits; + + while (nadcbits >= 9) { + raw.IncNrSamples(); + raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample); + isample++; + } + ++fNrCreatedRawMsgs; + // the message is done and the raw message container should contain everything we need. So now we can call makeDigi() + makeDigi(raw); + } + else { + // We move the word counter backwards by one, such that the unexpected message can correctly be digested + iword--; + LOG(debug) + << fName + << "::unpack() We had a SOM message and hence, desparately need an EOM message but none came. This " + "is quite mysterious and a problem!"; + } + break; + } + case Spadic::MsMessageType::kRDA: { + LOG(debug) << fName << "::unpack() Unexpected wild RDA word"; + fNrWildRda++; + break; + } + case Spadic::MsMessageType::kEOM: { + LOG(debug) << fName << "::unpack() Unexpected wild EOM word"; + fNrWildEom++; + break; + } + case Spadic::MsMessageType::kINF: { + digestInfoMsg(frame, criId, crobId, elinkId); + break; + } + case Spadic::MsMessageType::kNUL: { + if (iword != (nwords - 1) || (istream != (fStreamsPerWord - 1))) + // last word in Microslice is 0. + { + LOG(debug) << fName + << "::unpack() Null Word but " + "not at end of Microslice."; + fNrWildNul++; + } + break; + } + case Spadic::MsMessageType::kUNK: { + LOG(debug) << fName + << "::unpack() Unknown Word. " + "Microslice corrupted."; + ++fNrUnknownWords; + return false; + break; + } + default: + // We have varying msg types for different versions of the message format. Hence, to not produce compiler warnings we have a "default break;" here. + break; + } + } + } + return unpackOk; +} + +ClassImp(CbmTrdUnpackAlgoR) diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.h b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.h new file mode 100644 index 0000000000000000000000000000000000000000..2806e9198272c9eea74cc0afd54cb4cea7a9457e --- /dev/null +++ b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.h @@ -0,0 +1,201 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig, David Schledt */ + +/** + * @file CbmTrdUnpackAlgoR.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @author David Schledt + * @brief Unpacker algorithm for the TrdR 2021 data + * @version 1.0 + * @date 2021-04-21 + * + * @copyright Copyright (c) 2021 + * + * Implementation of the TrdR unpacker currently valid from mcbm 2021 and after + * +*/ + +#ifndef CbmTrdUnpackAlgoR_H +#define CbmTrdUnpackAlgoR_H + +#include "CbmTrdRawMessageSpadic.h" +#include "CbmTrdUnpackAlgoBaseR.h" + +#include <MicrosliceDescriptor.hpp> // fles subsystemId +#include <Timeslice.hpp> // timeslice + +#include <FairTask.h> // for InitStatus + +#include <Rtypes.h> // for types +#include <RtypesCore.h> + +#include <cstdint> +#include <vector> + +#include <cmath> + +class CbmTrdUnpackAlgoR : public CbmTrdUnpackAlgoBaseR { + +private: + /* data */ + +public: + /** @brief Create the Cbm Trd Unpack AlgoBase object */ + CbmTrdUnpackAlgoR(/* args */); + + /** @brief Destroy the Cbm Trd Unpack Task object */ + virtual ~CbmTrdUnpackAlgoR(); + + /** @brief Copy constructor - not implemented **/ + CbmTrdUnpackAlgoR(const CbmTrdUnpackAlgoR&) = delete; + + /** @brief Assignment operator - not implemented **/ + CbmTrdUnpackAlgoR& operator=(const CbmTrdUnpackAlgoR&) = delete; + + /** + * @brief Get the requested parameter containers. + * Return the required parameter containers together with the paths to the ascii + * files to. + * + * @param[in] std::string geoTag as used in CbmSetup + * @param[in] std::uint32_t runId for runwise defined parameters + * @return fParContVec + */ + virtual std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* + GetParContainerRequest(std::string geoTag, std::uint32_t runId); + + +protected: + /** + * @brief Digest the aditional flags stored in the 4 "cccc" bits of the EPO messages. + * @param frame + * @param criId id of the cri that send the µSlice + * @param criobId id of the crob that send the µSlice (currently not used set to 0 062021 PR) + * @param elinkId id of the elink from which the info message frame came + * @return Spadic::MsInfoType + */ + Spadic::MsInfoType digestBufInfoFlags(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId, + std::uint16_t elinkId); + + /** + * @brief Digest a info message run all default information forwarding from the msg. + * @param frame + * @param criId id of the cri that send the µSlice + * @param criobId id of the crob that send the µSlice (currently not used set to 0 062021 PR) + * @param elinkId id of the elink from which the info message frame came + */ + void digestInfoMsg(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId, std::uint16_t elinkId); + + /** + * @brief Digest the flags of the currently unpacked µSlice. + * @param flags flags stored in the µSlice descriptor + * @param criId id of the cri that send the µSlice + * @param criobId id of the crob that send the µSlice (currently not used set to 0 062021 PR) + */ + void digestMsFlags(const std::uint16_t flags, std::uint16_t criId, std::uint8_t crobId); + + /** @brief Extract all adc samples from a given adcbuffer container */ + + /** + * @brief Extract one adc sample from a given adcbuffer + * + * @param[in] adcbuffer + * @param[in,out] nadcbits + * @return std::int16_t + */ + std::int16_t extractSample(size_t* adcbuffer, size_t* nadcbits); + + /** + * @brief Extract the baseline average sample from a given adcbuffer. + * Depending on the Spadic settings sample-0 is a plain sample or the averaged + * baseline calculation. The latter is not a 9 bit signed integer, but a 9 bit + * floating point number 7 digits before the point and 2 afterwards. + * @param[in] adcbuffer + * @param[in,out] nadcbits + * @return std::float_t + */ + std::float_t extractAvgSample(size_t* adcbuffer, size_t* nadcbits); + + /** @brief Additional explicit finish function of this algo implementation. */ + void finishDerived(); + + /** @brief Identify the InfoType of a 64bit InfoMessage word inside a Microslice */ + Spadic::MsInfoType getInfoType(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId, + std::uint16_t elinkId); + + /** @brief Identify the message type of a given 32bit frame inside a Microslice */ + Spadic::MsMessageType getMessageType(const std::uint32_t frame); + + /** + * @brief Get the ts_msb information from the TS_MSB(kEPO) frame. We take the first of the 3 + * The 3 redundant TS_MSB sets are already compared at the FPGA level. + * @param frame + * @return ts_msb value + */ + std::uint8_t getTsMsb(const std::uint32_t frame); + + /** + * @brief Create a CbmTrdRawMessageSpadic from the hit message input. + * + * @param word + * @param criId id of the cri that send the µSlice + * @param criobId id of the crob that send the µSlice (currently not used set to 0 062021 PR) + * @param istream + * @return CbmTrdRawMessageSpadic + * + * @todo Check if we can get rid of the future obsolete microslice stuff. + */ + virtual CbmTrdRawMessageSpadic makeRaw(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId, + std::uint16_t elinkId, std::uint8_t istream); + + /** + * @brief Create an actual digi from the raw message + * + * @param raw + */ + void makeDigi(CbmTrdRawMessageSpadic raw); + + /** @brief Up to now we do not need this function for this algorithm */ + bool setDerivedTsParameters(size_t /*itimeslice*/) { return true; } + + /** + * @brief Unpack a given microslice. + * + * @param ts timeslice pointer + * @param icomp index to the component to be unpacked + * @param imslice index of the microslice to be unpacked + * @return true + * @return false + * + * @remark The content of the µslice can only be accessed via the timeslice. Hence, we need to pass the pointer to the full timeslice + */ + bool unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice); + + // Parameter storage members + + /** @brief Counter for the ts_msb used to reconstruct the time */ + std::vector<std::uint8_t> fNrTsMsbVec = {}; + + /** @brief Counter for the ts_msb used to reconstruct the time */ + size_t fNrNonMajorTsMsb = 0; + + /** @brief Number of SOM to RDA/EOM mismatches */ + size_t fNrElinkMis = 0; + + /** @brief Start time of the current µSlice in Spadic CC */ + size_t fMsStartTimeCC = 0; + + // Constants + /** @brief Bytes per spadic frame stored in the microslices */ + static const std::uint8_t fBytesPerWord = 8; + /** @brief Number of streams per word + * For the msg format used from 2021 ongoing we have 2 parallel streams per word. All data from eLinks 0..20 go to one stream and 21..41 to the other */ + static const std::uint8_t fStreamsPerWord = 2; + + +private: + ClassDef(CbmTrdUnpackAlgoR, 2) +}; + +#endif // CbmTrdUnpackAlgoR_H diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackConfig.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackConfig.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0e248fa6293cb4c355d3afd277cafb238addc5a9 --- /dev/null +++ b/reco/detectors/trd/unpack/CbmTrdUnpackConfig.cxx @@ -0,0 +1,98 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +#include "CbmTrdUnpackConfig.h" + +#include "CbmTrdUnpackAlgoLegacy2020R.h" +#include "CbmTrdUnpackAlgoR.h" + +#include <Logger.h> + +#include <Rtypes.h> +#include <RtypesCore.h> + +#include <memory> +#include <vector> + +CbmTrdUnpackConfig::CbmTrdUnpackConfig(std::string detGeoSetupTag, UInt_t runid) + : CbmRecoUnpackConfig("CbmTrdUnpackConfig") + , fGeoSetupTag(detGeoSetupTag) + , fRunId(runid) +{ +} + +CbmTrdUnpackConfig::~CbmTrdUnpackConfig() {} + +// ---- Init ---- +void CbmTrdUnpackConfig::InitUnpacker() +{ + LOG(info) << fName << "::Init -"; + + auto initOk = kTRUE; + + // First choose the derived unpacking algorithm to be used and pass the raw to digi method + auto algo = chooseAlgo(); + + // If we got a handmade spadic we pass it to the algorithm and the RTD method + if (fSpadic) { + algo->SetSpadicObject(fSpadic); + fRTDMethod->SetSpadicObject(fSpadic); + } + + if (fDoLog) LOG(info) << fName << "::Init - SetRawToDigiMethod"; + algo->SetRawToDigiMethod(fRTDMethod); + + if (fDoLog) LOG(info) << fName << "::Init - SetParFilesBasePath"; + algo->SetParFilesBasePath(fParFilesBasePath); + + // If we have a monitor in the config add it to the algo + if (fMonitor) algo->SetMonitor(fMonitor); + + // Initialise the parameter containers required by the unpacker algo. Includes loading the corresponding ascii files + auto reqparvec = algo->GetParContainerRequest(fGeoSetupTag, fRunId); + initOk &= initParContainers(reqparvec); + + // Now we have all information required to initialise the algorithm + algo->Init(); + + // Pass the algo to its member in the base class + fAlgo = algo; +} + +// ---- chooseAlgo ---- +std::shared_ptr<CbmTrdUnpackAlgoBaseR> CbmTrdUnpackConfig::chooseAlgo() +{ + if (fDoLog) LOG(info) << fName << "::Init - chooseAlgo"; + + // Non default unpacker selection + // Legacy unpacker for data taken before mcbm 2021 + if (fGeoSetupTag.find("Desy2019") != fGeoSetupTag.npos) { + auto algo = std::make_shared<CbmTrdUnpackAlgoLegacy2020R>(); + LOG(info) << fName << "::chooseAlgo() - selected algo = " << algo->Class_Name(); + return algo; + } + if (fGeoSetupTag.find("trd_IkfSmallChamber") != fGeoSetupTag.npos) { + auto algo = std::make_shared<CbmTrdUnpackAlgoLegacy2020R>(); + LOG(info) << fName << "::chooseAlgo() - selected algo = " << algo->Class_Name(); + return algo; + } + if (fGeoSetupTag.find("v20a_mcbm") != fGeoSetupTag.npos) { + auto algo = std::make_shared<CbmTrdUnpackAlgoLegacy2020R>(); + LOG(info) << fName << "::chooseAlgo() - selected algo = " << algo->Class_Name(); + return algo; + } + + // Default unpacker selection + // Unpacker algo from mcbm 2021 on and hopefully default for a long time. + auto algo = std::make_shared<CbmTrdUnpackAlgoR>(); + LOG(info) << fName << "::chooseAlgo() - selected algo = " << algo->Class_Name(); + return algo; + + LOG(error) << fName + << "::Init - chooseAlgo() - no algorithm created something went wrong. We can not work like this!"; + return nullptr; +} + + +ClassImp(CbmTrdUnpackConfig) diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackConfig.h b/reco/detectors/trd/unpack/CbmTrdUnpackConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..d75bada2e5190da7a9954a327ce5f1c6d845aed4 --- /dev/null +++ b/reco/detectors/trd/unpack/CbmTrdUnpackConfig.h @@ -0,0 +1,123 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +/** + * @file CbmTrdUnpackConfig.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Configuration class for an unpacker algorithm + * @version 0.1 + * @date 2021-04-21 + * + * @copyright Copyright (c) 2021 + * + * This is the common configuration class for unpacking algorithms + * +*/ + +#ifndef CbmTrdUnpackConfig_H +#define CbmTrdUnpackConfig_H + + +#include "CbmRecoUnpackConfig.tmpl" +#include "CbmTrdRawToDigiBaseR.h" +#include "CbmTrdRawToDigiMaxAdcR.h" +#include "CbmTrdUnpackAlgoBaseR.h" +#include "CbmTrdUnpackMonitor.h" + +#include <FairLogger.h> +#include <Logger.h> + +#include <Rtypes.h> +#include <RtypesCore.h> + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <vector> + +class CbmTrdUnpackConfig : + public CbmRecoUnpackConfig<CbmTrdUnpackAlgoBaseR, CbmTrdDigi, CbmTrdRawMessageSpadic, std::pair<size_t, size_t>> { + +public: + /** + * @brief Create the Cbm Trd Unpack Task object + * + * @param geoSetupTag Geometry setup tag for the given detector as used by CbmSetup objects + * @param runid set if unpacker is rerun on a special run with special parameters + *@remark We use the string instead of CbmSetup here, to not having to link against sim/steer... + */ + CbmTrdUnpackConfig(std::string detGeoSetupTag, UInt_t runid = 0); + + /** + * @brief Destroy the Cbm Trd Unpack Task object + * + */ + virtual ~CbmTrdUnpackConfig(); + + /** @brief Copy constructor - not implemented **/ + CbmTrdUnpackConfig(const CbmTrdUnpackConfig&) = delete; + + /** @brief Assignment operator - not implemented **/ + CbmTrdUnpackConfig& operator=(const CbmTrdUnpackConfig&) = delete; + + // Getters + /** @brief Get the potentially added monitor. */ + std::shared_ptr<CbmTrdUnpackMonitor> GetMonitor() { return fMonitor; } + + /** @brief Get the spadic object attached to this config. @return CbmTrdSpadic */ + std::shared_ptr<CbmTrdSpadic> GetSpadicObject() { return fSpadic; } + + /** + * @brief Prepare the unpacker to be ready to run. + * In this function all initialization steps of the unpacker algorithms happen. + */ + void InitUnpacker(); + + // Setters + + /** @brief Add a monitor to the unpacker. @param value CbmTrdUnpackMonitor */ + void SetMonitor(std::shared_ptr<CbmTrdUnpackMonitor> value) { fMonitor = value; } + + /** + * @brief Set the raw to digi method + * + * @param value + */ + void SetRawToDigiMethod(std::shared_ptr<CbmTrdRawToDigiBaseR> value) { fRTDMethod = value; } + + /** + * @brief Set the Spadic Object + * + * @param value + */ + void SetSpadicObject(std::shared_ptr<CbmTrdSpadic> value) { fSpadic = value; } + +protected: + /** + * @brief Choose the derived unpacker algorithm to be used for the DAQ output to Digi translation. If algo was already set manually by the user this algorithm is used. + * + * @return Bool_t initOk + */ + virtual std::shared_ptr<CbmTrdUnpackAlgoBaseR> chooseAlgo(); + + /** @brief pointer to the raw msg to digi method */ + std::shared_ptr<CbmTrdRawToDigiBaseR> fRTDMethod = std::make_shared<CbmTrdRawToDigiMaxAdcR>(); + + /** @brief Spadic software reprensentation object */ + std::shared_ptr<CbmTrdSpadic> fSpadic = nullptr; + + /** @brief pointer to the monitor object */ + std::shared_ptr<CbmTrdUnpackMonitor> fMonitor = nullptr; + + /** @brief Geometry setup tag for the given detector as used by CbmSetup objects */ + std::string fGeoSetupTag = ""; + + /** @brief RunId of the current run, if not known 0 is a valid runtime case. Used runId based parameter loading. */ + UInt_t fRunId = 0; + +private: + ClassDef(CbmTrdUnpackConfig, 2) +}; + +#endif // CbmTrdUnpackConfig_H diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackMonitor.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackMonitor.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c15a8380696e8076646697a9a5a4c732b945015b --- /dev/null +++ b/reco/detectors/trd/unpack/CbmTrdUnpackMonitor.cxx @@ -0,0 +1,566 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +#include "CbmTrdUnpackMonitor.h" + +#include "CbmTrdDigi.h" +#include "CbmTrdParModDigi.h" +#include "CbmTrdRawMessageSpadic.h" + +#include <MicrosliceDescriptor.hpp> + +#include <FairRun.h> +#include <FairRunOnline.h> +#include <Logger.h> + +#include <RtypesCore.h> +#include <TFile.h> +#include <TH1.h> +#include <TH2.h> +#include <TProfile.h> + +#include <boost/math/special_functions/math_fwd.hpp> + +#include <cstdint> +#include <iostream> +#include <memory> +#include <numeric> +#include <string> +#include <utility> +#include <vector> + +#include <cmath> + +CbmTrdUnpackMonitor::CbmTrdUnpackMonitor(/* args */) {} + +CbmTrdUnpackMonitor::~CbmTrdUnpackMonitor() {} + +// ---- FillHistos ---- +void CbmTrdUnpackMonitor::FillHistos(CbmTrdDigi* digi, CbmTrdRawMessageSpadic* raw) +{ + auto moduleid = digi->GetAddressModule(); + for (auto pair : fDigiHistoMap) { + auto modulepair = pair.second.find(moduleid); + auto histo = modulepair->second; + fillHisto(digi, pair.first, moduleid, histo); + } + + if (raw) { + for (auto pair : fRawHistoMap) { + auto modulepair = pair.second.find(moduleid); + auto histo = modulepair->second; + fillHisto(raw, pair.first, histo, digi); + } + } +} + +// ---- FillHistos ---- +void CbmTrdUnpackMonitor::FillHisto(Spadic::MsInfoType type, std::uint32_t moduleid) +{ + auto pair = fOtherHistoMap.find(eOtherHistos::kSpadic_Info_Types); + if (pair == fOtherHistoMap.end()) return; + + auto histo = pair->second.find(moduleid)->second; + + histo->Fill(static_cast<std::uint32_t>(type)); +} + +// ---- FillHistos ---- +void CbmTrdUnpackMonitor::FillHisto(fles::MicrosliceFlags flag, std::uint32_t moduleid) +{ + auto pair = fOtherHistoMap.find(eOtherHistos::kMs_Flags); + if (pair == fOtherHistoMap.end()) return; + + auto histo = pair->second.find(moduleid)->second; + + histo->Fill(static_cast<std::uint32_t>(flag)); +} + +void CbmTrdUnpackMonitor::Finish() +{ + LOG(info) << Class_Name() << "::Finish() - "; + + if (fDoWriteToFile) { + size_t nhistos = 0; + + /// Save old global file and folder pointer to avoid messing with FairRoot + TFile* oldFile = gFile; + TDirectory* oldDir = gDirectory; + + /// (Re-)Create ROOT file to store the histos + // std::unique_ptr<TFile> histofile(new TFile(fOutfilename.data(), "RECREATE")); + TFile histofile(fOutfilename.data(), "RECREATE"); + + // Move into the histofile + // histofile->cd(); + histofile.cd(); + /// Write all the histograms to the file. + for (auto histopair : fHistoVec) { + // Make sure we end up in chosen folder + if (nullptr == gDirectory->Get(histopair.first.data())) gDirectory->mkdir(histopair.first.data()); + gDirectory->cd(histopair.first.data()); + + // Now lets extract whether we have a digi, raw or other histo and move (create) to the subdirectory + auto histotype = getHistoType(histopair.second); + // (Create and) Move to the directory of the type + if (nullptr == gDirectory->Get(histotype.data())) gDirectory->mkdir(histotype.data()); + gDirectory->cd(histotype.data()); + + + // Write histogram + LOG(debug) << Class_Name() << "::Finish() Write histo " << histopair.second->GetName() << " to file " + << histofile.GetName() << " in folder " << histopair.first.data() << "/" << histotype.data(); + histopair.second->Write(); + // Move back to root directory of the output file + // histofile->cd(); + histofile.cd(); + + nhistos++; + } + /// Restore old global file and folder pointer to avoid messing with FairRoot + gFile = oldFile; + gDirectory = oldDir; + + // histofile->Close(); + histofile.Close(); + + LOG(info) << Class_Name() << "::Finish() nHistos " << nhistos << " written to " << fOutfilename.data(); + } +} + +// ---- Init ---- +Bool_t CbmTrdUnpackMonitor::Init(CbmTrdParSetDigi* digiParSet) +{ + auto modulemap = digiParSet->GetModuleMap(); + for (auto modulepair : modulemap) { + auto parmoddigi = static_cast<CbmTrdParModDigi*>(modulepair.second); + + fModuleIdsVec.emplace_back(modulepair.first); + + fModuleOrientation.emplace(std::pair<std::uint32_t, std::uint8_t>(modulepair.first, parmoddigi->GetOrientation())); + fModuleNrRows.emplace(std::pair<std::uint32_t, std::uint8_t>(modulepair.first, parmoddigi->GetNofRows())); + fModuleNrColumns.emplace(std::pair<std::uint32_t, std::uint8_t>(modulepair.first, parmoddigi->GetNofColumns())); + } + + if (fModuleOrientation.empty() || fModuleNrRows.empty() || fModuleNrColumns.empty()) return kFALSE; + + // Check if there is a HttpServer and if so we later on register the created histograms in it. + if (FairRun::Instance()->IsA() == FairRunOnline::Class()) { + auto run = static_cast<FairRunOnline*>(FairRun::Instance()); + + fHistoServer = run->GetHttpServer(); + } + + createHistos(); + + return kTRUE; +} + +// ---- createHisto ---- +void CbmTrdUnpackMonitor::createHisto(eDigiHistos kHisto) +{ + std::string histoname = ""; + std::shared_ptr<TH1> newhisto = nullptr; + + for (auto moduleid : fModuleIdsVec) { + auto ncols = fModuleNrColumns.find(moduleid)->second; + auto nrows = fModuleNrRows.find(moduleid)->second; + auto nchannels = nrows * ncols; + auto rotation = fModuleOrientation.find(moduleid)->second; + + histoname = "ModuleId_" + std::to_string(moduleid) + "-"; + histoname += getHistoName(kHisto); + switch (kHisto) { + case eDigiHistos::kMap: + case eDigiHistos::kMap_St: + case eDigiHistos::kMap_Nt: + // Check if we have chamber sensitive along the x-axis + if (rotation % 2 == 0) { + newhisto = std::make_shared<TH2I>(histoname.data(), histoname.data(), ncols, -0.5, (ncols - 0.5), nrows, -0.5, + (nrows - 0.5)); + newhisto->SetXTitle("Pad column"); + newhisto->SetYTitle("Pad row"); + } + // If not it is sensitive along the y-axis + else { + newhisto = std::make_shared<TH2I>(histoname.data(), histoname.data(), nrows, -0.5, (nrows - 0.5), ncols, -0.5, + (ncols - 0.5)); + newhisto->SetXTitle("Pad row"); + newhisto->SetYTitle("Pad column"); + } + break; + + case eDigiHistos::kCharge: + case eDigiHistos::kCharge_St: + case eDigiHistos::kCharge_Nt: + newhisto = std::make_shared<TH1I>(histoname.data(), histoname.data(), fSpadic->GetDynamicRange(), 0 - 0.5, + fSpadic->GetDynamicRange() - 0.5); + newhisto->SetXTitle("MaxAdc [ADC units]"); + newhisto->SetYTitle("Counts"); + break; + case eDigiHistos::kTriggerType: + newhisto = std::make_shared<TH1I>(histoname.data(), histoname.data(), + static_cast<Int_t>(CbmTrdDigi::eTriggerType::kNTrg), -0.5, + (static_cast<Int_t>(CbmTrdDigi::eTriggerType::kNTrg) - 0.5)); + newhisto->SetXTitle("CbmTrdDigi eTriggerType"); + newhisto->SetYTitle("Counts"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(CbmTrdDigi::eTriggerType::kSelf) + 1), "St"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(CbmTrdDigi::eTriggerType::kNeighbor) + 1), "Nt"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(CbmTrdDigi::eTriggerType::kMulti) + 1), "Multihit"); + + break; + case eDigiHistos::kDigiDeltaT: + newhisto = std::make_shared<TH2I>(histoname.data(), histoname.data(), nchannels, -0.5, (nchannels - 0.5), 3500, + -2e6, 5e6); + newhisto->SetXTitle("ChannelId"); + newhisto->SetYTitle("#DeltaT(Digi(n)-Digi(n-1)) [ns]"); + break; + default: return; break; + } + LOG(debug) << Class_Name() << "::CreateHisto() HistoDigi " << static_cast<size_t>(kHisto) << " Module " << moduleid + << " initialized as " << histoname.data(); + if (newhisto) { addHistoToMap<eDigiHistos>(newhisto, &fDigiHistoMap, moduleid, kHisto); } + } +} + +// ---- createHisto ---- +void CbmTrdUnpackMonitor::createHisto(eRawHistos kHisto) +{ + std::string histoname = ""; + std::shared_ptr<TH1> newhisto = nullptr; + + for (auto moduleid : fModuleIdsVec) { + auto ncols = fModuleNrColumns.find(moduleid)->second; + auto nrows = fModuleNrRows.find(moduleid)->second; + auto nchannels = nrows * ncols; + + histoname = "ModuleId_" + std::to_string(moduleid) + "-"; + histoname += getHistoName(kHisto); + switch (kHisto) { + case eRawHistos::kSignalshape: + case eRawHistos::kSignalshape_St: + case eRawHistos::kSignalshape_Nt: + newhisto = std::make_shared<TH2I>(histoname.data(), histoname.data(), 32, -0.5, 31.5, 520, -260, 260); + newhisto->SetXTitle("ADC Sample [CC]"); + newhisto->SetYTitle("ADC Value [a.u.]"); + break; + case eRawHistos::kMap: + case eRawHistos::kMap_St: + case eRawHistos::kMap_Nt: + newhisto = std::make_shared<TH2I>(histoname.data(), histoname.data(), 42, -0.5, 41.5, 16, -0.5, 15.5); + newhisto->SetXTitle("ElinkId"); + newhisto->SetYTitle("eLink-ChannelId"); + break; + case eRawHistos::kElinkId: + newhisto = std::make_shared<TH1I>(histoname.data(), histoname.data(), 42, -0.5, 41.5); + newhisto->SetXTitle("ElinkId"); + newhisto->SetYTitle("Counts"); + break; + case eRawHistos::kSampleDistStdDev: + newhisto = std::make_shared<TH1F>(histoname.data(), histoname.data(), 200, 0.0, 100.0); + newhisto->SetXTitle("ADC signal std. deviation [#sigma]"); + newhisto->SetYTitle("Counts"); + break; + case eRawHistos::kSample0perChannel: + newhisto = std::make_shared<TH2I>(histoname.data(), histoname.data(), nchannels, -0.5, (nchannels - 0.5), 601, + -300, 300); + newhisto->SetXTitle("ChannelId"); + newhisto->SetYTitle("ADC Value(Sample-0) [a.u.]"); + break; + case eRawHistos::kHitType: + newhisto = std::make_shared<TH1I>(histoname.data(), histoname.data(), + static_cast<Int_t>(Spadic::eTriggerType::kGlobal) + 1, -0.5, + (static_cast<Int_t>(Spadic::eTriggerType::kSandN) + 0.5)); + newhisto->SetXTitle("Spadic::eTriggerType"); + newhisto->SetYTitle("Counts"); + break; + default: return; break; + } + LOG(debug) << Class_Name() << "::CreateHisto() HistoRaw " << static_cast<size_t>(kHisto) << " Module " << moduleid + << "initialized as " << histoname.data(); + /** @todo the part below is in principle copy paste for all histo types, so we should be able to move this to a single function */ + if (newhisto) { addHistoToMap<eRawHistos>(newhisto, &fRawHistoMap, moduleid, kHisto); } + } +} + +// ---- createHisto ---- +void CbmTrdUnpackMonitor::createHisto(eOtherHistos kHisto) +{ + std::string histoname = ""; + std::shared_ptr<TH1> newhisto = nullptr; + + for (auto moduleid : fModuleIdsVec) { + histoname = "ModuleId_" + std::to_string(moduleid) + "-"; + histoname += getHistoName(kHisto); + switch (kHisto) { + case eOtherHistos::kSpadic_Info_Types: { + auto nbins = static_cast<std::uint32_t>(Spadic::MsInfoType::kNInfMsgs); + newhisto = std::make_shared<TH1I>(histoname.data(), histoname.data(), nbins, -0.5, nbins - 0.5); + newhisto->SetXTitle("Info message type"); + newhisto->SetYTitle("Counts"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(Spadic::MsInfoType::kBOM) + 1), "BOM"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(Spadic::MsInfoType::kMSB) + 1), "MSB"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(Spadic::MsInfoType::kBUF) + 1), "BUF"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(Spadic::MsInfoType::kUNU) + 1), "UNU"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(Spadic::MsInfoType::kMIS) + 1), "MIS"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(Spadic::MsInfoType::kChannelBuf) + 1), "ChBuf"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(Spadic::MsInfoType::kOrdFifoBuf) + 1), "OrdFifoBuf"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(Spadic::MsInfoType::kChannelBufM) + 1), "ChBufMH"); + ; + break; + } + case eOtherHistos::kMs_Flags: { + auto nbins = static_cast<std::uint32_t>(fles::MicrosliceFlags::DataError) + 1; + newhisto = std::make_shared<TH1I>(histoname.data(), histoname.data(), nbins, -0.5, nbins - 0.5); + newhisto->SetXTitle("#muSlice info/error flags"); + newhisto->SetYTitle("Counts"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(fles::MicrosliceFlags::CrcValid) + 1), "CrcValid"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(fles::MicrosliceFlags::OverflowFlim) + 1), "OverflowFlim"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(fles::MicrosliceFlags::OverflowUser) + 1), "OverflowUser"); + newhisto->GetXaxis()->SetBinLabel((static_cast<int>(fles::MicrosliceFlags::DataError) + 1), "DataError"); + break; + } + default: return; break; + } + LOG(debug) << Class_Name() << "::CreateHisto() HistoOther " << static_cast<size_t>(kHisto) << " Module " << moduleid + << "initialized as " << histoname.data(); + + if (newhisto) { addHistoToMap<eOtherHistos>(newhisto, &fOtherHistoMap, moduleid, kHisto); } + } +} + +// ---- createHistos ---- +void CbmTrdUnpackMonitor::createHistos() +{ + for (auto kHisto : fActiveDigiHistos) { + createHisto(kHisto); + } + for (auto kHisto : fActiveRawHistos) { + createHisto(kHisto); + } + for (auto kHisto : fActiveOtherHistos) { + createHisto(kHisto); + } +} + +// ---- fillHisto ---- +void CbmTrdUnpackMonitor::fillHisto(CbmTrdDigi* digi, eDigiHistos kHisto, std::uint32_t moduleid, + std::shared_ptr<TH1> histo) +{ + auto triggertype = static_cast<CbmTrdDigi::eTriggerType>(digi->GetTriggerType()); + switch (kHisto) { + case eDigiHistos::kMap_St: { + if (triggertype != CbmTrdDigi::eTriggerType::kSelf) { return; } + else { + auto addresspair = getRowAndCol(moduleid, digi->GetAddressChannel()); + histo->Fill(addresspair.second, addresspair.first); + break; + } + } + case eDigiHistos::kMap_Nt: { + if (triggertype != CbmTrdDigi::eTriggerType::kNeighbor) { return; } + else { + auto addresspair = getRowAndCol(moduleid, digi->GetAddressChannel()); + histo->Fill(addresspair.second, addresspair.first); + break; + } + } + case eDigiHistos::kMap: { + auto addresspair = getRowAndCol(moduleid, digi->GetAddressChannel()); + histo->Fill(addresspair.second, addresspair.first); + break; + } + + case eDigiHistos::kCharge: histo->Fill(digi->GetCharge()); break; + case eDigiHistos::kCharge_St: + if (triggertype != CbmTrdDigi::eTriggerType::kSelf) { return; } + histo->Fill(digi->GetCharge()); + break; + case eDigiHistos::kCharge_Nt: + if (triggertype != CbmTrdDigi::eTriggerType::kNeighbor) { return; } + histo->Fill(digi->GetCharge()); + break; + + case eDigiHistos::kTriggerType: histo->Fill(digi->GetTriggerType()); break; + case eDigiHistos::kDigiDeltaT: histo->Fill(digi->GetAddressChannel(), getDeltaT(digi)); break; + + default: return; break; + } +} + +// ---- fillHisto ---- +void CbmTrdUnpackMonitor::fillHisto(CbmTrdRawMessageSpadic* raw, eRawHistos kHisto, std::shared_ptr<TH1> histo, + CbmTrdDigi* digi) +{ + auto triggertype = static_cast<Spadic::eTriggerType>(raw->GetHitType()); + switch (kHisto) { + case eRawHistos::kSignalshape: fillSamplesHisto(histo, raw); break; + case eRawHistos::kSignalshape_St: + if (triggertype != Spadic::eTriggerType::kSelf && triggertype != Spadic::eTriggerType::kSandN) return; + fillSamplesHisto(histo, raw); + break; + case eRawHistos::kSignalshape_Nt: + if (triggertype != Spadic::eTriggerType::kNeigh) return; + fillSamplesHisto(histo, raw); + break; + case eRawHistos::kMap: histo->Fill(raw->GetElinkId(), raw->GetChannelId()); break; + case eRawHistos::kMap_St: + if (triggertype != Spadic::eTriggerType::kSelf && triggertype != Spadic::eTriggerType::kSandN) return; + histo->Fill(raw->GetElinkId(), raw->GetChannelId()); + break; + case eRawHistos::kMap_Nt: + if (triggertype != Spadic::eTriggerType::kNeigh) return; + histo->Fill(raw->GetElinkId(), raw->GetChannelId()); + break; + case eRawHistos::kElinkId: histo->Fill(raw->GetElinkId()); break; + case eRawHistos::kSampleDistStdDev: histo->Fill(getSamplesStdDev(raw)); break; + case eRawHistos::kSample0perChannel: { + if (!digi) return; + histo->Fill(digi->GetAddressChannel(), raw->GetSamples()->at(0)); + break; + } + case eRawHistos::kHitType: histo->Fill(raw->GetHitType()); break; + default: return; break; + } +} + +// ---- fillSamplesHisto ---- +void CbmTrdUnpackMonitor::fillSamplesHisto(std::shared_ptr<TH1> histo, CbmTrdRawMessageSpadic* raw) +{ + for (size_t isample = 0; isample < raw->GetSamples()->size(); isample++) { + histo->Fill(isample, raw->GetSamples()->at(isample)); + } +} + +// ---- getDeltaT ---- +std::double_t CbmTrdUnpackMonitor::getDeltaT(CbmTrdDigi* digi) +{ + auto moduleid = digi->GetAddressModule(); + auto channelid = digi->GetAddressChannel(); + auto modulevecpair = fLastDigiTimeMap.find(moduleid); + if (modulevecpair == fLastDigiTimeMap.end()) { + auto nchannels = fModuleNrColumns.find(moduleid)->second * fModuleNrRows.find(moduleid)->second; + std::vector<size_t> channelsvec(nchannels, 0); + channelsvec.at(channelid) = digi->GetTime(); + auto pair = std::make_pair(moduleid, channelsvec); + fLastDigiTimeMap.emplace(pair); + return digi->GetTime(); + ; + } + else { + auto prevtime = modulevecpair->second.at(channelid); + modulevecpair->second.at(channelid) = digi->GetTime(); + auto dt = digi->GetTime() - prevtime; + return dt; + } +} + +// ---- getHistoName ---- +std::string CbmTrdUnpackMonitor::getHistoName(eDigiHistos kHisto) +{ + std::string histoname = "Digi_"; + + switch (kHisto) { + case eDigiHistos::kMap: histoname += "Map"; break; + case eDigiHistos::kMap_St: histoname += "Map_St"; break; + case eDigiHistos::kMap_Nt: histoname += "Map_Nt"; break; + case eDigiHistos::kCharge: histoname += "Charge"; break; + case eDigiHistos::kCharge_St: histoname += "Charge_St"; break; + case eDigiHistos::kCharge_Nt: histoname += "Charge_Nt"; break; + case eDigiHistos::kTriggerType: histoname += "TriggerType"; break; + case eDigiHistos::kDigiDeltaT: histoname += "DigiDeltaT"; break; + + default: return ""; break; + } + return histoname; +} + +// ---- getHistoName ---- +std::string CbmTrdUnpackMonitor::getHistoName(eRawHistos kHisto) +{ + std::string histoname = "Raw_"; + + switch (kHisto) { + case eRawHistos::kSignalshape: histoname += "Signalshape"; break; + case eRawHistos::kSignalshape_St: histoname += "Signalshape_St"; break; + case eRawHistos::kSignalshape_Nt: histoname += "Signalshape_Nt"; break; + case eRawHistos::kMap: histoname += "Map"; break; + case eRawHistos::kMap_St: histoname += "Map_St"; break; + case eRawHistos::kMap_Nt: histoname += "Map_Nt"; break; + case eRawHistos::kElinkId: histoname += "ElinkId"; break; + case eRawHistos::kSampleDistStdDev: histoname += "SampleDistStdDev"; break; + case eRawHistos::kSample0perChannel: histoname += "Sample0perChannel"; break; + case eRawHistos::kHitType: histoname += "HitType"; break; + default: return ""; break; + } + return histoname; +} + +// ---- getHistoName ---- +std::string CbmTrdUnpackMonitor::getHistoName(eOtherHistos kHisto) +{ + std::string histoname = "Other_"; + + switch (kHisto) { + case eOtherHistos::kSpadic_Info_Types: histoname += "Spadic_Info_Types"; break; + case eOtherHistos::kMs_Flags: histoname += "Ms_Flags"; break; + default: return ""; break; + } + return histoname; +} + +// ---- getHistoType ---- +std::string CbmTrdUnpackMonitor::getHistoType(std::shared_ptr<TH1> histo) +{ + std::string histoname = histo->GetName(); + // The type follows on the module id separated by the first occurance of "-" + auto startpos = histoname.find_first_of("-"); + // Now we are positioned at "-" so we move one further to get the correct place + startpos++; + // Extract the type from the rest of the string + auto length = histoname.find_first_of("_", startpos) - startpos; + auto histotype = histoname.substr(startpos, length); + + return histotype; +} + +// ---- getRowAndCol ---- +std::pair<std::uint32_t, std::uint32_t> CbmTrdUnpackMonitor::getRowAndCol(std::uint32_t moduleid, + std::uint32_t channelid) +{ + // Check if we have to rotate the address, is true in case of 180(2) or 270(3) degree rotation + bool doRotate = fModuleOrientation.find(moduleid)->second / 2; + bool isYsensitive = fModuleOrientation.find(moduleid)->second % 2; + auto nrows = static_cast<std::uint32_t>(fModuleNrRows.find(moduleid)->second); + auto ncols = static_cast<std::uint32_t>(fModuleNrColumns.find(moduleid)->second); + + // Potentially rotate the address + std::uint32_t rotatedid = doRotate ? (channelid * (-1) + (nrows * ncols) - 1) : channelid; + + auto row = rotatedid / ncols; + auto col = rotatedid % ncols; + + // In case we have a chamber with the columns along x we return row,col + if (!isYsensitive) return std::make_pair(row, col); + else + // In case we have a chamber with the columns along y we return col,row + return std::make_pair(col, row); +} + +// ---- getSamplesStdDev ---- +std::float_t CbmTrdUnpackMonitor::getSamplesStdDev(CbmTrdRawMessageSpadic* raw) +{ + std::float_t sum = std::accumulate(raw->GetSamples()->begin(), raw->GetSamples()->end(), 0); + + std::float_t mean = sum / raw->GetNrSamples(); + + std::float_t dev = 0; + + for (auto sample : *raw->GetSamples()) { + dev += (sample - mean) * (sample - mean); + } + return std::sqrt(1.0 / raw->GetNrSamples() * dev); +} + +ClassImp(CbmTrdUnpackMonitor) diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackMonitor.h b/reco/detectors/trd/unpack/CbmTrdUnpackMonitor.h new file mode 100644 index 0000000000000000000000000000000000000000..ddca97906e7b99db55ded442c3e29ed8bdb0c743 --- /dev/null +++ b/reco/detectors/trd/unpack/CbmTrdUnpackMonitor.h @@ -0,0 +1,300 @@ +/* Copyright (C) 2010 - 2021 Goethe-University Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pascal Raisig */ + +/** + * @file CbmTrdUnpackMonitor.h + * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de) + * @brief Monitor class to monitor the data from the Trd unpacker algorithms + * @version 0.1 + * @date 2021-04-21 + * + * @copyright Copyright (c) 2021 + * + * This class can be attached to an unpacker algorithm class. It will than take the + * CbmTrdDigi and CbmTrdRawMessageSpadic object to fill predefined histograms with the + * given information. + * + * +*/ + +#ifndef CbmTrdUnpackMonitor_H +#define CbmTrdUnpackMonitor_H + +#include "CbmTrdDigi.h" +#include "CbmTrdParSetDigi.h" +#include "CbmTrdRawMessageSpadic.h" +#include "CbmTrdSpadic.h" + +#include <MicrosliceDescriptor.hpp> +#include <Timeslice.hpp> + +#include <FairRunOnline.h> +#include <FairTask.h> + +#include <Rtypes.h> // for types +#include <RtypesCore.h> +#include <TH1.h> +#include <THttpServer.h> // for histogram server + +#include <cstdint> +#include <map> +#include <memory> +#include <vector> + +#include <cmath> + +class CbmTrdUnpackMonitor { +public: + /** @brief Enum for the predefined digi histograms. */ + enum class eDigiHistos : size_t + { + kMap = 0, + kMap_St, + kMap_Nt, + kCharge, + kCharge_St, + kCharge_Nt, + kTriggerType, + kDigiDeltaT, + // kDigiMeanHitFrequency, // Heavy histogram add with care + // kDigiHitFrequency, + }; + + /** @brief Enum for the predefined raw histograms. */ + enum class eRawHistos : size_t + { + kSignalshape = 0, + kSignalshape_St, + kSignalshape_Nt, + kMap, + kMap_St, + kMap_Nt, + kElinkId, + kSampleDistStdDev, + kSample0perChannel, + kHitType, + }; + + /** @brief Enum for the predefined other histograms. */ + enum class eOtherHistos : size_t + { + kSpadic_Info_Types = 0, + kMs_Flags + }; + + /** @brief Create the Cbm Trd Unpack AlgoBase object */ + CbmTrdUnpackMonitor(/* args */); + + /** @brief Destroy the Cbm Trd Unpack Task object */ + virtual ~CbmTrdUnpackMonitor(); + + /** @brief Copy constructor - not implemented **/ + CbmTrdUnpackMonitor(const CbmTrdUnpackMonitor&) = delete; + + /** @brief Assignment operator - not implemented **/ + CbmTrdUnpackMonitor& operator=(const CbmTrdUnpackMonitor&) = delete; + + /** @brief fill the stored digi histograms @param digi pointer to the digi @param raw pointer to the raw msg */ + void FillHistos(CbmTrdDigi* digi, CbmTrdRawMessageSpadic* raw = nullptr); + + /** + * @brief Fill the given histo with the information on the info type + * @param[in] type Spadic::MsInfoType + * @param[in] moduleid unique CbmAddress moduleid + */ + void FillHisto(Spadic::MsInfoType type, std::uint32_t moduleid); + + /** + * @brief Fill the given histo with the information on the flag + * @param[in] flag fles::MicrosliceFlags + * @param[in] moduleid unique CbmAddress moduleid + */ + void FillHisto(fles::MicrosliceFlags flag, std::uint32_t moduleid); + + /** @brief Actions at the end of the run, e.g. write histos to file if flag is set. */ + void Finish(); + + // Runtime functions + /** @brief Init all required parameter informations */ + Bool_t Init(CbmTrdParSetDigi* digiParSet); + + /** @brief transfer the enums for the histos to be activated to the member vector */ + void SetActiveHistos(std::vector<eDigiHistos> vec) { fActiveDigiHistos.swap(vec); } + + /** @brief transfer the enums for the histos to be activated to the member vector */ + void SetActiveHistos(std::vector<eRawHistos> vec) { fActiveRawHistos.swap(vec); } + + /** @brief transfer the enums for the histos to be activated to the member vector */ + void SetActiveHistos(std::vector<eOtherHistos> vec) { fActiveOtherHistos.swap(vec); } + + /** @brief Set the Spadic Object @param value */ + void SetSpadicObject(std::shared_ptr<CbmTrdSpadic> value) { fSpadic = value; } + + /** @brief Set the output filename, automatically also sets the flag to create an output file. @param filename Absolute path for the output file */ + void SetWriteToFile(std::string filename) + { + fOutfilename = filename; + fDoWriteToFile = true; + } + + +protected: + template<class histotype> + void addHistoToMap(std::shared_ptr<TH1> histo, + std::map<histotype, std::map<std::uint32_t, std::shared_ptr<TH1>>>* histomap, + std::uint32_t moduleid, histotype kHisto) + { + // Store the histo pointer in the global histos vec + { + auto histopair = std::make_pair(std::to_string(moduleid), histo); + fHistoVec.emplace_back(histopair); + } + + // Create a histo module pair + auto histopair = std::make_pair(moduleid, histo); + + // Check if already have a histo map for the histo category + auto histomapIt = histomap->find(kHisto); + if (histomapIt == histomap->end()) { + // There is no map yet for the given histogram category + std::map<std::uint32_t, std::shared_ptr<TH1>> newmap = {}; + newmap.emplace(histopair); + // Create a pair with the map and the histogram category + auto pair = std::make_pair(kHisto, newmap); + // And put it to the digi histo map + histomap->emplace(pair); + } + else { + // We found a map where we can put the histopair into + histomapIt->second.emplace(histopair); + } + // And finally if we have HttpServer we pass the histogram pointer to it + if (fHistoServer) { + + std::string directory = std::to_string(moduleid) + "/" + getHistoType(histo) + "/"; + fHistoServer->Register(directory.data(), histo.get()); + } + } + + + /** @brief Create the actual TH1 shared_ptrs */ + void createHistos(); + + /** @brief Create the actual TH1 shared_ptrs of the Digi histos */ + void createHisto(eDigiHistos kHisto); + + /** @brief Create the actual TH1 shared_ptrs of the Raw histos */ + void createHisto(eRawHistos kHisto); + + /** @brief Create the actual TH1 shared_ptrs of the Others histos */ + void createHisto(eOtherHistos kHisto); + + /** + * @brief Fill the given histo with the information from the digi + * + * @param[in] digi CbmTrdDigi + * @param[in] kHisto Histo definition + * @param[in] moduleid Unique module Id from which the digi came + * @param[out] histo pointer to the histo (we do not want to extract it a snd time from the map) + */ + void fillHisto(CbmTrdDigi* digi, eDigiHistos kHisto, std::uint32_t moduleid, std::shared_ptr<TH1> histo); + + /** + * @brief Fill the given histo with the information from the raw message + * + * @param[in] raw CbmTrdRawMessageSpadic + * @param[in] kHisto Histo definition + * @param[out] histo pointer to the histo (we do not want to extract it a snd time from the map) + */ + void fillHisto(CbmTrdRawMessageSpadic* raw, eRawHistos kHisto, std::shared_ptr<TH1> histo, CbmTrdDigi* digi); + + /** + * @brief Fill the passed histo with the samples as function of time + * + * @param histo + * @param raw + */ + void fillSamplesHisto(std::shared_ptr<TH1> histo, CbmTrdRawMessageSpadic* raw); + + /** @brief Get the time difference between this digi and the previous one from the channel of this digi @param digi CbmTrdDigi @return delta t [ns]*/ + std::double_t getDeltaT(CbmTrdDigi* digi); + + /** @brief Get the Histo Name for the given histo @param kHisto eDigiHistos @return std::string */ + std::string getHistoName(eDigiHistos kHisto); + + /** @brief Get the Histo Name for the given histo @param kHisto eRawHistos @return std::string */ + std::string getHistoName(eRawHistos kHisto); + + /** @brief Get the Histo Name for the given histo @param kHisto eOtherHistos @return std::string */ + std::string getHistoName(eOtherHistos kHisto); + + /** @brief Get the Histo Type, i.e. "Digi/Raw/Other", deduced from the histo name. @param histo @return std::string */ + std::string getHistoType(std::shared_ptr<TH1> histo); + + /** + * @brief Get the row and column ids (potentially rotated chambers are adjusted to humand readable rotations) + * + * @param moduleid + * @param channelid + * @return std::pair<std::uint32_t, std::uint32_t> {row,col} + */ + std::pair<std::uint32_t, std::uint32_t> getRowAndCol(std::uint32_t moduleid, std::uint32_t channelid); + + /** @brief Extract the std deviation of all samples in the message */ + std::float_t getSamplesStdDev(CbmTrdRawMessageSpadic* raw); + + /** @brief histogram pointers (all) stored in a vector to be accessible for THttpServer */ + std::vector<std::pair<std::string, std::shared_ptr<TH1>>> fHistoVec = {}; + + /** @brief Digi histogram pointers stored in a map together with the module id */ + std::map<eDigiHistos, std::map<std::uint32_t, std::shared_ptr<TH1>>> fDigiHistoMap = {}; + + /** @brief Raw histogram pointers stored in a map together with the module id */ + std::map<eRawHistos, std::map<std::uint32_t, std::shared_ptr<TH1>>> fRawHistoMap = {}; + + /** @brief Other histogram pointers stored in a map together with the module id */ + std::map<eOtherHistos, std::map<std::uint32_t, std::shared_ptr<TH1>>> fOtherHistoMap = {}; + + /** @brief Enums of Digi histos to be activated */ + std::vector<eDigiHistos> fActiveDigiHistos = {}; + + /** @brief Enums of Raw histos to be activated */ + std::vector<eRawHistos> fActiveRawHistos = {}; + + /** @brief Enums of Raw histos to be activated */ + std::vector<eOtherHistos> fActiveOtherHistos = {}; + + /** @brief Pointer to the histogram server, in case we run the online monitoring, the pointer is automatically deduced from the run. */ + THttpServer* fHistoServer = nullptr; + + /** @brief Flag whether to write histos to file or not, gets activated if a output filename gets set. */ + bool fDoWriteToFile = false; + + /** @brief File name for the output file */ + std::string fOutfilename = ""; + + // ---- TRD parameters ---- + /** @brief Vector with the unique module Ids */ + std::vector<std::uint32_t> fModuleIdsVec = {}; + + /** @brief Map with the orientations of the modules. Performance helper to not go through the extraction from ParModDigi everytime */ + std::map<std::uint32_t, std::uint8_t> fModuleOrientation = {}; + + /** @brief Map with the number of rows of the modules. Performance helper to not go through the extraction from ParModDigi everytime */ + std::map<std::uint32_t, std::uint8_t> fModuleNrRows = {}; + + /** @brief Map with the number of columns of the modules. Performance helper to not go through the extraction from ParModDigi everytime */ + std::map<std::uint32_t, std::uint8_t> fModuleNrColumns = {}; + + /** @brief Map with the last digi time for each channel of a given module */ + std::map<std::uint32_t, std::vector<size_t>> fLastDigiTimeMap = {}; + + // All other parameters and containers + std::shared_ptr<CbmTrdSpadic> fSpadic = nullptr; + +private: + ClassDef(CbmTrdUnpackMonitor, 2) +}; + +#endif // CbmTrdUnpackMonitor_H diff --git a/reco/steer/CMakeLists.txt b/reco/steer/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..30157e8112d876b7b964f467f18709c2a1ab8e70 --- /dev/null +++ b/reco/steer/CMakeLists.txt @@ -0,0 +1,76 @@ +# CMakeList file for library CbmRecoSteer +# V. Friese, 2 June 2021 + + + +# ----- Library name ---------------------------------- +Set(LIBRARY_NAME CbmRecoSteer) +# --------------------------------------------------------- + +# ----- Compilation sources ---------------------------- +set(SRCS +CbmRecoUnpack.cxx +CbmSourceTsArchive.cxx +) +# --------------------------------------------------------- + + + +# ---- Include directories ------------------------------- +set(INCLUDE_DIRECTORIES +${CBMROOT_SOURCE_DIR}/reco/steer +${CBMROOT_SOURCE_DIR}/reco/base +${CBMROOT_SOURCE_DIR}/reco/detectors/trd +${CBMROOT_SOURCE_DIR}/reco/detectors/trd/rawToDigiMethods +${CBMROOT_SOURCE_DIR}/reco/detectors/trd/unpack + +${CBMROOT_SOURCE_DIR}/core/base +${CBMROOT_SOURCE_DIR}/core/data +${CBMROOT_SOURCE_DIR}/core/data/base +${CBMROOT_SOURCE_DIR}/core/data/trd +${CBMROOT_SOURCE_DIR}/core/detectors/trd +${CBMROOT_SOURCE_DIR}/core/data/sts + + +) + +set(SYSTEM_INCLUDE_DIRECTORIES +${BASE_INCLUDE_DIRECTORIES} +${IPC_INCLUDE_DIRECTORY} +) +# --------------------------------------------------------- + + + +# ---- Link directories ---------------------------------- +set(LINK_DIRECTORIES +${ROOT_LIBRARY_DIR} +${FAIRROOT_LIBRARY_DIR} +${Boost_LIBRARY_DIRS} +) +# --------------------------------------------------------- + + + +# ----- Library dependences --------------------------- +Set(DEPENDENCIES +fles_ipc +Base +CbmBase +CbmTrdReco +CbmData +) +# --------------------------------------------------------- + + +# ----- LinkDef file ----------------------------------- +set(LINKDEF ${LIBRARY_NAME}LinkDef.h) +# --------------------------------------------------------- + + +# ----- Let cmake do the job --------------------------- +include_directories( ${INCLUDE_DIRECTORIES}) +include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES}) +link_directories( ${LINK_DIRECTORIES}) +GENERATE_LIBRARY() +# --------------------------------------------------------- diff --git a/reco/steer/CbmRecoSteerLinkDef.h b/reco/steer/CbmRecoSteerLinkDef.h new file mode 100644 index 0000000000000000000000000000000000000000..7a366acb4acce1a7e55b234cc06b03e1b098adda --- /dev/null +++ b/reco/steer/CbmRecoSteerLinkDef.h @@ -0,0 +1,16 @@ +/** @file CbmRecoSteerLinkDef.h + * @copyright Copyright (C) 2020 Facility for Antiproton and Ion Research in Europe, Darmstadt + * @license SPDX-License-Identifier: GPL-3.0-only + * @authors Volker Friese [originator] **/ + +#ifdef __CINT__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +// --- Classes +#pragma link C++ class CbmRecoUnpack + ; +#pragma link C++ class CbmSourceTsArchive + ; + +#endif /* __CINT__ */ diff --git a/reco/steer/CbmRecoUnpack.cxx b/reco/steer/CbmRecoUnpack.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f47821f3709fe3dc2acb704075b2272704b0a903 --- /dev/null +++ b/reco/steer/CbmRecoUnpack.cxx @@ -0,0 +1,96 @@ +/** @file CbmRecoUnpack.cxx + ** @copyright Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + ** @license SPDX-License-Identifier: GPL-3.0-only + ** @author Volker Friese [originator] + **/ + + +#include "CbmRecoUnpack.h" + +#include "MicrosliceDescriptor.hpp" + +#include <FairRootManager.h> +#include <Logger.h> + +#include <utility> +#include <vector> + + +using fles::Timeslice; +using std::unique_ptr; + + +// ----- Constructor ------------------------------------------------------ +CbmRecoUnpack::CbmRecoUnpack() {} +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- + + +// ----- Initialisation --------------------------------------------------- +void CbmRecoUnpack::Finish() +{ + LOG(info) << "CbmRecoUnpack::Finish() I do let the unpackers talk first : "; + fTrdConfig->GetUnpacker()->Finish(); +} + +// ---------------------------------------------------------------------------- + +// ----- Initialisation --------------------------------------------------- +Bool_t CbmRecoUnpack::Init() +{ + + FairRootManager* ioman = FairRootManager::Instance(); + assert(ioman); + + // --- TRD + fTrdConfig->Init(ioman); + fTrdConfig->InitUnpacker(); + + return kTRUE; +} +// ---------------------------------------------------------------------------- + + +// ----- Reset ------------------------------------------------------------ +void CbmRecoUnpack::Reset() +{ + // Reset the unpackers for a new timeslice, e.g. clear the output vectors + + // ---- Trd ---- + fTrdConfig->Reset(); +} + +// ---------------------------------------------------------------------------- + +// ----- Unpacking -------------------------------------------------------- +void CbmRecoUnpack::Unpack(unique_ptr<Timeslice> ts) +{ + // Prepare timeslice + const fles::Timeslice& timeslice = *ts; + + uint64_t nComponents = ts->num_components(); + LOG(info) << "Unpack: TS index " << ts->index() << " components " << nComponents; + + for (uint64_t component = 0; component < nComponents; component++) { + + auto systemId = static_cast<std::uint16_t>(ts->descriptor(component, 0).sys_id); + + switch (systemId) { + case fkFlesTrd: { + if (fTrdConfig) + unpack(×lice, component, fTrdConfig, fTrdConfig->GetOptOutAVec(), fTrdConfig->GetOptOutBVec()); + break; + }; + + default: { + if (fDoDebugPrints) LOG(error) << "Unpack: Unknown system ID " << systemId << " for component " << component; + break; + } + } + } +} +// ---------------------------------------------------------------------------- + + +ClassImp(CbmRecoUnpack) diff --git a/reco/steer/CbmRecoUnpack.h b/reco/steer/CbmRecoUnpack.h new file mode 100644 index 0000000000000000000000000000000000000000..bbb18779303e700b2f19601e630ce78ca6e9ad6c --- /dev/null +++ b/reco/steer/CbmRecoUnpack.h @@ -0,0 +1,174 @@ +/** @file CbmRecoUnpack.h + ** @copyright Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + ** @license SPDX-License-Identifier: GPL-3.0-only + ** @author Volker Friese, Pascal Raisig + **/ + + +#ifndef CBMRECOUNPACK_H +#define CBMRECOUNPACK_H 1 + +#include "CbmTrdUnpackConfig.h" + +#include <MicrosliceDescriptor.hpp> +#include <Timeslice.hpp> + +#include <TObject.h> +#include <type_traits> // this is std::lib used for template is_member_function_pointer + +#include <cstddef> +#include <memory> +#include <vector> + + +/** @class CbmRecoUnpack + ** @brief Main steering class for unpacking in cbmroot + ** @author Volker Friese + ** @since 2 June 2021 + ** + ** This class runs the unpackers for each input time-slice component. + **/ +class CbmRecoUnpack : public TObject { + +public: + /** @brief Constructor + ** @param fileName Name of (single) input file. + ** + ** More input files can be added by the method AddInputFile. + */ + CbmRecoUnpack(); + + + /** @brief Destructor **/ + ~CbmRecoUnpack() {}; + + /** @brief Copy constructor - not implemented **/ + CbmRecoUnpack(const CbmRecoUnpack&) = delete; + + /** @brief Assignment operator - not implemented **/ + CbmRecoUnpack& operator=(const CbmRecoUnpack&) = delete; + + /** @brief Actions at the end of the run **/ + void Finish(); + + /** @brief Initialisation **/ + Bool_t Init(); + + /** @brief Clear the output vectors as preparation of the next timeslice. Called via FairSource::Reset() */ + void Reset(); + + /** + * @brief Set the Debug Printout Flag + * + * @param value + */ + void SetDebugPrintout(bool value = true) { fDoDebugPrints = value; } + + /** + * @brief Set the Trd Unpack Config + * + * @param config + */ + void SetUnpackConfig(std::shared_ptr<CbmTrdUnpackConfig> config) { fTrdConfig = config; } + + /** @brief Trigger the unpacking procedure **/ + void Unpack(std::unique_ptr<fles::Timeslice> ts); + +private: + static constexpr std::uint16_t fkFlesMvd = static_cast<std::uint16_t>(fles::SubsystemIdentifier::MVD); + static constexpr std::uint16_t fkFlesSts = static_cast<std::uint16_t>(fles::SubsystemIdentifier::STS); + static constexpr std::uint16_t fkFlesRich = static_cast<std::uint16_t>(fles::SubsystemIdentifier::RICH); + static constexpr std::uint16_t fkFlesMuch = static_cast<std::uint16_t>(fles::SubsystemIdentifier::MUCH); + static constexpr std::uint16_t fkFlesTrd = static_cast<std::uint16_t>(fles::SubsystemIdentifier::TRD); + static constexpr std::uint16_t fkFlesTof = static_cast<std::uint16_t>(fles::SubsystemIdentifier::RPC); + static constexpr std::uint16_t fkFlesPsd = static_cast<std::uint16_t>(fles::SubsystemIdentifier::PSD); + + /** @brief Flag if extended debug output is to be printed or not*/ + bool fDoDebugPrints = false; + + /** @brief Sort a vector timewise vector type has to provide GetTime() */ + template<typename TVecobj> + typename std::enable_if<std::is_member_function_pointer<decltype(&TVecobj::GetTime)>::value, void>::type + timesort(std::vector<TVecobj>* vec = nullptr) + { + if (vec == nullptr) return; + std::sort(vec->begin(), vec->end(), + [](const TVecobj& a, const TVecobj& b) -> bool { return a.GetTime() < b.GetTime(); }); + } + + template<typename TVecobj> + typename std::enable_if<!std::is_member_function_pointer<decltype(&TVecobj::GetTime)>::value, void>::type + timesort(std::vector<TVecobj>* /*vec = nullptr*/) + { + LOG(debug) << "CbmRecoUnpack::timesort() object " << TVecobj::Class_Name() + << " has no member function GetTime(). Hence, we can and will not timesort it!"; + } + + /** + * @brief Template for the unpacking call of a given algorithm. + * + * @tparam TAlgo Algorithm to be called + * @tparam TOutput Output element types + * @tparam TOptoutputs Optional output element types + * @param ts Timeslice + * @param icomp Component number + * @param algo Algorithm to be used for this component + * @param outtargetvec Target vector for the output elements + * @param optoutputvecs Target vectors for optional outputs + */ + template<class TConfig, class TOptOutA = std::nullptr_t, class TOptOutB = std::nullptr_t> + void unpack(const fles::Timeslice* ts, std::uint16_t icomp, TConfig config, + std::vector<TOptOutA>* optouttargetvecA = nullptr, std::vector<TOptOutB>* optouttargetvecB = nullptr) + { + auto algo = config->GetUnpacker(); + std::vector<TOptOutA> optoutAvec = {}; + std::vector<TOptOutB> optoutBvec = {}; + if (optouttargetvecA) { algo->SetOptOutAVec(&optoutAvec); } + if (optouttargetvecB) { algo->SetOptOutBVec(&optoutBvec); } + + // Run the actual unpacking + auto digivec = algo->Unpack(ts, icomp); + + // Check if we want to write the output to somewhere (in pure online monitoring mode for example this can/would/should be skipped) + if (config->GetOutputVec()) { + // Lets do some timesorting + timesort(&digivec); + + // Transfer the data from the timeslice vector to the target branch vector + // Digis/default output retrieved as offered by the algorithm + for (auto digi : digivec) + config->GetOutputVec()->emplace_back(digi); + } + if (optouttargetvecA) { + // Lets do some timesorting + timesort(&optoutAvec); + // Transfer the data from the timeslice vector to the target branch vector + for (auto optoutA : optoutAvec) + optouttargetvecA->emplace_back(optoutA); + } + if (optouttargetvecB) { + // Second opt output is not time sorted to allow non GetTime data container. + // Transfer the data from the timeslice vector to the target branch vector + for (auto optoutB : optoutBvec) + optouttargetvecB->emplace_back(optoutB); + } + + + // Check some numbers from this timeslice + size_t nDigis = digivec.size(); + + LOG(info) << "Component " << icomp << " connected to config " << config->GetName() << " n-Digis " << nDigis + << " processed in this timeslice."; + } + // ---------------------------------------------------------------------------- + + + /** @brief Configuration of the Trd unpacker. Provides the configured algorithm */ + std::shared_ptr<CbmTrdUnpackConfig> fTrdConfig = nullptr; //! + + + ClassDef(CbmRecoUnpack, 1); +}; + + +#endif diff --git a/reco/steer/CbmSourceTsArchive.cxx b/reco/steer/CbmSourceTsArchive.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6018c4e166f232f1c89ce46ab0c73c11bec09a0d --- /dev/null +++ b/reco/steer/CbmSourceTsArchive.cxx @@ -0,0 +1,125 @@ +/** @file CbmSourceTsArchive.cxx + ** @copyright Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + ** @license SPDX-License-Identifier: GPL-3.0-only + ** @author Volker Friese [originator] + **/ + + +#include "CbmSourceTsArchive.h" + +#include <TimesliceMultiInputArchive.hpp> +#include <TimesliceMultiSubscriber.hpp> + +#include <FairSource.h> +#include <Logger.h> + + +using fles::Timeslice; +using std::string; +using std::unique_ptr; + + +// ----- Constructor ------------------------------------------------------ +CbmSourceTsArchive::CbmSourceTsArchive(const char* fileName) { AddInputFile(fileName); } +// ---------------------------------------------------------------------------- + + +// ----- Add an input file ------------------------------------------------ +size_t CbmSourceTsArchive::AddInputFile(const char* fileName) +{ + string sFile(fileName); + if (sFile.size()) fFileNames.push_back(sFile); + return fFileNames.size(); +} +// ---------------------------------------------------------------------------- + + +// ----- Close ----------------------------------------------------------- +void CbmSourceTsArchive::Close() +{ + LOG(info) << "SourceTsArchive::Close() Let's hear some famous last words: "; + fUnpack.Finish(); +} +// ---------------------------------------------------------------------------- + + +// ----- Initialisation --------------------------------------------------- +Bool_t CbmSourceTsArchive::Init() +{ + + switch (fSourceType) { + case Source_Type::kONLINE: { + // Create a ";" separated string with all host/port combinations + // Build a semicolon-separated list of file names for TimesliceMultiInputArchive + string fileList; + for (const auto& fileName : fFileNames) { + fileList += fileName; + fileList += ";"; + } + fileList.pop_back(); // Remove last semicolon after last file name + + fTsSource = new fles::TimesliceMultiSubscriber(fileList, fHighWaterMark); + + /// Initialize the Multisubscriber + /// (This restores the original behavior after modifications needed to make the MQ version + dynamic_cast<fles::TimesliceMultiSubscriber*>(fTsSource)->InitTimesliceSubscriber(); + + if (!fTsSource) { + LOG(fatal) << "Could not connect to the TS publisher."; + return kFALSE; + } + break; + } + case Source_Type::kFILE: { + // Return error for empty file list and an offline run + if (fFileNames.empty()) return kFALSE; + + + // Build a semicolon-separated list of file names for TimesliceMultiInputArchive + string fileList; + for (const auto& fileName : fFileNames) { + fileList += fileName; + fileList += ";"; + } + fileList.pop_back(); // Remove last semicolon after last file name + + // Create the proper TS source + fTsSource = new fles::TimesliceMultiInputArchive(fileList); + if (!fTsSource) { + LOG(error) << "SourceTsArchive: Failed to create TSMultiInputArchive!"; + return kFALSE; + } + break; + } + } + // Initialise unpacker + fUnpack.Init(); + LOG(info) << "Source: Init done"; + return kTRUE; +} +// ---------------------------------------------------------------------------- + + +// ----- Read one time slice from archive --------------------------------- +Int_t CbmSourceTsArchive::ReadEvent(UInt_t) +{ + + unique_ptr<Timeslice> ts; + ts = fTsSource->get(); + + if (!ts) { + LOG(info) << "SourceTsArchive: End of archive reached; stopping run."; + return 1; + } + LOG(info) << "SourceTsArchive: Reading time slice " << fTsCounter << " (index " << ts->index() << ")"; + + fUnpack.Unpack(std::move(ts)); + + + fTsCounter++; + return 0; +} +// ---------------------------------------------------------------------------- + + +ClassImp(CbmSourceTsArchive) diff --git a/reco/steer/CbmSourceTsArchive.h b/reco/steer/CbmSourceTsArchive.h new file mode 100644 index 0000000000000000000000000000000000000000..8a835eb0663068d0d4e2d2a392b58b8f746d8717 --- /dev/null +++ b/reco/steer/CbmSourceTsArchive.h @@ -0,0 +1,127 @@ +/** @file CbmSourceTsArchive.h + ** @copyright Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + ** @license SPDX-License-Identifier: GPL-3.0-only + ** @author Volker Friese [originator] + **/ + + +#ifndef CBMSOURCETSARCHIVE_H +#define CBMSOURCETSARCHIVE_H 1 + +#include "CbmRecoUnpack.h" + +#include <TimesliceSource.hpp> + +#include <FairSource.h> + +#include <cstdint> +#include <string> + + +/** @class CbmSourceTsArchive + ** @brief Source class for reading from archived time slice data + ** @author Volker Friese + ** @since 2 June 2021 + ** + ** This class allows to read time-slice data from file(s) and hands them to + ** the unpacking stage. It interfaces fles::TimesliceMultiInputArchive to cbmroot. + **/ +class CbmSourceTsArchive : public FairSource { + +public: + /** @brief Constructor + ** @param fileName Name of (single) input file. + ** + ** More input files can be added by the method AddInputFile. + */ + CbmSourceTsArchive(const char* fileName = ""); + + + /** @brief Destructor **/ + virtual ~CbmSourceTsArchive() {}; + + + /** @brief Copy constructor - not implemented **/ + CbmSourceTsArchive(const CbmSourceTsArchive&) = delete; + + /** @brief Assignment operator - not implemented **/ + CbmSourceTsArchive& operator=(const CbmSourceTsArchive&) = delete; + + + /** @brief Add an input file + ** @param fileName Input file name + ** @return Number of input files after adding this one + **/ + size_t AddInputFile(const char* fileName); + + + /** @brief Close source after end of run **/ + virtual void Close(); + + + /** @brief Source type + ** @return kFILE + **/ + virtual Source_Type GetSourceType() { return fSourceType; } + + /** + * @brief Get the Reco Unpack + * Access the CbmRecoUnpack class to add unpacker configs + * @return CbmRecoUnpack* + */ + CbmRecoUnpack* GetRecoUnpack() { return &fUnpack; } + + + /** @brief Initialisation **/ + virtual Bool_t Init(); + + + /** @brief Initialise unpackers (forced by base class) **/ + virtual Bool_t InitUnpackers() { return kTRUE; } + + + /** @brief Read one time slice from file **/ + Int_t ReadEvent(UInt_t = 0); + + + /** @brief Re-Initialise unpackers (forced by base class) **/ + virtual Bool_t ReInitUnpackers() { return kTRUE; } + + + /** @brief Reset clear the output vectors as preparation for the next timeslice. Forwarded to CbmRecoUnpack **/ + virtual void Reset() { fUnpack.Reset(); } + + /** @brief Set the high water mark (limit of buffered timeslice by the publisher) */ + void SetHighWaterMark(std::uint32_t value) { fHighWaterMark = value; } + + /** @brief Set unpacker parameters (forced by base class) **/ + virtual void SetParUnpackers() {} + + /** @brief Set the Source Type @param type */ + void SetSourceType(Source_Type type) { fSourceType = type; } + +private: + /** List of input file names **/ + std::vector<std::string> fFileNames = {}; + + /** @brief Amount of Timeslices buffered before the publisher starts dropping new ones, if the old are not digested yet.*/ + std::uint32_t fHighWaterMark = 1; + + /** @brief type of source that is currently used */ + Source_Type fSourceType = Source_Type::kFILE; + + /** Time-slice source interface **/ + fles::TimesliceSource* fTsSource = nullptr; //! + + /** Time-slice counter **/ + ULong64_t fTsCounter = 0; + + /** Unpack steering class **/ + CbmRecoUnpack fUnpack = {}; + + + ClassDef(CbmSourceTsArchive, 1) +}; + + +#endif diff --git a/sim/detectors/trd/CbmTrdModuleSimR.cxx b/sim/detectors/trd/CbmTrdModuleSimR.cxx index 8d058fd16b9ffe435a0ce0e0f0b7e18a3b949b52..b0adf877df99fff4cb95fc842285ac90212246aa 100644 --- a/sim/detectors/trd/CbmTrdModuleSimR.cxx +++ b/sim/detectors/trd/CbmTrdModuleSimR.cxx @@ -144,7 +144,11 @@ void CbmTrdModuleSimR::AddDigi(Int_t address, Double_t charge, Double_t /*charge digiMatch->AddLink(CbmLink(weighting, fPointId, fEventId, fInputId)); AddNoise(charge); - CbmTrdDigi* digi = new CbmTrdDigi(channel, fModAddress, charge * 1e6, ULong64_t(time), 0, 0); + CbmTrdDigi::eTriggerType triggertype = CbmTrdDigi::eTriggerType::kNTrg; + if (trigger == 1) triggertype = CbmTrdDigi::eTriggerType::kSelf; + if (trigger == 2) triggertype = CbmTrdDigi::eTriggerType::kNeighbor; + + CbmTrdDigi* digi = new CbmTrdDigi(channel, fModAddress, charge * 1e6, ULong64_t(time), triggertype, 0); digi->SetFlag(0, true); if (fDigiPar->GetPadSizeY(sec) == 1.5) digi->SetErrorClass(1); @@ -156,8 +160,6 @@ void CbmTrdModuleSimR::AddDigi(Int_t address, Double_t charge, Double_t /*charge it = fDigiMap.find(address); // it->second.first->SetAddressModule(fModAddress);//module); <- now handled in the digi contructor - if (trigger == 1) it->second.first->SetTriggerType(CbmTrdDigi::kSelf); - if (trigger == 2) it->second.first->SetTriggerType(CbmTrdDigi::kNeighbor); } else { it->second.first->AddCharge(charge * 1e6); @@ -240,10 +242,8 @@ void CbmTrdModuleSimR::ProcessPulseBuffer(Int_t address, Bool_t FNcall, Bool_t M Float_t shift = fMessageConverter->GetTimeShift(temp); Float_t corr = fMinDrift; //correction of average sampling to clock difference and systematic average drift time - if (!CbmTrdDigitizer::IsTimeBased()) - corr = CbmTrdDigi::Clk( - CbmTrdDigi:: - kSPADIC); //correction for EB case is done later, due to the event time 0 and the unsigned data member for the time in the digi + if (!CbmTrdDigitizer::IsTimeBased()) corr = CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC); + //correction for EB case is done later, due to the event time 0 and the unsigned data member for the time in the digi if (fTimeSlice) { if (fTimeBuffer[address] + corr - shift < fTimeSlice->GetStartTime()) { @@ -268,7 +268,7 @@ void CbmTrdModuleSimR::ProcessPulseBuffer(Int_t address, Bool_t FNcall, Bool_t M if (!CbmTrdDigitizer::IsTimeBased()) digi->SetFlag(1, true); Int_t shiftcut = fShiftQA[address] * 10; - Float_t timeshift = shiftcut / 10; + Float_t timeshift = shiftcut / 10.0; if (temp[fMinBin] == fClipLevel - 1 && temp[fMaxBin] == fClipLevel - 1) digi->SetCharge(35.); std::vector<CbmLink> links = fPulseBuffer[address].second->GetLinks(); @@ -375,9 +375,9 @@ void CbmTrdModuleSimR::ProcessPulseBuffer(Int_t address, Bool_t FNcall, Bool_t M // digi->SetAddressModule(fModAddress); Not required anymore, now handled in the digi c'tor - if (trigger == 1) { digi->SetTriggerType(CbmTrdDigi::kSelf); } - if (trigger == 0 && FNcall) { digi->SetTriggerType(CbmTrdDigi::kNeighbor); } - if (trigger == 1 && MultiCall) { digi->SetTriggerType(CbmTrdDigi::kMulti); } + if (trigger == 1) { digi->SetTriggerType(CbmTrdDigi::eTriggerType::kSelf); } + if (trigger == 0 && FNcall) { digi->SetTriggerType(CbmTrdDigi::eTriggerType::kNeighbor); } + if (trigger == 1 && MultiCall) { digi->SetTriggerType(CbmTrdDigi::eTriggerType::kMulti); } //digi->SetMatch(digiMatch); if (fDebug) { @@ -407,7 +407,7 @@ void CbmTrdModuleSimR::ProcessPulseBuffer(Int_t address, Bool_t FNcall, Bool_t M FNaddress = CbmTrdAddress::GetAddress(CbmTrdAddress::GetLayerId(address), CbmTrdAddress::GetModuleId(fModAddress), sec, row, col - 1); Double_t timediff = TMath::Abs(fTimeBuffer[address] - fTimeBuffer[FNaddress]); - if (FNaddress != 0 && timediff < CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)) + if (FNaddress != 0 && timediff < CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)) ProcessPulseBuffer(FNaddress, true, false, true, false); } @@ -417,7 +417,7 @@ void CbmTrdModuleSimR::ProcessPulseBuffer(Int_t address, Bool_t FNcall, Bool_t M FNaddress = CbmTrdAddress::GetAddress(CbmTrdAddress::GetLayerId(address), CbmTrdAddress::GetModuleId(address), sec, row, col + 1); Double_t timediff = TMath::Abs(fTimeBuffer[address] - fTimeBuffer[FNaddress]); - if (FNaddress != 0 && timediff < CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)) + if (FNaddress != 0 && timediff < CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)) ProcessPulseBuffer(FNaddress, true, false, false, true); } } @@ -479,12 +479,15 @@ void CbmTrdModuleSimR::AddDigitoBuffer(Int_t address, Double_t charge, Double_t channel += ncols * fDigiPar->GetNofRowsInSector(isec); channel += ncols * row + col; - // std::cout<<charge*1e6<<" "<<fTimeBuffer[address]/CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)<<std::endl; + auto triggertype = CbmTrdDigi::eTriggerType::kNTrg; + if (trigger == 1) triggertype = CbmTrdDigi::eTriggerType::kSelf; + if (trigger == 2) triggertype = CbmTrdDigi::eTriggerType::kNeighbor; + // std::cout<<charge*1e6<<" "<<fTimeBuffer[address]/CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)<<std::endl; CbmTrdDigi* digi = - new CbmTrdDigi(channel, fModAddress, charge * 1e6, ULong64_t(time / CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)), 0, 0); + new CbmTrdDigi(channel, fModAddress, charge * 1e6, + ULong64_t(time / CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)), triggertype, 0); + - if (trigger == 1) digi->SetTriggerType(CbmTrdDigi::kSelf); - if (trigger == 2) digi->SetTriggerType(CbmTrdDigi::kNeighbor); //digi->SetMatch(digiMatch); // printf("CbmTrdModuleSimR::AddDigitoBuffer(%10d)=%3d [%d] col[%3d] row[%d] sec[%d]\n", address, channel, fModAddress, col, row, sec); @@ -583,8 +586,9 @@ std::vector<Double_t> CbmTrdModuleSimR::MakePulse(Double_t charge, std::vector<D Double_t sample[32]; for (Int_t i = 0; i < 32; i++) sample[i] = 0; - // Double_t timeshift = gRandom->Uniform(0.,CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); - Double_t timeshift = ((Int_t)(fCurrentTime * 10) % (Int_t)(CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) * 10)) / 10; + // Double_t timeshift = gRandom->Uniform(0.,CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); + Double_t timeshift = + ((Int_t)(fCurrentTime * 10) % (Int_t)(CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) * 10)) / 10.0; if (fDebug) fQA->Fill("Shift", timeshift); // Int_t shift=timeshift; //fShiftQA[address]=shift; @@ -596,9 +600,10 @@ std::vector<Double_t> CbmTrdModuleSimR::MakePulse(Double_t charge, std::vector<D } if (fTimeShift) sample[i] = fCalibration * charge * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + timeshift); + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + timeshift); if (!fTimeShift) - sample[i] = fCalibration * charge * 1e6 * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + sample[i] = fCalibration * charge * 1e6 + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); if (sample[i] > fClipLevel && fClipping) sample[i] = fClipLevel - 1; //clipping } @@ -619,9 +624,10 @@ void CbmTrdModuleSimR::AddToPulse(Int_t address, Double_t charge, Double_t reldr std::vector<Double_t> temppulse; for (Int_t i = 0; i < 32; i++) temppulse.push_back(pulse[i]); - Double_t dt = fCurrentTime - fTimeBuffer[address]; - Int_t startbin = (dt + reldrift) / CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC); - Double_t timeshift = ((Int_t)((dt + reldrift) * 10) % (Int_t)(CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) * 10)) / 10; + Double_t dt = fCurrentTime - fTimeBuffer[address]; + Int_t startbin = (dt + reldrift) / CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC); + Double_t timeshift = + ((Int_t)((dt + reldrift) * 10) % (Int_t)(CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) * 10)) / 10.0; if (startbin > 31 || dt < 0.) return; if (fDebug) fMCQA[address] += charge * 1e6; @@ -631,7 +637,8 @@ void CbmTrdModuleSimR::AddToPulse(Int_t address, Double_t charge, Double_t reldr continue; } Int_t addtime = i - startbin - fPresamples; - pulse[i] += fCalibration * charge * 1e6 * CalcResponse(addtime * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + timeshift); + pulse[i] += fCalibration * charge * 1e6 + * CalcResponse(addtime * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + timeshift); if (pulse[i] > fClipLevel && fClipping) pulse[i] = fClipLevel - 1; //clipping } @@ -639,12 +646,12 @@ void CbmTrdModuleSimR::AddToPulse(Int_t address, Double_t charge, Double_t reldr // for(Int_t i=0;i<32;i++){ // if(i < fPresamples) continue; // if(fTimeShift){ - // Int_t sample = fCalibration*charge*1e6*CalcResponse((i-fPresamples)*CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)+timeshift); + // Int_t sample = fCalibration*charge*1e6*CalcResponse((i-fPresamples)*CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)+timeshift); // if(sample > fClipLevel && fClipping) sample=fClipLevel-1; //clipping // newpulse.push_back(sample); // } // if(!fTimeShift){ - // Int_t sample = fCalibration*charge*1e6*CalcResponse((i-fPresamples)*CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + // Int_t sample = fCalibration*charge*1e6*CalcResponse((i-fPresamples)*CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); // if(sample > fClipLevel && fClipping) sample=fClipLevel-1; //clipping // newpulse.push_back(sample); // } @@ -665,20 +672,22 @@ void CbmTrdModuleSimR::AddToPulse(Int_t address, Double_t charge, Double_t reldr Int_t shift = startbin + i; if (fTimeShift) { if (shift < 32) - pulse[i] = - temppulse[shift] - + fCalibration * charge * 1e6 * CalcResponse(addtime * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + timeshift); + pulse[i] = temppulse[shift] + + fCalibration * charge * 1e6 + * CalcResponse(addtime * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + timeshift); else - pulse[i] = - fCalibration * charge * 1e6 * CalcResponse(addtime * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + timeshift); + pulse[i] = fCalibration * charge * 1e6 + * CalcResponse(addtime * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + timeshift); if (pulse[i] > fClipLevel && fClipping) pulse[i] = fClipLevel - 1; //clipping } if (!fTimeShift) { if (shift < 32) pulse[i] = temppulse[shift] - + fCalibration * charge * 1e6 * CalcResponse(addtime * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + + fCalibration * charge * 1e6 + * CalcResponse(addtime * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); else - pulse[i] = fCalibration * charge * 1e6 * CalcResponse(addtime * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + pulse[i] = + fCalibration * charge * 1e6 * CalcResponse(addtime * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); if (pulse[i] > fClipLevel && fClipping) pulse[i] = fClipLevel - 1; //clipping } } @@ -702,9 +711,10 @@ Bool_t CbmTrdModuleSimR::CheckMulti(Int_t address, std::vector<Double_t> pulse) Int_t sec = CbmTrdAddress::GetSectorId(address); Int_t shift = GetMultiBin(pulse); Int_t ncols = fDigiPar->GetNofColumns(); - // Double_t timeshift = gRandom->Uniform(0.,CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + // Double_t timeshift = gRandom->Uniform(0.,CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); Double_t timeshift = - ((Int_t)(fMultiBuffer[address].second * 10) % (Int_t)(CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) * 10)) / 10; + ((Int_t)(fMultiBuffer[address].second * 10) % (Int_t)(CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) * 10)) + / 10.0; std::vector<Double_t> temppulse; std::map<Int_t, std::vector<Double_t>> templow; @@ -740,7 +750,8 @@ Bool_t CbmTrdModuleSimR::CheckMulti(Int_t address, std::vector<Double_t> pulse) col--; FNpulse = fPulseBuffer[FNaddress].first; templow[FNaddress] = FNpulse; - FNshift = (fTimeBuffer[address] - fTimeBuffer[FNaddress]) / CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift; + FNshift = + (fTimeBuffer[address] - fTimeBuffer[FNaddress]) / CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift; for (Int_t i = 0; i < 32; i++) { if (i >= FNshift) FNpulse[i] = 0.; } @@ -767,7 +778,8 @@ Bool_t CbmTrdModuleSimR::CheckMulti(Int_t address, std::vector<Double_t> pulse) col++; FNpulse = fPulseBuffer[FNaddress].first; temphigh[FNaddress] = FNpulse; - FNshift = (fTimeBuffer[address] - fTimeBuffer[FNaddress]) / CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift; + FNshift = + (fTimeBuffer[address] - fTimeBuffer[FNaddress]) / CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift; for (Int_t i = 0; i < 32; i++) { if (i >= FNshift) FNpulse[i] = 0.; } @@ -784,30 +796,32 @@ Bool_t CbmTrdModuleSimR::CheckMulti(Int_t address, std::vector<Double_t> pulse) } if (shift + i - fPresamples < 32) { if (fTimeShift) - pulse[i] = temppulse[shift + i - fPresamples] - + fCalibration * fMultiBuffer[address].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + timeshift); + pulse[i] = + temppulse[shift + i - fPresamples] + + fCalibration * fMultiBuffer[address].first * 1e6 + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + timeshift); if (!fTimeShift) pulse[i] = temppulse[shift + i - fPresamples] + fCalibration * fMultiBuffer[address].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); } else { if (fTimeShift) - pulse[i] = fCalibration * fMultiBuffer[address].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + timeshift); + pulse[i] = + fCalibration * fMultiBuffer[address].first * 1e6 + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + timeshift); if (!fTimeShift) pulse[i] = fCalibration * fMultiBuffer[address].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); } // if(shift+i < 32){ - // if(fTimeShift) pulse[i]=temppulse[shift+i]+fCalibration*fMultiBuffer[address].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)+timeshift); - // if(!fTimeShift) pulse[i]=temppulse[shift+i]+fCalibration*fMultiBuffer[address].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + // if(fTimeShift) pulse[i]=temppulse[shift+i]+fCalibration*fMultiBuffer[address].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)+timeshift); + // if(!fTimeShift) pulse[i]=temppulse[shift+i]+fCalibration*fMultiBuffer[address].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); // } // else{ - // if(fTimeShift) pulse[i]=fCalibration*fMultiBuffer[address].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)+timeshift); - // if(!fTimeShift) pulse[i]=fCalibration*fMultiBuffer[address].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + // if(fTimeShift) pulse[i]=fCalibration*fMultiBuffer[address].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)+timeshift); + // if(!fTimeShift) pulse[i]=fCalibration*fMultiBuffer[address].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); // } } for (Int_t i = 0; i < 32; i++) { @@ -838,33 +852,35 @@ Bool_t CbmTrdModuleSimR::CheckMulti(Int_t address, std::vector<Double_t> pulse) } if (fTimeShift) { if ((size_t) shift + i - fPresamples < temphigh[FNaddress].size()) - FNpulse[i] = temphigh[FNaddress][shift + i - fPresamples] - + fCalibration * fMultiBuffer[FNaddress].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + timeshift); + FNpulse[i] = + temphigh[FNaddress][shift + i - fPresamples] + + fCalibration * fMultiBuffer[FNaddress].first * 1e6 + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + timeshift); else - FNpulse[i] = fCalibration * fMultiBuffer[FNaddress].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + timeshift); + FNpulse[i] = + fCalibration * fMultiBuffer[FNaddress].first * 1e6 + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + timeshift); if (FNpulse[i] > fClipLevel && fClipping) FNpulse[i] = fClipLevel - 1; //clipping } if (!fTimeShift) { if ((size_t) shift + i - fPresamples < temphigh[FNaddress].size()) FNpulse[i] = temphigh[FNaddress][shift + i - fPresamples] + fCalibration * fMultiBuffer[FNaddress].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); else FNpulse[i] = fCalibration * fMultiBuffer[FNaddress].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); if (FNpulse[i] > fClipLevel && fClipping) FNpulse[i] = fClipLevel - 1; //clipping } // if(fTimeShift){ - // if(shift+i<32 && temphigh[FNaddress].size()>0) FNpulse[i]=temphigh[FNaddress][shift+i]+fCalibration*fMultiBuffer[FNaddress].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)+timeshift); - // else FNpulse[i]=fCalibration*fMultiBuffer[FNaddress].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)+timeshift); + // if(shift+i<32 && temphigh[FNaddress].size()>0) FNpulse[i]=temphigh[FNaddress][shift+i]+fCalibration*fMultiBuffer[FNaddress].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)+timeshift); + // else FNpulse[i]=fCalibration*fMultiBuffer[FNaddress].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)+timeshift); // if(FNpulse[i] > fClipLevel && fClipping) FNpulse[i]=fClipLevel-1; //clipping // } // if(!fTimeShift){ - // if(shift+i<32 && temphigh[FNaddress].size()>0) FNpulse[i]=temphigh[FNaddress][shift+i]+fCalibration*fMultiBuffer[FNaddress].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); - // else FNpulse[i]=fCalibration*fMultiBuffer[FNaddress].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + // if(shift+i<32 && temphigh[FNaddress].size()>0) FNpulse[i]=temphigh[FNaddress][shift+i]+fCalibration*fMultiBuffer[FNaddress].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); + // else FNpulse[i]=fCalibration*fMultiBuffer[FNaddress].first*1e6*CalcResponse(i*CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); // if(FNpulse[i] > fClipLevel && fClipping) FNpulse[i]=fClipLevel-1; //clipping // } } @@ -914,22 +930,24 @@ Bool_t CbmTrdModuleSimR::CheckMulti(Int_t address, std::vector<Double_t> pulse) } if (fTimeShift) { if ((size_t) shift + i - fPresamples < templow[FNaddress].size()) - FNpulse[i] = templow[FNaddress][shift + i - fPresamples] - + fCalibration * fMultiBuffer[FNaddress].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + timeshift); + FNpulse[i] = + templow[FNaddress][shift + i - fPresamples] + + fCalibration * fMultiBuffer[FNaddress].first * 1e6 + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + timeshift); else - FNpulse[i] = fCalibration * fMultiBuffer[FNaddress].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + timeshift); + FNpulse[i] = + fCalibration * fMultiBuffer[FNaddress].first * 1e6 + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + timeshift); if (FNpulse[i] > fClipLevel && fClipping) FNpulse[i] = fClipLevel - 1; //clipping } if (!fTimeShift) { if ((size_t) shift + i - fPresamples < templow[FNaddress].size()) FNpulse[i] = templow[FNaddress][shift + i - fPresamples] + fCalibration * fMultiBuffer[FNaddress].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); else FNpulse[i] = fCalibration * fMultiBuffer[FNaddress].first * 1e6 - * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + * CalcResponse((i - fPresamples) * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); if (FNpulse[i] > fClipLevel && fClipping) FNpulse[i] = fClipLevel - 1; //clipping } } @@ -1698,7 +1716,7 @@ void CbmTrdModuleSimR::SetSpadicResponse(Double_t calibration, Double_t tau) fTau = tau; Double_t sum = 0; for (auto i = frecostart; i <= frecostop; i++) - sum += fCalibration * CalcResponse(i * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + sum += fCalibration * CalcResponse(i * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); fEReco = sum; } diff --git a/sim/detectors/trd/CbmTrdModuleSimR.h b/sim/detectors/trd/CbmTrdModuleSimR.h index d6b17577ff3ff15348725e50352d175964183e72..82b45a2b88f1308f4fa2e0b72b39047aec4a14b9 100644 --- a/sim/detectors/trd/CbmTrdModuleSimR.h +++ b/sim/detectors/trd/CbmTrdModuleSimR.h @@ -168,7 +168,7 @@ private: CbmTrdRawToDigiR* fMessageConverter = NULL; TH2D* fDriftTime = NULL; CbmTrdCheckUtil* fQA = NULL; - Bool_t fDebug = false; + Bool_t fDebug = true; ClassDef(CbmTrdModuleSimR, 1) // Simulation module implementation for rectangular pad geometry diff --git a/sim/detectors/trd/CbmTrdRawToDigiR.cxx b/sim/detectors/trd/CbmTrdRawToDigiR.cxx index 61f8fd8f2f56f89a6ae174ccf6ab215778d77538..d041e2f7db62f1d4eacc3d43192255f1e96cb60b 100644 --- a/sim/detectors/trd/CbmTrdRawToDigiR.cxx +++ b/sim/detectors/trd/CbmTrdRawToDigiR.cxx @@ -94,7 +94,7 @@ void CbmTrdRawToDigiR::SetPars(Int_t mode, Double_t cal, Double_t tau, std::vect fTau = tau; Double_t sum = 0; for (UInt_t i = 0; i < mask.size(); i++) - sum += fCalibration * CalcResponse(mask[i] * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + sum += fCalibration * CalcResponse(mask[i] * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); fEReco = sum; FillLookUps(); } @@ -106,7 +106,7 @@ void CbmTrdRawToDigiR::SetPars(Int_t mode, Double_t cal, Double_t tau, std::vect fLookUp = 0; Double_t sum = 0; for (UInt_t i = 0; i < fSampleMask.size(); i++) - sum += fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + sum += fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); fEReco = sum; auto start = high_resolution_clock::now(); FillLookUps(); @@ -123,7 +123,7 @@ void CbmTrdRawToDigiR::SetPars(Int_t mode, Double_t cal, Double_t tau, std::vect if (mode == 2) { Double_t sum = 0; for (UInt_t i = 0; i < fSampleMask.size(); i++) - sum += fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + sum += fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); fEReco = sum; auto start = high_resolution_clock::now(); FillLookUps(); @@ -145,7 +145,7 @@ void CbmTrdRawToDigiR::Init() //default Double_t sum = 0; for (UInt_t i = 0; i < fSampleMask.size(); i++) - sum += fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC)); + sum += fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC)); fEReco = sum; auto start = high_resolution_clock::now(); if (fReadFile == "") FillLookUps(fWriteFile); @@ -170,17 +170,21 @@ void CbmTrdRawToDigiR::FillLookUps(std::string write) { if (fLookUp == 1) { - for (Int_t shift = 0.; shift < CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC); shift++) { + for (Int_t shift = 0.; shift < CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC); shift++) { Double_t sum = 0; for (Int_t i = fMinBin; i <= fMaxBin; i++) - sum += fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift); - fEReco = sum; - Float_t temp = fCalibration * CalcResponse(fMaxBin * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift); + sum += + fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift); + fEReco = sum; + Float_t temp = + fCalibration * CalcResponse(fMaxBin * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift); for (Int_t max = 0; max < fDynamicRange; max++) { Float_t energy = max * 1.0 / temp; - Int_t a = energy * fCalibration * CalcResponse(fMinBin * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift); - Int_t b = energy * fCalibration * CalcResponse((fHighBin) *CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift); + Int_t a = + energy * fCalibration * CalcResponse(fMinBin * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift); + Int_t b = energy * fCalibration + * CalcResponse((fHighBin) *CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift); Int_t mina = a - fExtrapolate * a; Int_t maxa = a + fExtrapolate * a; @@ -245,17 +249,21 @@ void CbmTrdRawToDigiR::FillLookUps(std::string write) if (write != "") WriteMaps(write); } if (fLookUp == 2) { - for (Int_t shift = 0.; shift < CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC); shift++) { + for (Int_t shift = 0.; shift < CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC); shift++) { Double_t sum = 0; for (Int_t i = fMinBin; i <= fMaxBin; i++) - sum += fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift); - fEReco = sum; - Float_t temp = fCalibration * CalcResponse(fMaxBin * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift); + sum += + fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift); + fEReco = sum; + Float_t temp = + fCalibration * CalcResponse(fMaxBin * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift); Int_t extrapolate = 0; for (Int_t max = 0; max < fDynamicRange; max++) { Float_t energy = max * 1.0 / temp; - Int_t a = energy * fCalibration * CalcResponse(fMinBin * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift); - Int_t b = energy * fCalibration * CalcResponse((fHighBin) *CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift); + Int_t a = + energy * fCalibration * CalcResponse(fMinBin * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift); + Int_t b = energy * fCalibration + * CalcResponse((fHighBin) *CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift); Int_t mina = a - fExtrapolate * a; Int_t maxa = a + fExtrapolate * a; @@ -264,7 +272,8 @@ void CbmTrdRawToDigiR::FillLookUps(std::string write) if (!(fElookupAsym[max][a][b] > 0)) fElookupAsym[max][a][b] = shift; sum = 0.; for (UInt_t i = 0; i < fSampleMask.size(); i++) - sum += energy * fCalibration * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC) + shift); + sum += energy * fCalibration + * CalcResponse(fSampleMask[i] * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC) + shift); fElookupSmall[shift][sum] = energy; if (fDebug) fQA->CreateHist("Asym", 512, -12.0, 500.0, 512, -12.0, 500.0); @@ -325,8 +334,9 @@ void CbmTrdRawToDigiR::FillLookUps(std::string write) } if (fLookUp == 4) { for (Int_t max = 0; max < fDynamicRange; max++) { - Float_t energy = max / (fCalibration * CalcResponse(fMaxBin * CbmTrdDigi::Clk(CbmTrdDigi::kSPADIC))); - fElookup[max] = energy; + Float_t energy = + max / (fCalibration * CalcResponse(fMaxBin * CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kSPADIC))); + fElookup[max] = energy; } } else { @@ -419,8 +429,8 @@ CbmTrdDigi* CbmTrdRawToDigiR::MakeDigi(std::vector<Int_t> samples, Int_t channel } if (fLookUp == 4 && FN) { digicharge = fElookup[samples[fMaxBin]]; } } - - CbmTrdDigi* digi = new CbmTrdDigi(channel, uniqueModuleId, digicharge, time, 0, 0); + // The triggertype is set later by the class (moduleSimR) using this function + CbmTrdDigi* digi = new CbmTrdDigi(channel, uniqueModuleId, digicharge, time, CbmTrdDigi::eTriggerType::kNTrg, 0); return digi; }