diff --git a/Detectors/HMPID/base/CMakeLists.txt b/Detectors/HMPID/base/CMakeLists.txt index 579e279202b51..2bab4f0230f37 100644 --- a/Detectors/HMPID/base/CMakeLists.txt +++ b/Detectors/HMPID/base/CMakeLists.txt @@ -16,5 +16,6 @@ o2_add_library(HMPIDBase o2_target_root_dictionary(HMPIDBase HEADERS include/HMPIDBase/Param.h include/HMPIDBase/Digit.h + include/HMPIDBase/Trigger.h include/HMPIDBase/Cluster.h include/HMPIDBase/Geo.h) diff --git a/Detectors/HMPID/base/include/HMPIDBase/Digit.h b/Detectors/HMPID/base/include/HMPIDBase/Digit.h index e30fe18e30fa2..7fcf96a8e4527 100644 --- a/Detectors/HMPID/base/include/HMPIDBase/Digit.h +++ b/Detectors/HMPID/base/include/HMPIDBase/Digit.h @@ -50,7 +50,7 @@ class Digit static void Equipment2Absolute(int Equi, int Colu, int Dilo, int Chan, int* Module, int* x, int* y); // Trigger time Conversion Functions - static inline uint64_t OrbitBcToEventId(uint32_t Orbit, uint16_t BC) { return ((Orbit << 12) || BC); }; + static inline uint64_t OrbitBcToEventId(uint32_t Orbit, uint16_t BC) { return ((Orbit << 12) | (0x0FFF & BC)); }; static inline uint32_t EventIdToOrbit(uint64_t EventId) { return (EventId >> 12); }; static inline uint16_t EventIdToBc(uint64_t EventId) { return (EventId & 0x0FFF); }; static double OrbitBcToTimeNs(uint32_t Orbit, uint16_t BC); @@ -80,10 +80,10 @@ class Digit public: Digit() = default; - Digit(uint16_t bc, uint32_t orbit, int pad, uint16_t charge) : mBc(bc), mOrbit(orbit), mQ(charge), mPad(pad){}; + Digit(uint16_t bc, uint32_t orbit, int pad, uint16_t charge); Digit(uint16_t bc, uint32_t orbit, int chamber, int photo, int x, int y, uint16_t charge); - Digit(uint16_t bc, uint32_t orbit, uint16_t, int equipment, int column, int dilogic, int channel); - Digit(uint16_t bc, uint32_t orbit, uint16_t, int module, int x, int y); + Digit(uint16_t bc, uint32_t orbit, uint16_t charge, int equipment, int column, int dilogic, int channel); + Digit(uint16_t bc, uint32_t orbit, uint16_t charge, int module, int x, int y); // Getter & Setters uint16_t getCharge() const { return mQ; } @@ -133,7 +133,13 @@ class Digit // Charge management functions static void getPadAndTotalCharge(HitType const& hit, int& chamber, int& pc, int& px, int& py, float& totalcharge); static float getFractionalContributionForPad(HitType const& hit, int somepad); - void addCharge(float q) { mQ += q; } + void addCharge(float q) + { + mQ += q; + if (mQ > 0x0FFF) { + mQ = 0x0FFF; + } + } void subCharge(float q) { mQ -= q; } private: diff --git a/Detectors/HMPID/base/include/HMPIDBase/Geo.h b/Detectors/HMPID/base/include/HMPIDBase/Geo.h index eab57ca0607bd..c1f9fb658b0f0 100644 --- a/Detectors/HMPID/base/include/HMPIDBase/Geo.h +++ b/Detectors/HMPID/base/include/HMPIDBase/Geo.h @@ -18,7 +18,6 @@ #define ALICEO2_HMPID_GEO_H #include -#include namespace o2 { @@ -134,6 +133,90 @@ class Geo ClassDefNV(Geo, 1); }; + +class ReadOut +{ + public: + struct LinkAddr { + uint8_t Fee; + uint8_t Cru; + uint8_t Lnk; + uint8_t Flp; + }; + union Lnk { + LinkAddr Id; + uint32_t LinkUId; + }; + static constexpr Lnk mEq[Geo::MAXEQUIPMENTS] = {{0, 0, 0, 160}, + {1, 0, 1, 160}, + {2, 0, 2, 160}, + {3, 0, 3, 160}, + {4, 1, 0, 160}, + {5, 1, 1, 160}, + {8, 1, 2, 160}, + {9, 1, 3, 160}, + {6, 2, 0, 161}, + {7, 2, 1, 161}, + {10, 2, 2, 161}, + {11, 3, 0, 161}, + {12, 3, 1, 161}, + {13, 3, 2, 161}}; + + static inline int FeeId(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? -1 : mEq[idx].Id.Fee; }; + static inline int CruId(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? -1 : mEq[idx].Id.Cru; }; + static inline int LnkId(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? -1 : mEq[idx].Id.Lnk; }; + static inline int FlpId(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? -1 : mEq[idx].Id.Flp; }; + static inline uint32_t UniqueId(unsigned int idx) { return (idx > Geo::MAXEQUIPMENTS) ? -1 : mEq[idx].LinkUId; }; + + static unsigned int searchIdx(int FeeId) + { + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + if (FeeId == mEq[i].Id.Fee) { + return (i); + } + } + return (-1); + } + static unsigned int searchIdx(int CruId, int LnkId) + { + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + if (CruId == mEq[i].Id.Cru && LnkId == mEq[i].Id.Lnk) { + return (i); + } + } + return (-1); + } + static void getInfo(unsigned int idx, int& Fee, int& Cru, int& Lnk, int& Flp) + { + Cru = mEq[idx].Id.Cru; + Lnk = mEq[idx].Id.Lnk; + Fee = mEq[idx].Id.Fee; + Flp = mEq[idx].Id.Flp; + return; + } + + ClassDefNV(ReadOut, 1); +}; +/* +void ReadOut::Init() +{ + mEq[0].Id = { 0, 0, 0, 160}; + mEq[1].Id = { 1, 0, 1, 160}; + mEq[2].Id = { 2, 0, 2, 160}; + mEq[3].Id = { 3, 0, 3, 160}; + mEq[4].Id = { 4, 1, 0, 160}; + mEq[5].Id = { 5, 1, 1, 160}; + mEq[6].Id = { 8, 1, 2, 160}; + mEq[7].Id = { 9, 1, 3, 160}; + mEq[8].Id = { 6, 2, 0, 161}; + mEq[9].Id = { 7, 2, 1, 161}; + mEq[10].Id = {10, 2, 2, 161}; + mEq[11].Id = {11, 3, 0, 161}; + mEq[12].Id = {12, 3, 1, 161}; + mEq[13].Id = {13, 3, 2, 161}; +}; +*/ + } // namespace hmpid } // namespace o2 diff --git a/Detectors/HMPID/base/include/HMPIDBase/Trigger.h b/Detectors/HMPID/base/include/HMPIDBase/Trigger.h new file mode 100644 index 0000000000000..1515b3b3be161 --- /dev/null +++ b/Detectors/HMPID/base/include/HMPIDBase/Trigger.h @@ -0,0 +1,102 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Trigger.h +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 2/03/2021 + +#ifndef DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_TRIGGER_H_ +#define DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_TRIGGER_H_ + +#include +#include "TMath.h" +#include "CommonDataFormat/TimeStamp.h" +#include "CommonConstants/LHCConstants.h" + +namespace o2 +{ +namespace hmpid +{ + +/// \class Trigger +/// \brief HMPID Trigger declaration +class Trigger +{ + public: + // Trigger time Conversion Functions + static inline uint64_t OrbitBcToEventId(uint32_t Orbit, uint16_t BC) { return ((Orbit << 12) | (0x0FFF & BC)); }; + static inline uint32_t EventIdToOrbit(uint64_t EventId) { return (EventId >> 12); }; + static inline uint16_t EventIdToBc(uint64_t EventId) { return (EventId & 0x0FFF); }; + static double OrbitBcToTimeNs(uint32_t Orbit, uint16_t BC) { return (BC * o2::constants::lhc::LHCBunchSpacingNS + Orbit * o2::constants::lhc::LHCOrbitNS); }; + static uint32_t TimeNsToOrbit(double TimeNs) { return (uint32_t)(TimeNs / o2::constants::lhc::LHCOrbitNS); }; + static uint16_t TimeNsToBc(double TimeNs) { return (uint16_t)(std::fmod(TimeNs, o2::constants::lhc::LHCOrbitNS) / o2::constants::lhc::LHCBunchSpacingNS); }; + static void TimeNsToOrbitBc(double TimeNs, uint32_t& Orbit, uint16_t& Bc) + { + Orbit = TimeNsToOrbit(TimeNs); + Bc = TimeNsToBc(TimeNs); + return; + }; + + // Operators definition ! + friend inline bool operator<(const Trigger& l, const Trigger& r) { return OrbitBcToEventId(l.mOrbit, l.mBc) < OrbitBcToEventId(r.mOrbit, r.mBc); }; + friend inline bool operator==(const Trigger& l, const Trigger& r) { return OrbitBcToEventId(l.mOrbit, l.mBc) == OrbitBcToEventId(r.mOrbit, r.mBc); }; + friend inline bool operator>(const Trigger& l, const Trigger& r) { return r < l; }; + friend inline bool operator<=(const Trigger& l, const Trigger& r) { return !(l > r); }; + friend inline bool operator>=(const Trigger& l, const Trigger& r) { return !(l < r); }; + friend inline bool operator!=(const Trigger& l, const Trigger& r) { return !(l == r); }; + + // Digit ASCII format (Orbit,BunchCrossing)[LHC Time nSec] + friend std::ostream& operator<<(std::ostream& os, const Trigger& d) + { + os << "(" << d.mOrbit << "," << d.mBc << ")[" << OrbitBcToTimeNs(d.mOrbit, d.mBc) << " ns]"; + return os; + }; + + public: + Trigger() = default; + Trigger(uint16_t bc, uint32_t orbit) + { + mBc = bc; + mOrbit = orbit; + }; + uint32_t getOrbit() const { return mOrbit; } + uint16_t getBc() const { return mBc; } + uint64_t getTriggerID() const { return OrbitBcToEventId(mOrbit, mBc); } + void setOrbit(uint32_t orbit) + { + mOrbit = orbit; + return; + } + void setBC(uint16_t bc) + { + mBc = bc; + return; + } + void setTriggerID(uint64_t trigger) + { + mOrbit = (trigger >> 12); + mBc = (trigger & 0x0FFF); + return; + } + + private: + // Members + uint16_t mBc = 0.; + uint32_t mOrbit = 0; + + ClassDefNV(Trigger, 2); +}; + +} // namespace hmpid +} // namespace o2 + +#endif /* DETECTORS_HMPID_BASE_INCLUDE_HMPIDBASE_TRIGGER_H_ */ diff --git a/Detectors/HMPID/base/src/Digit.cxx b/Detectors/HMPID/base/src/Digit.cxx index 3c6d6ceba6416..2711a642a2971 100644 --- a/Detectors/HMPID/base/src/Digit.cxx +++ b/Detectors/HMPID/base/src/Digit.cxx @@ -30,6 +30,20 @@ using namespace o2::hmpid; ClassImp(o2::hmpid::Digit); // ============= Digit Class implementation ======= +/// Constructor : Create the Digit structure. Accepts the trigger time (Orbit,BC) +/// The mapping of the digit is in the Photo Cathod coords +/// (Chamber, PhotoCathod, X, Y) +/// @param[in] bc : the bunch crossing [0 .. 2^12-1] +/// @param[in] orbit : the orbit number [0 .. 2^32-1] +/// @param[in] pad : the Digit Unique Id [0x00CPXXYY] +/// @param[in] charge : the value of the charge [0 .. 2^12-1] +Digit::Digit(uint16_t bc, uint32_t orbit, int pad, uint16_t charge) +{ + mBc = bc; + mOrbit = orbit; + mQ = charge > 0x0FFF ? 0x0FFF : charge; + mPad = pad; +} /// Constructor : Create the Digit structure. Accepts the trigger time (Orbit,BC) /// The mapping of the digit is in the Photo Cathod coords @@ -45,7 +59,7 @@ Digit::Digit(uint16_t bc, uint32_t orbit, int chamber, int photo, int x, int y, { mBc = bc; mOrbit = orbit; - mQ = charge; + mQ = charge > 0x0FFF ? 0x0FFF : charge; mPad = Abs(chamber, photo, x, y); } @@ -63,7 +77,7 @@ Digit::Digit(uint16_t bc, uint32_t orbit, uint16_t charge, int equipment, int co { mBc = bc; mOrbit = orbit; - mQ = charge; + mQ = charge > 0x0FFF ? 0x0FFF : charge; mPad = Equipment2Pad(equipment, column, dilogic, channel); } @@ -80,7 +94,7 @@ Digit::Digit(uint16_t bc, uint32_t orbit, uint16_t charge, int module, int x, in { mBc = bc; mOrbit = orbit; - mQ = charge; + mQ = charge > 0x0FFF ? 0x0FFF : charge; mPad = Absolute2Pad(module, x, y); } @@ -369,7 +383,7 @@ Double_t Digit::OrbitBcToTimeNs(uint32_t Orbit, uint16_t BC) /// @return : the Orbit number [0..2^32-1] uint32_t Digit::TimeNsToOrbit(Double_t TimeNs) { - return (TimeNs / o2::constants::lhc::LHCOrbitNS); + return (uint32_t)(TimeNs / o2::constants::lhc::LHCOrbitNS); } /// TimeNsToBc : Extracts the Bunch Crossing number from the absolute @@ -379,7 +393,7 @@ uint32_t Digit::TimeNsToOrbit(Double_t TimeNs) /// @return : the Bunch Crossing number [0..2^12-1] uint16_t Digit::TimeNsToBc(Double_t TimeNs) { - return (std::fmod(TimeNs, o2::constants::lhc::LHCOrbitNS) / o2::constants::lhc::LHCBunchSpacingNS); + return (uint16_t)(std::fmod(TimeNs, o2::constants::lhc::LHCOrbitNS) / o2::constants::lhc::LHCBunchSpacingNS); } /// TimeNsToOrbitBc : Extracts the (Orbit,BC) pair from the absolute diff --git a/Detectors/HMPID/base/src/HMPIDBaseLinkDef.h b/Detectors/HMPID/base/src/HMPIDBaseLinkDef.h index ea6c399143946..462c67964ceed 100644 --- a/Detectors/HMPID/base/src/HMPIDBaseLinkDef.h +++ b/Detectors/HMPID/base/src/HMPIDBaseLinkDef.h @@ -22,5 +22,7 @@ #pragma link C++ class o2::hmpid::HitType + ; #pragma link C++ class vector < o2::hmpid::HitType> + ; #pragma link C++ class o2::hmpid::Geo + ; +#pragma link C++ class o2::hmpid::Trigger + ; +#pragma link C++ class vector < o2::hmpid::Trigger> + ; #endif diff --git a/Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx b/Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx index b2df8dded8028..4985d3b6e18f8 100644 --- a/Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx +++ b/Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx @@ -12,7 +12,7 @@ /// \file HmpidDecoder.cxx /// \author Antonio Franco - INFN Bari /// \brief Base Class to decode HMPID Raw Data stream -/// \version 1.0 +/// \version 1.1 /// \date 17/11/2020 /* ------ HISTORY --------- @@ -84,7 +84,7 @@ HmpidDecoder::~HmpidDecoder() } } -/// Resets to 0 all the class members +/// Init all the members variables. void HmpidDecoder::init() { mRDHAcceptedVersion = 6; @@ -182,7 +182,7 @@ int HmpidDecoder::getEquipmentID(int CruId, int LinkId) /// @returns Type of Word : the type of word [0..4] (0 := undetect) int HmpidDecoder::checkType(uint32_t wp, int* p1, int* p2, int* p3, int* p4) { - if ((wp & 0x0000ffff) == 0x36A8 || (wp & 0x0000ffff) == 0x32A8 || (wp & 0x0000ffff) == 0x30A0 || (wp & 0x0800ffff) == 0x080010A0) { + if ((wp & 0x0000ffff) == 0x000036A8 || (wp & 0x0000ffff) == 0x000032A8 || (wp & 0x0000ffff) == 0x000030A0 || (wp & 0x0800ffff) == 0x080010A0) { *p2 = (wp & 0x03ff0000) >> 16; // Number of words of row *p1 = wp & 0x0000ffff; return (WTYPE_ROW); @@ -252,7 +252,6 @@ bool HmpidDecoder::isSegmentMarker(uint32_t wp, int* Err, int* segSize, int* Seg *segSize = (wp & 0x000fff00) >> 8; // # Number of words of Segment *mark = (wp & 0xfff00000) >> 20; *Seg = wp & 0x0000000F; - if (*Seg > 3 || *Seg < 1) { LOG(INFO) << " Wrong segment Marker Word, bad Number of segment" << *Seg << "!"; *Err = true; @@ -275,19 +274,27 @@ bool HmpidDecoder::isSegmentMarker(uint32_t wp, int* Err, int* segSize, int* Seg bool HmpidDecoder::isPadWord(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Channel, int* Charge) { *Err = false; - if ((wp & 0x0000ffff) == 0x36A8 || (wp & 0x0000ffff) == 0x32A8 || (wp & 0x0000ffff) == 0x30A0 || (wp & 0x0800ffff) == 0x080010A0 || (wp & 0x08000000) != 0) { // # ! this is a pad + // if ((wp & 0x08000000) != 0) { + if ((wp & 0x08000000) != 0) { return (false); + } + *Col = (wp & 0x07c00000) >> 22; + *Dilogic = (wp & 0x003C0000) >> 18; + *Channel = (wp & 0x0003F000) >> 12; + *Charge = (wp & 0x00000FFF); + + if ((wp & 0x0ffff) == 0x036A8 || (wp & 0x0ffff) == 0x032A8 || (wp & 0x0ffff) == 0x030A0 || (wp & 0x0ffff) == 0x010A0) { // # ! this is a pad + if (*Dilogic > 10 || *Channel > 47 || *Dilogic < 1 || *Col > 24 || *Col < 1) { + return (false); + } } else { - *Col = (wp & 0x07c00000) >> 22; - *Dilogic = (wp & 0x003C0000) >> 18; - *Channel = (wp & 0x0003F000) >> 12; - *Charge = (wp & 0x00000FFF); if (*Dilogic > 10 || *Channel > 47 || *Dilogic < 1 || *Col > 24 || *Col < 1) { - LOG(WARNING) << " Wrong Pad values Col=" << *Col << " Dilogic=" << *Dilogic << " Channel=" << *Channel << " Charge=" << *Charge; + // LOG(WARNING) << " Wrong Pad values Col=" << *Col << " Dilogic=" << *Dilogic << " Channel=" << *Channel << " Charge=" << *Charge << " wp:0x" << std::hex << wp << std::dec; *Err = true; + return (false); } - return (true); } + return (true); } /// Checks if is a EoE Marker and extracts the Column, Dilogic and the size @@ -434,7 +441,7 @@ void HmpidDecoder::updateStatistics(HmpidEquipment* eq) eq->mTotalPads += eq->mSampleNumber; eq->mTotalErrors += eq->mErrorsCounter; - // std::cout << ">>>>.. end >>> "<mNumberOfEvents<<" :" <mEventSize<<","<< eq->mEventSizeAverage<< ", "<mEventNumber<<" "<>>updateStatistics() >>> "<< eq->getEquipmentId() << "="<< eq->mNumberOfEvents<<" :" << eq->mEventSize <<","<< eq->mTotalPads << ", " << eq->mSampleNumber << std::endl; return; } @@ -468,6 +475,11 @@ HmpidEquipment* HmpidDecoder::evaluateHeaderContents(int EquipmentIndex) return (eq); } +/// --------------- Decode One Page from Data Buffer --------------- +/// Read the stream, decode the contents and store resuls. +/// ATTENTION : Assumes that the input stream was set +/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header +/// @param[in] streamBuf : the pointer to the Pointer of the Stream Buffer void HmpidDecoder::decodePage(uint32_t** streamBuf) { int equipmentIndex; @@ -502,7 +514,6 @@ void HmpidDecoder::decodePage(uint32_t** streamBuf) if (!getWordFromStream(&wp)) { // end the stream break; } - type = checkType(wp, &p1, &p2, &p3, &p4); if (type == WTYPE_NONE) { if (eq->mWillBePad == true) { // try to recover the first pad ! @@ -520,7 +531,9 @@ void HmpidDecoder::decodePage(uint32_t** streamBuf) continue; } } - + if (mEquipment == 8) { + LOG(INFO) << "Event" << eq->mEventNumber << " >" << std::hex << wp << std::dec << "<" << type; + } if (eq->mWillBeRowMarker == true) { // #shoud be a Row Marker if (type == WTYPE_ROW) { eq->mColumnCounter++; @@ -601,6 +614,9 @@ void HmpidDecoder::decodePage(uint32_t** streamBuf) } } else { setPad(eq, p1 - 1, p2 - 1, p3, p4); + if (mEquipment == 8) { + LOG(INFO) << "Event" << eq->mEventNumber << " >" << p1 - 1 << "," << p2 - 1 << "," << p3 << "," << p4; + } eq->mWordsPerDilogicCounter++; eq->mSampleNumber++; if (p3 == 47) { @@ -760,6 +776,11 @@ bool HmpidDecoder::decodeBuffer() return (true); } +/// --------- Decode One Page from Data Buffer with Fast Decoding -------- +/// Read the stream, decode the contents and store resuls. +/// ATTENTION : Assumes that the input stream was set +/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header +/// @param[in] streamBuf : the pointer to the Pointer of the Stream Buffer void HmpidDecoder::decodePageFast(uint32_t** streamBuf) { int equipmentIndex; @@ -776,15 +797,12 @@ void HmpidDecoder::decodePageFast(uint32_t** streamBuf) LOG(INFO) << "Failed to decode the Header !"; throw TH_WRONGHEADER; } - HmpidEquipment* eq = evaluateHeaderContents(equipmentIndex); - uint32_t wpprev = 0; uint32_t wp = 0; int newOne = true; int Column, Dilogic, Channel, Charge; int pwer; - int payIndex = 0; while (payIndex < mNumberWordToRead) { //start the payload loop word by word wpprev = wp; diff --git a/Detectors/HMPID/reconstruction/src/HmpidEquipment.cxx b/Detectors/HMPID/reconstruction/src/HmpidEquipment.cxx index d6c8896e872a1..32983f4545742 100644 --- a/Detectors/HMPID/reconstruction/src/HmpidEquipment.cxx +++ b/Detectors/HMPID/reconstruction/src/HmpidEquipment.cxx @@ -34,6 +34,33 @@ HmpidEquipment::HmpidEquipment(int Equipment, int Cru, int Link) mEquipmentId = Equipment; mCruId = Cru; mLinkId = Link; + mWordsPerRowCounter = 0; + mBusyTimeAverage = 0; + mBusyTimeSamples = 0; + mBusyTimeValue = 0; + mTotalErrors = 0; + mTotalPads = 0; + mNumberOfEmptyEvents = 0; + mNumberOfEvents = 0; + mNumberOfWrongEvents = 0; + mWordsPerDilogicCounter = 0; + mWordsPerRowCounter = 0; + mWordsPerSegCounter = 0; + mEventSizeAverage = 0; + mErrorsCounter = 0; + mEventNumber = 0; + mEventSize = 0; + mPadsPerEventAverage = 0; + mSegment = 0; + mWillBeEoE = false; + mWillBePad = false; + mWillBeRowMarker = false; + mWillBeSegmentMarker = false; + mSampleNumber = 0; + mEventSizeAverage = 0; + mColumnCounter = 0; + mRowSize = 0; + mErrorPadsPerEvent = 0; return; } diff --git a/Detectors/HMPID/simulation/CMakeLists.txt b/Detectors/HMPID/simulation/CMakeLists.txt index 639816aa14992..181cb2ad1d2ed 100644 --- a/Detectors/HMPID/simulation/CMakeLists.txt +++ b/Detectors/HMPID/simulation/CMakeLists.txt @@ -10,11 +10,15 @@ o2_add_library(HMPIDSimulation SOURCES src/Detector.cxx src/HMPIDDigitizer.cxx src/HmpidCoder.cxx - PUBLIC_LINK_LIBRARIES O2::HMPIDBase) + SOURCES src/HmpidCoder2.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDBase + O2::DetectorsRaw + ROOT::Physics) o2_target_root_dictionary(HMPIDSimulation HEADERS include/HMPIDSimulation/Detector.h include/HMPIDSimulation/HmpidCoder.h + include/HMPIDSimulation/HmpidCoder2.h include/HMPIDSimulation/HMPIDDigitizer.h) diff --git a/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h b/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h index 8ef8b579773bb..92643e54a56a4 100644 --- a/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h +++ b/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h @@ -12,6 +12,7 @@ #define DETECTORS_HMPID_SIMULATION_INCLUDE_HMPIDSIMULATION_HMPIDDIGITIZER_H_ #include "HMPIDBase/Digit.h" +#include "HMPIDBase/Trigger.h" #include "HMPIDSimulation/Detector.h" // for the hit #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" @@ -44,12 +45,12 @@ class HMPIDDigitizer // for the first trigger no busy check necessary mCurrentTriggerTime = timeNS; mReadoutCounter++; - Digit::TimeNsToOrbitBc(mCurrentTriggerTime, mOrbit, mBc); + Trigger::TimeNsToOrbitBc(mCurrentTriggerTime, mOrbit, mBc); return true; } else { if ((timeNS - mCurrentTriggerTime) > BUSYTIME) { mCurrentTriggerTime = timeNS; - Digit::TimeNsToOrbitBc(mCurrentTriggerTime, mOrbit, mBc); + Trigger::TimeNsToOrbitBc(mCurrentTriggerTime, mOrbit, mBc); mReadoutCounter++; return true; } else { @@ -58,6 +59,9 @@ class HMPIDDigitizer } } + uint32_t getOrbit() { return mOrbit; }; + uint16_t getBc() { return mBc; }; + void setEventID(int eventID) { mEventID = eventID; } void setSrcID(int sID) { mSrcID = sID; } diff --git a/Detectors/HMPID/simulation/include/HMPIDSimulation/HmpidCoder2.h b/Detectors/HMPID/simulation/include/HMPIDSimulation/HmpidCoder2.h new file mode 100644 index 0000000000000..09015bf2c9b68 --- /dev/null +++ b/Detectors/HMPID/simulation/include/HMPIDSimulation/HmpidCoder2.h @@ -0,0 +1,132 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidCoder.h +/// \author Antonio Franco - INFN Bari +/// \brief Base Class to code HMPID Raw Data file +/// + +#ifndef COMMON_HMPIDCODER2_H_ +#define COMMON_HMPIDCODER2_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "Headers/RAWDataHeader.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/RawFileWriter.h" + +#include "FairLogger.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDBase/Digit.h" +#include "HMPIDBase/Trigger.h" + +// ---- RDH 6 standard dimension ------- +#define RAWBLOCKDIMENSION_W 2048 +#define HEADERDIMENSION_W 16 +#define PAYLOADDIMENSION_W 2032 +#define PAYLOADMAXSPACE_W 2028 + +// ---- CHARGE CONSTANTS ----- +#define CHARGE_CONST 150 +#define CHARGE_RAND_MAX 400 + +using namespace o2::raw; + +namespace o2 +{ + +namespace hmpid +{ + +class HmpidCoder2 +{ + public: + int mVerbose; + int mNumberOfEquipments; + + RawFileWriter mWriter{"HMP", false}; + + private: + // The standard definition of HMPID equipments at P2 + // const int mEqIds[Geo::MAXEQUIPMENTS] = {0, 1, 2, 3, 4, 5, 8, 9, 6, 7, 10, 11, 12, 13}; + // const int mCruIds[Geo::MAXEQUIPMENTS] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3}; + // const int mLinkIds[Geo::MAXEQUIPMENTS] = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 0, 1, 2}; + // const int mFlpIds[Geo::MAXEQUIPMENTS] = {160, 160, 160, 160, 160, 160, 160, 160, 161, 161, 161, 161, 161, 161}; + + char mFileName[1024]; + uint32_t* mPayloadBufferPtr; + uint32_t* mPadMap; + int mEventSizePerEquipment[Geo::MAXEQUIPMENTS]; + int mEventPadsPerEquipment[Geo::MAXEQUIPMENTS]; + int mPailoadBufferDimPerEquipment; + long mPadsCoded; + bool mSkipEmptyEvents; + std::unique_ptr mUPayloadBufferPtr; + std::unique_ptr mUPadMap; + + LinkSubSpec_t mTheRFWLinks[Geo::MAXEQUIPMENTS]; + + int mBusyTime; + int mHmpidErrorFlag; + int mHmpidFrwVersion; + + public: + HmpidCoder2(int numOfEquipments); + virtual ~HmpidCoder2(); + + void setVerbosity(int Level) + { + mVerbose = Level; + }; + int getVerbosity() + { + return (mVerbose); + }; + int getNumberOfEquipments() + { + return (mNumberOfEquipments); + }; + void setSkipEmptyEvents(bool Skip) + { + mSkipEmptyEvents = Skip; + } + bool getSkipEmptyEvents() + { + return (mSkipEmptyEvents); + } + o2::raw::RawFileWriter& getWriter() { return mWriter; } + + void setDetectorSpecificFields(float BusyTime = 0.001, int Error = 0, int Version = 9); + void openOutputStream(const char* OutputFileName, std::string perFile); + void closeOutputStream(); + + void codeEventChunkDigits(std::vector& digits); + void codeEventChunkDigits(std::vector& digits, Trigger ir); + void dumpResults(); + + private: + int getEquipmentPadIndex(int eq, int col, int dil, int cha); + void fillTheOutputBuffer(uint32_t* padMap); + void writePaginatedEvent(uint32_t orbit, uint16_t bc); + void setRDHFields(int eq = -1); +}; + +} // namespace hmpid +} // namespace o2 + +#endif /* COMMON_HMPIDCODER_H_ */ diff --git a/Detectors/HMPID/simulation/src/HMPIDDigitizer.cxx b/Detectors/HMPID/simulation/src/HMPIDDigitizer.cxx index facfdb488a5f3..aff73f8c1ab37 100644 --- a/Detectors/HMPID/simulation/src/HMPIDDigitizer.cxx +++ b/Detectors/HMPID/simulation/src/HMPIDDigitizer.cxx @@ -10,6 +10,9 @@ #include "HMPIDSimulation/HMPIDDigitizer.h" #include "HMPIDBase/Digit.h" +#include "HMPIDBase/Trigger.h" + +#include "Framework/Logger.h" #include "Framework/Logger.h" @@ -31,12 +34,13 @@ void HMPIDDigitizer::zeroSuppress(std::vector const& digits, s int index = 0; for (auto& digit : digits) { if (digit.getCharge() >= getThreshold(digit)) { + // if(digit.getPx() < 80 && digit.getPy() < 48) { newdigits.push_back(digit); - if (newlabels) { // copy the labels to the new place with the right new index newlabels->addElements(newdigits.size() - 1, labels.getLabels(index)); } + // } } index++; } @@ -75,11 +79,15 @@ void HMPIDDigitizer::process(std::vector const& hits, std::v int counter = 0; for (int nx = -1; nx <= 1; ++nx) { for (int ny = -1; ny <= 1; ++ny) { + if ((px + nx) < 0 || (px + nx) > 79 || (py + ny) < 0 || (py + ny) > 47) { + LOG(INFO) << ">> Pad out the PhotoCathod boundary. Excluded :" << px << " " << py << " :" << nx << "," << ny; + continue; + } allpads[counter] = Param::Abs(chamber, pc, px + nx, py + ny); counter++; } } - + // LOG(INFO) << "." << px << " " << py ; for (auto& pad : allpads) { auto iter = mIndexForPad.find(pad); int index = -1; @@ -111,7 +119,7 @@ void HMPIDDigitizer::process(std::vector const& hits, std::v } else { // create digit ... and register // mDigits.emplace_back(mCurrentTriggerTime, pad, totalQ * fraction); - mDigits.emplace_back(mOrbit, mBc, pad, totalQ * fraction); + mDigits.emplace_back(mBc, mOrbit, pad, totalQ * fraction); mIndexForPad[pad] = mDigits.size() - 1; mInvolvedPads.emplace_back(pad); diff --git a/Detectors/HMPID/simulation/src/HMPIDSimulationLinkDef.h b/Detectors/HMPID/simulation/src/HMPIDSimulationLinkDef.h index 5367c5bcb20e1..866728f3baad5 100644 --- a/Detectors/HMPID/simulation/src/HMPIDSimulationLinkDef.h +++ b/Detectors/HMPID/simulation/src/HMPIDSimulationLinkDef.h @@ -18,5 +18,6 @@ #pragma link C++ class o2::base::DetImpl < o2::hmpid::Detector> + ; #pragma link C++ class o2::hmpid::HMPIDDigitizer + ; #pragma link C++ class o2::hmpid::HmpidCoder + ; +#pragma link C++ class o2::hmpid::HmpidCoder2 + ; #endif diff --git a/Detectors/HMPID/simulation/src/HmpidCoder2.cxx b/Detectors/HMPID/simulation/src/HmpidCoder2.cxx new file mode 100644 index 0000000000000..b021890098fa9 --- /dev/null +++ b/Detectors/HMPID/simulation/src/HmpidCoder2.cxx @@ -0,0 +1,292 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file HmpidCoder.cxx +/// \author Antonio Franco - INFN Bari +/// \brief Base Class for coding HMPID Raw Data File +/// \version 1.0 +/// \date 24 feb 2021 + +#include +#include +#include + +#include "Headers/RAWDataHeader.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/RawFileWriter.h" +#include "DataFormatsParameters/GRPObject.h" + +#include "HMPIDBase/Digit.h" +#include "HMPIDSimulation/HmpidCoder2.h" + +using namespace o2::raw; +using namespace o2::hmpid; +using namespace o2::header; + +/// HMPID Raw Coder Constructor +/// @param[in] numOfEquipments : number of Equipments +HmpidCoder2::HmpidCoder2(int numOfEquipments) +{ + mPadsCoded = 0; + mNumberOfEquipments = numOfEquipments; + mVerbose = 0; + mSkipEmptyEvents = true; + mPailoadBufferDimPerEquipment = ((Geo::N_SEGMENTS * (Geo::N_COLXSEGMENT * (Geo::N_DILOGICS * (Geo::N_CHANNELS + 1) + 1) + 1)) + 10); + auto UPayloadBufferPtr = std::make_unique(sizeof(uint32_t) * mNumberOfEquipments * mPailoadBufferDimPerEquipment); + auto UPadMap = std::make_unique(sizeof(uint32_t) * Geo::N_HMPIDTOTALPADS); + mPayloadBufferPtr = UPayloadBufferPtr.get(); + mPadMap = UPadMap.get(); + mBusyTime = 20000; // 1 milli sec + mHmpidErrorFlag = 0; + mHmpidFrwVersion = 9; +} + +/// HMPID Raw Coder +HmpidCoder2::~HmpidCoder2() +{ +} + +/// setDetectorSpecificFields() : sets the HMPID parameters for the next +/// raw file writes +/// @param[in] BusyTime : busy time in milliseconds +/// @param[in] Error : the Error field +/// @param[in] Version : the Firmware Version [def. 9] +void HmpidCoder2::setDetectorSpecificFields(float BusyTime, int Error, int Version) +{ + uint32_t busy = (uint32_t)(BusyTime / 0.00000005); + mBusyTime = busy; + mHmpidErrorFlag = Error; + mHmpidFrwVersion = Version; + return; +} + +/// setRDHFields() : sets the HMPID RDH Field for the next +/// raw file writes +/// @param[in] eq : the HMPID Equipment ID [0..13] if == -1 -> all +void HmpidCoder2::setRDHFields(int eq) +{ + int st, en; + uint32_t wr = (mBusyTime << 9) | ((mHmpidErrorFlag & 0x01F) << 4) | (mHmpidFrwVersion & 0x0F); + st = (eq < 0 || eq >= Geo::MAXEQUIPMENTS) ? 0 : eq; + en = (eq < 0 || eq >= Geo::MAXEQUIPMENTS) ? Geo::MAXEQUIPMENTS : eq + 1; + for (int l = st; l < en; l++) { + o2::raw::RawFileWriter::LinkData& link = mWriter.getLinkWithSubSpec(mTheRFWLinks[l]); + RDHAny* RDHptr = link.getLastRDH(); + if (RDHptr != nullptr) { + o2::raw::RDHUtils::setDetectorField(RDHptr, wr); + } + } + return; +} + +/// constexpr to accelerate the coordinates changing +constexpr int p1() { return (Geo::N_SEGMENTS * Geo::N_COLXSEGMENT * Geo::N_DILOGICS * Geo::N_CHANNELS); } +constexpr int p2() { return (Geo::N_DILOGICS * Geo::N_CHANNELS); } + +/// getEquipmentPadIndex() : converts the (Equipment, Column, Dilogic, Channel) +/// coordinate into a unique PadIndex value used to address the PADs array +/// @param[in] eq : the HMPID Equipment ID [0..13] +/// @param[in] col : the Equipment Column [0..23] +/// @param[in] dil : the Dilogic [0..9] +/// @param[in] cha : the Channel [0..47] +/// @returns The PAD index value [0..161279] +int HmpidCoder2::getEquipmentPadIndex(int eq, int col, int dil, int cha) +{ + return (eq * p1() + col * p2() + dil * Geo::N_CHANNELS + cha); +} + +/// Scans the PADs array and fill the Output buffer with the RawFile structure +/// a two step algorithm... +/// @param[in] padMap : poiter to the PADs map array +void HmpidCoder2::fillTheOutputBuffer(uint32_t* padMap) +{ + uint32_t rowMarker, segMarker, eoeMarker, padWord; + uint32_t rowSize; + uint32_t ptr = 0; + int pads[Geo::MAXEQUIPMENTS]; + int padsCount; + int segSize; + + for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { + mEventSizePerEquipment[i] = 0; + } + + for (int eq = 0; eq < mNumberOfEquipments; eq++) { + int startPtr = ptr; + padsCount = 0; + for (int s = 1; s <= Geo::N_SEGMENTS; s++) { + segSize = 0; + for (int c = 1; c <= Geo::N_COLXSEGMENT; c++) { + // ---- Pre-calculate the size of each column + for (int j = 0; j < Geo::N_DILOGICS; j++) { + pads[j] = 0; + } + rowSize = 0; + for (int j = 0; j < Geo::N_DILOGICS; j++) { + for (int k = 0; k < Geo::N_CHANNELS; k++) { + int idx = getEquipmentPadIndex(eq, ((s - 1) * Geo::N_COLXSEGMENT + (c - 1)), j, k); + if (padMap[idx] > 0) { + pads[j]++; + rowSize++; + padsCount++; + } + } + } + rowSize += Geo::N_DILOGICS; + segSize += (rowSize + 1); + rowMarker = 0x000036A8 | ((rowSize << 16) & 0x03ff0000); + + // ---- fills the Payload Buffer + mPayloadBufferPtr[ptr++] = rowMarker; + int col = (s - 1) * Geo::N_COLXSEGMENT + c; + for (int d = 1; d <= Geo::N_DILOGICS; d++) { + for (int p = 0; p < Geo::N_CHANNELS; p++) { + int idx = getEquipmentPadIndex(eq, ((s - 1) * Geo::N_COLXSEGMENT + (c - 1)), (d - 1), p); + if (padMap[idx] > 0) { + padWord = ((col << 22) & 0x07c00000) | ((d << 18) & 0x003C0000) | ((p << 12) & 0x0003F000) | (padMap[idx] & 0x00000FFF); + mPayloadBufferPtr[ptr++] = padWord; + } + } + eoeMarker = 0x08000080 | ((col << 22) & 0x07c00000) | (d << 18 & 0x003C0000) | (pads[d - 1] & 0x0000007F); + mPayloadBufferPtr[ptr++] = eoeMarker; + } + } + segSize += 1; + segMarker = 0xAB000000 | ((segSize << 8) & 0x000fff00) | (s & 0x0000000F); + mPayloadBufferPtr[ptr++] = segMarker; + } + mPadsCoded += padsCount; + mEventPadsPerEquipment[eq] = padsCount; + mEventSizePerEquipment[eq] = ptr - startPtr; + } + return; +} + +/// Add a chunk of data in the Output buffer to the RawWriter +/// setting the CRU,Link coordinates and the Trigger Info +/// One or more Pages will be created for each equipment +/// +/// @param[in] orbit : the Trigger ORBIT value +/// @param[in] bc : the Trigger BC value +void HmpidCoder2::writePaginatedEvent(uint32_t orbit, uint16_t bc) +{ + uint32_t* ptrStartEquipment = mPayloadBufferPtr; + for (int eq = 0; eq < mNumberOfEquipments; eq++) { + int EventSize = mEventSizePerEquipment[eq]; + LOG(DEBUG) << "writePaginatedEvent() Eq=" << eq << " Size:" << EventSize << " Pads:" << mEventPadsPerEquipment[eq] << " Orbit:" << orbit << " BC:" << bc; + if (mEventPadsPerEquipment[eq] > 0 || !mSkipEmptyEvents) { // Skips the Events with 0 Pads + mWriter.addData(ReadOut::FeeId(eq), ReadOut::CruId(eq), ReadOut::LnkId(eq), 0, {bc, orbit}, gsl::span(reinterpret_cast(ptrStartEquipment), EventSize * sizeof(uint32_t))); + // We fill the fields ! + // TODO: we can fill the detector field with Simulated Data + setDetectorSpecificFields(0.000001 * EventSize); + setRDHFields(eq); + } + ptrStartEquipment += EventSize; + } + return; +} + +/// Analyze a Digits Vector and setup the PADs array +/// with the charge value, then fills the output buffer +/// and forward it to the RawWriter object +/// +/// NOTE: this version take the Trigger info from the first +/// digit in the vector. We ASSUME that the vector contains +/// one and only one event !!!! +/// @param[in] digits : the vector of Digit structures +void HmpidCoder2::codeEventChunkDigits(std::vector& digits) +{ + if (digits.size() == 0) + return; // the vector is empty ! + codeEventChunkDigits(digits, Trigger{digits[0].getBC(), digits[0].getOrbit()}); + return; +} + +/// Analyze a Digits Vector and setup the PADs array +/// with the charge value, then fills the output buffer +/// and forward it to the RawWriter object +/// +/// NOTE: the vector could be empty! +/// @param[in] digits : the vector of Digit structures +/// @param[in] ir : the Interaction Record structure +void HmpidCoder2::codeEventChunkDigits(std::vector& digits, Trigger ir) +{ + int eq, col, dil, cha, mo, x, y, idx; + uint32_t orbit = ir.getOrbit(); + uint16_t bc = ir.getBc(); + + int padsCount = 0; + LOG(INFO) << "Manage chunk Orbit :" << orbit << " BC:" << bc << " Digits size:" << digits.size(); + for (o2::hmpid::Digit d : digits) { + Digit::Pad2Equipment(d.getPadID(), &eq, &col, &dil, &cha); // From Digit to Hardware coords + eq = ReadOut::FeeId(eq); // converts the Equipment Id in Cru/Link position ref + idx = getEquipmentPadIndex(eq, col, dil, cha); // finally to the unique padmap index + if (mPadMap[idx] != 0) { // We already have the pad set + LOG(WARNING) << "Duplicated DIGIT =" << d << " (" << eq << "," << col << "," << dil << "," << cha << ")"; + } else { + mPadMap[idx] = d.getCharge(); + padsCount++; + } + } + fillTheOutputBuffer(mPadMap); // Fill the Buffer for all Equipments per Event + writePaginatedEvent(orbit, bc); + std::memset(mPadMap, 0, sizeof(uint32_t) * Geo::N_HMPIDTOTALPADS); // Update for the new event + return; +} + +/// Create the Raw File/Files for the output. +/// Also registers the links in the RawWriter object +/// +/// @param[in] OutputFileName : the Path/Prefix name for the raw files +/// @param[in] perFlpFile : if true a couple of files will be created, one for each +/// HMPID FLPs +void HmpidCoder2::openOutputStream(const char* OutputFileName, std::string perFile) +{ + RAWDataHeader rdh; // by default, v6 is used currently. + for (int eq = 0; eq < mNumberOfEquipments; eq++) { + rdh.feeId = ReadOut::FeeId(eq); + rdh.cruID = ReadOut::CruId(eq); + rdh.linkID = ReadOut::LnkId(eq); + rdh.endPointID = 0; + + if (perFile == "link") { + sprintf(mFileName, "%s_L%d%s", OutputFileName, ReadOut::FeeId(eq), ".raw"); + } else if (perFile == "flp") { + sprintf(mFileName, "%s_%d%s", OutputFileName, ReadOut::FlpId(eq), ".raw"); + } else if (perFile == "all") { + sprintf(mFileName, "%s%s", OutputFileName, ".raw"); + } else { + throw std::runtime_error(fmt::format("unknown raw file grouping option {}", perFile)); + } + + mWriter.registerLink(rdh, mFileName); // register the link + LinkSubSpec_t ap = RDHUtils::getSubSpec(ReadOut::CruId(eq), ReadOut::LnkId(eq), 0, ReadOut::FeeId(eq)); + mTheRFWLinks[eq] = ap; // Store the RawFileWriter Link ID + } + return; +} + +/// Close and flush the output streams. +void HmpidCoder2::closeOutputStream() +{ + mWriter.close(); + return; +} + +/// Dumps the results of the last coding +void HmpidCoder2::dumpResults() +{ + std::cout << " **** HMPID RawFile Coder : results ****" << std::endl; + std::cout << " Created files : " << mFileName << std::endl; + std::cout << " Number of Pads coded : " << mPadsCoded << std::endl; + std::cout << " ----------------------------------------" << std::endl; +} diff --git a/Detectors/HMPID/workflow/CMakeLists.txt b/Detectors/HMPID/workflow/CMakeLists.txt index d71773ee8c3aa..66c3bc963d33c 100644 --- a/Detectors/HMPID/workflow/CMakeLists.txt +++ b/Detectors/HMPID/workflow/CMakeLists.txt @@ -15,6 +15,7 @@ o2_add_library(HMPIDWorkflow src/DumpDigitsSpec.cxx src/ReadRawFileSpec.cxx src/WriteRawFromDigitsSpec.cxx + src/WriteRawFromRootSpec.cxx src/PedestalsCalculationSpec.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::CCDB @@ -34,14 +35,14 @@ o2_add_executable(read-raw-file-workflow SOURCES src/read-raw-file-workflow.cxx PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) -o2_add_executable(raw-to-digits-workflow +o2_add_executable(raw-to-digitstream-workflow COMPONENT_NAME hmpid - SOURCES src/raw-to-digits-workflow.cxx + SOURCES src/raw-to-digitstream-workflow.cxx PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) -o2_add_executable(write-raw-from-digits-workflow +o2_add_executable(digitstream-to-raw-workflow COMPONENT_NAME hmpid - SOURCES src/write-raw-from-digits-workflow.cxx + SOURCES src/digitstream-to-raw-workflow.cxx PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) o2_add_executable(dump-digits-workflow @@ -49,13 +50,18 @@ o2_add_executable(dump-digits-workflow SOURCES src/dump-digits-workflow.cxx PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) -o2_add_executable(write-root-from-digits-workflow +o2_add_executable(digitstream-to-digits-workflow COMPONENT_NAME hmpid - SOURCES src/write-root-from-digits-workflow.cxx + SOURCES src/digitstream-to-digits-workflow.cxx PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) o2_add_executable(raw-to-pedestals-workflow COMPONENT_NAME hmpid SOURCES src/raw-to-pedestals-workflow.cxx PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) + +o2_add_executable(digits-to-raw-workflow + COMPONENT_NAME hmpid + SOURCES src/digits-to-raw-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDWorkflow) \ No newline at end of file diff --git a/Detectors/HMPID/workflow/README.md b/Detectors/HMPID/workflow/README.md index ce60e40341411..20e0c87b307ec 100644 --- a/Detectors/HMPID/workflow/README.md +++ b/Detectors/HMPID/workflow/README.md @@ -2,7 +2,7 @@ \page refHMPworkflow HMP workflow /doxy --> -# DPL workflows for the HMPID v.0.3 +# DPL workflows for the HMPID v.0.4 ## HMPID DPL processors @@ -114,6 +114,43 @@ Example [O2Suite/latest-o2] ~/Downloads/provaRec $> o2-hmpid-read-raw-file-workflow --raw-file test_full_flp1.raw -b | o2-hmpid-raw-to-digits-workflow -b | o2-hmpid-write-root-from-digits-workflow -b ``` +### o2-hmpid-write-raw-from-root-workflow +Write raw files with the digits information contained in a root file + +``` +o2-hmpid-write-raw-from-root-workflow +``` + +Data processor options: HMP-WriteRawFromRootFile: + +``` + --hmp-raw-outdir arg (=./) base dir for output file + --hmp-raw-outfile arg (=hmpReadOut) base name for output file + --hmp-raw-perlink produce one file per link + --hmp-raw-perflp produce one raw file per FLPs + --in-file arg (=hmpiddigits.root) name of the input sim root file + --dump-digits out the digits file in /tmp/hmpDumpDigits.dat + --hmp-skip-empty skip empty events + --start-value-enumeration arg (=0) initial value for the enumeration + --end-value-enumeration arg (=-1) final value for the enumeration + --step-value-enumeration arg (=1) step between one value and the other +``` + +Example + +``` +[O2Suite/latest-o2] ~/Downloads/provaRec $>o2-sim-serial -m HMP -n 20 -e TGeant4 -g pythia8hi +[O2Suite/latest-o2] ~/Downloads/provaRec $>o2-sim-digitizer-workflow --onlyDet HMP +[O2Suite/latest-o2] ~/Downloads/provaRec $>o2-hmpid-write-raw-from-root-workflow --in-file hmpiddigits.root --hmp-raw-outfile hmpRawFromRoot --dump-digits -b +``` + +in order to verify the write, the inverse decoding of raw file + +``` +[O2Suite/latest-o2] ~/Downloads/provaRec $>o2-hmpid-read-raw-file-workflow --raw-file hmpRawFromRoot.raw -b | o2-hmpid-raw-to-digits-workflow -b | o2-hmpid-dump-digits-workflow --out-file /tmp/hmpDumpDigitsVerify.dat +``` + + ### o2-hmpid-raw-to-pedestals-workflow Write the Pedestals/Threshold files for the readout and registers Mean and Sigma in the CCDB diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRawFromRootSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRawFromRootSpec.h new file mode 100644 index 0000000000000..1f47fc2b2c76f --- /dev/null +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRawFromRootSpec.h @@ -0,0 +1,61 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_WRITERAWFROMROOT_H_ +#define DETECTORS_HMPID_WORKFLOW_INCLUDE_HMPIDWORKFLOW_WRITERAWFROMROOT_H_ + +#include +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "DetectorsRaw/HBFUtils.h" +#include "DetectorsRaw/RawFileWriter.h" + +#include "HMPIDBase/Common.h" +#include "HMPIDBase/Digit.h" +#include "HMPIDBase/Trigger.h" +#include "HMPIDSimulation/HmpidCoder2.h" + +namespace o2 +{ +namespace hmpid +{ + +class WriteRawFromRootTask : public framework::Task +{ + public: + WriteRawFromRootTask() = default; + ~WriteRawFromRootTask() override = default; + void init(framework::InitContext& ic) final; + void run(framework::ProcessingContext& pc) final; + void endOfStream(framework::EndOfStreamContext& ec) override; + + private: + void readRootFile(); + std::string mBaseFileName = ""; + std::string mDirectoryName = ""; + std::string mBaseRootFileName = ""; + bool mSkipEmpty = false; + bool mDumpDigits = false; + std::string mPerFile = "all"; + + std::vector mDigits; + long mDigitsReceived; + int mEventsReceived; + HmpidCoder2* mCod; + ExecutionTimer mExTimer; + TTree* mDigTree; +}; + +o2::framework::DataProcessorSpec getWriteRawFromRootSpec(std::string inputSpec = "HMP/DIGITS"); + +} // end namespace hmpid +} // end namespace o2 + +#endif diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRootFromDigitsSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRootFromDigitsSpec.h index d0cb20ac56b2c..d10e07b1046f5 100644 --- a/Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRootFromDigitsSpec.h +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/WriteRootFromDigitsSpec.h @@ -15,6 +15,7 @@ #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "Framework/InputSpec.h" #include "HMPIDBase/Digit.h" +#include "HMPIDBase/Trigger.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" @@ -30,7 +31,7 @@ o2::framework::DataProcessorSpec getWriteRootFromDigitSpec(bool mctruth = false) { using InputSpec = framework::InputSpec; using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; - return MakeRootTreeWriterSpec("HMPDigitWriter", + return MakeRootTreeWriterSpec("HMPRootFileWriter", "hmpiddigits.root", "o2sim", -1, diff --git a/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx b/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx index 7e1e167610d96..02a8142ad4b46 100644 --- a/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx +++ b/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx @@ -113,10 +113,17 @@ void DataDecoderTask::endOfStream(framework::EndOfStreamContext& ec) theObj[Geo::N_MODULES]->Branch("Average_Event_Size", &avgEventSize, "F"); theObj[Geo::N_MODULES]->Branch("Average_Busy_Time", &avgBusyTime, "F"); + // Update the Stat for the Decoding + int numEqui = mDeco->getNumberOfEquipments(); + // cycle in order to update info for the last event + for (int i = 0; i < numEqui; i++) { + if (mDeco->mTheEquipments[i]->mNumberOfEvents > 0) { + mDeco->updateStatistics(mDeco->mTheEquipments[i]); + } + } char summaryFileName[254]; sprintf(summaryFileName, "%s_stat.txt", mRootStatFile.c_str()); mDeco->writeSummaryFile(summaryFileName); - int numEqui = mDeco->getNumberOfEquipments(); for (int e = 0; e < numEqui; e++) { avgEventSize = mDeco->getAverageEventSize(e); avgBusyTime = mDeco->getAverageBusyTime(e); @@ -161,7 +168,7 @@ void DataDecoderTask::decodeTF(framework::ProcessingContext& pc) mTotalFrames++; pc.outputs().snapshot(o2::framework::Output{"HMP", "DIGITS", 0, o2::framework::Lifetime::Timeframe}, mDeco->mDigits); // mTotalDigits += mDeco->mDigits.size(); - LOG(DEBUG) << "Writing " << mDeco->mDigits.size() << "/" << mTotalDigits << " Digits ..."; + //LOG(INFO) << "Writing " << mDeco->mDigits.size() << "/" << mTotalDigits << " Digits ..."; } return; } diff --git a/Detectors/HMPID/workflow/src/DumpDigitsSpec.cxx b/Detectors/HMPID/workflow/src/DumpDigitsSpec.cxx index 29dcef7150c28..5de9d2a74b2c9 100644 --- a/Detectors/HMPID/workflow/src/DumpDigitsSpec.cxx +++ b/Detectors/HMPID/workflow/src/DumpDigitsSpec.cxx @@ -98,12 +98,12 @@ void DumpDigitsTask::run(framework::ProcessingContext& pc) if (Dig.getOrbit() != mOrbit || Dig.getBC() != mBc) { mOrbit = Dig.getOrbit(); mBc = Dig.getBC(); - LOG(INFO) << "Event :" << mOrbit << " / " << mBc; + // LOG(INFO) << "Event :" << mOrbit << " / " << mBc; } } } } - mExTimer.elapseMes("... Dumping... Digits received = " + std::to_string(mDigitsReceived)); + mExTimer.elapseMes("... Dumping Digits received = " + std::to_string(mDigitsReceived)); return; } diff --git a/Detectors/HMPID/workflow/src/WriteRawFromRootSpec.cxx b/Detectors/HMPID/workflow/src/WriteRawFromRootSpec.cxx new file mode 100644 index 0000000000000..cc2264b8bcc35 --- /dev/null +++ b/Detectors/HMPID/workflow/src/WriteRawFromRootSpec.cxx @@ -0,0 +1,212 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file WriteRawFromDigitsSpec.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// \brief Implementation of a data processor to produce raw files from a Digits stream +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Framework/DataRefUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Lifetime.h" +#include "Framework/Output.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Logger.h" +#include "Framework/InputRecordWalker.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsCommonDataFormats/NameConf.h" + +#include "TFile.h" +#include "TTree.h" +#include + +#include "Headers/RAWDataHeader.h" +#include "DetectorsRaw/RDHUtils.h" +#include "DPLUtils/DPLRawParser.h" + +#include "HMPIDBase/Digit.h" +#include "HMPIDBase/Trigger.h" +#include "HMPIDBase/Geo.h" +#include "HMPIDSimulation/HmpidCoder2.h" +#include "HMPIDWorkflow/WriteRawFromRootSpec.h" + +namespace o2 +{ +namespace hmpid +{ + +using namespace o2; +using namespace o2::framework; +using RDH = o2::header::RDHAny; + +//======================= +// Data decoder +void WriteRawFromRootTask::init(framework::InitContext& ic) +{ + LOG(INFO) << "HMPID Write Raw File From Root sim Digits vector - init()"; + mDigitsReceived = 0; + mEventsReceived = 0; + mBaseRootFileName = ic.options().get("in-file"); + mBaseFileName = ic.options().get("hmp-raw-outfile"); + mDirectoryName = ic.options().get("hmp-raw-outdir"); + mPerFile = ic.options().get("hmp-file-for"); + mDumpDigits = ic.options().get("dump-digits"); // Debug flags + mSkipEmpty = ic.options().get("hmp-skip-empty"); + + // Arrange Files path + if (gSystem->AccessPathName(mDirectoryName.c_str())) { + if (gSystem->mkdir(mDirectoryName.c_str(), kTRUE)) { + LOG(FATAL) << "could not create output directory " << mDirectoryName; + } else { + LOG(INFO) << "created output directory " << mDirectoryName; + } + } + std::string fullFName = o2::utils::concat_string(mDirectoryName, "/", mBaseFileName); + + // Setup the Coder + mCod = new HmpidCoder2(Geo::MAXEQUIPMENTS); + mCod->setSkipEmptyEvents(mSkipEmpty); + mCod->openOutputStream(fullFName.c_str(), mPerFile); + std::string inputGRP = o2::base::NameConf::getGRPFileName(); + std::unique_ptr grp{o2::parameters::GRPObject::loadFrom(inputGRP)}; + mCod->getWriter().setContinuousReadout(grp->isDetContinuousReadOut(o2::detectors::DetID::HMP)); // must be set explicitly + + // Open the ROOT file + TFile* fdig = TFile::Open(mBaseRootFileName.data()); + assert(fdig != nullptr); + LOG(INFO) << "Open Root digits file " << mBaseRootFileName.data(); + mDigTree = (TTree*)fdig->Get("o2sim"); + + // Ready to operate + mCod->getWriter().writeConfFile("HMP", "RAWDATA", o2::utils::concat_string(mDirectoryName, '/', "HMPraw.cfg")); + mExTimer.start(); + return; +} + +void WriteRawFromRootTask::readRootFile() +{ + std::vector digitsPerEvent; + std::vector digits, *hmpBCDataPtr = &digits; + std::vector interactions, *interactionsPtr = &interactions; + + // Keeps the Interactions ! + mDigTree->SetBranchAddress("InteractionRecords", &interactionsPtr); + LOG(DEBUG) << "Number of Interaction Records vectors in the simulation file :" << mDigTree->GetEntries(); + for (int ient = 0; ient < mDigTree->GetEntries(); ient++) { + mDigTree->GetEntry(ient); + LOG(INFO) << "Interactions records in simulation :" << interactions.size(); + for (auto a : interactions) { + LOG(DEBUG) << a; + } + } + sort(interactions.begin(), interactions.end()); // Sort interactions in ascending order + int trigPointer = 0; + + mDigTree->SetBranchAddress("HMPDigit", &hmpBCDataPtr); + LOG(INFO) << "Number of entries in the simulation file :" << mDigTree->GetEntries(); + + // Loops in the Entry of ROOT Branch + for (int ient = 0; ient < mDigTree->GetEntries(); ient++) { + mDigTree->GetEntry(ient); + int nbc = digits.size(); + if (nbc == 0) { // exit for empty + LOG(INFO) << "The Entry :" << ient << " doesn't have digits !"; + continue; + } + sort(digits.begin(), digits.end(), o2::hmpid::Digit::eventEquipPadsComp); + if (mDumpDigits) { // we wand the dump of digits ? + std::ofstream dumpfile; + dumpfile.open("/tmp/hmpDumpDigits.dat"); + for (int i = 0; i < nbc; i++) { + dumpfile << digits[i] << std::endl; + } + dumpfile.close(); + } + // ready to operate + LOG(INFO) << "For the entry = " << ient << " there are " << nbc << " DIGITS stored."; + for (int i = 0; i < nbc; i++) { + if (digits[i].getOrbit() != interactions[trigPointer].getOrbit() || digits[i].getBC() != interactions[trigPointer].getBc()) { + do { + mEventsReceived++; + LOG(DEBUG) << "Orbit =" << interactions[trigPointer].getOrbit() << " BC =" << interactions[trigPointer].getBc(); + mCod->codeEventChunkDigits(digitsPerEvent, interactions[trigPointer]); + digitsPerEvent.clear(); + trigPointer++; + } while ((digits[i].getOrbit() != interactions[trigPointer].getOrbit() || digits[i].getBC() != interactions[trigPointer].getBc()) && trigPointer < interactions.size()); + if (trigPointer == interactions.size()) { + LOG(WARNING) << "Digits without Interaction Record !!! ABORT"; + break; + } + } + digitsPerEvent.push_back(digits[i]); + } + mEventsReceived++; + LOG(DEBUG) << "Orbit =" << interactions[trigPointer].getOrbit() << " BC =" << interactions[trigPointer].getBc(); + mCod->codeEventChunkDigits(digitsPerEvent, interactions[trigPointer]); + mDigitsReceived += nbc; + } + mExTimer.logMes("End of Write raw file Job !"); + return; +} + +void WriteRawFromRootTask::run(framework::ProcessingContext& pc) +{ + readRootFile(); + mCod->closeOutputStream(); + mCod->dumpResults(); + mExTimer.logMes("Raw File created ! Digits = " + std::to_string(mDigitsReceived) + " for Events =" + std::to_string(mEventsReceived)); + mExTimer.stop(); + pc.services().get().readyToQuit(framework::QuitRequest::Me); + return; +} + +void WriteRawFromRootTask::endOfStream(framework::EndOfStreamContext& ec) +{ + return; +} + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getWriteRawFromRootSpec(std::string inputSpec) +{ + std::vector inputs; + std::vector outputs; + + return DataProcessorSpec{ + "HMP-WriteRawFromRootFile", + inputs, + outputs, + AlgorithmSpec{adaptFromTask()}, + Options{{"hmp-raw-outdir", VariantType::String, "./", {"base dir for output file"}}, + {"hmp-raw-outfile", VariantType::String, "hmpReadOut", {"base name for output file"}}, + {"hmp-file-for", VariantType::String, "all", {"produce single file per: all, flp, link"}}, + {"hmp-raw-perflp", VariantType::Bool, false, {"produce one raw file per FLPs"}}, + {"in-file", VariantType::String, "hmpiddigits.root", {"name of the input sim root file"}}, + // {"configKeyValues", VariantType::String, "", {"comma-separated configKeyValues"}}, + {"dump-digits", VariantType::Bool, false, {"out the digits file in /tmp/hmpDumpDigits.dat"}}, + {"hmp-skip-empty", VariantType::Bool, false, {"skip empty events"}}}}; +} + +} // namespace hmpid +} // end namespace o2 diff --git a/Detectors/HMPID/workflow/src/write-root-from-digits-workflow.cxx b/Detectors/HMPID/workflow/src/digits-to-raw-workflow.cxx similarity index 80% rename from Detectors/HMPID/workflow/src/write-root-from-digits-workflow.cxx rename to Detectors/HMPID/workflow/src/digits-to-raw-workflow.cxx index d623ef9f0ff56..5bc64e9442c0b 100644 --- a/Detectors/HMPID/workflow/src/write-root-from-digits-workflow.cxx +++ b/Detectors/HMPID/workflow/src/digits-to-raw-workflow.cxx @@ -8,7 +8,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file write-root-from-digits-workflow.cxx +/// \file write-raw-from-root-workflow.cxx /// \author Antonio Franco - INFN Bari /// \version 1.0 /// \date 01 feb 2021 @@ -28,12 +28,12 @@ void customize(std::vector& policies) { using o2::framework::CompletionPolicy; using o2::framework::CompletionPolicyHelpers; - policies.push_back(CompletionPolicyHelpers::defineByName("digit-root-write", CompletionPolicy::CompletionOp::Consume)); + policies.push_back(CompletionPolicyHelpers::defineByName("digit-hmpid-write", CompletionPolicy::CompletionOp::Consume)); } #include "Framework/runDataProcessing.h" -#include "HMPIDWorkflow/WriteRootFromDigitsSpec.h" +#include "HMPIDWorkflow/WriteRawFromRootSpec.h" using namespace o2; using namespace o2::framework; @@ -42,7 +42,10 @@ WorkflowSpec defineDataProcessing(const ConfigContext&) { WorkflowSpec specs; - DataProcessorSpec consumer = o2::hmpid::getWriteRootFromDigitSpec(); + DataProcessorSpec consumer = o2::hmpid::getWriteRawFromRootSpec(); + // DataProcessorSpec consumer = o2::hmpid::getDecodingSpec(); specs.push_back(consumer); + // specs.push_back(consumer); + return specs; } diff --git a/Detectors/HMPID/workflow/src/digitstream-to-digits-workflow.cxx b/Detectors/HMPID/workflow/src/digitstream-to-digits-workflow.cxx new file mode 100644 index 0000000000000..5708e04d0aac1 --- /dev/null +++ b/Detectors/HMPID/workflow/src/digitstream-to-digits-workflow.cxx @@ -0,0 +1,61 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file write-root-from-digit-workflow.cxx +/// \author Antonio Franco - INFN Bari +/// \version 1.0 +/// \date 01 feb 2021 +/// + +#include "Framework/WorkflowSpec.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/CallbackService.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/Variant.h" + +#include "HMPIDWorkflow/WriteRootFromDigitsSpec.h" + +// customize the completion policy +void customize(std::vector& policies) +{ + using o2::framework::CompletionPolicy; + using o2::framework::CompletionPolicyHelpers; + policies.push_back(CompletionPolicyHelpers::defineByName("digit-root-write", CompletionPolicy::CompletionOp::Consume)); +} + +void customize(std::vector& workflowOptions) +{ + using o2::framework::ConfigParamSpec; + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", o2::framework::VariantType::String, "", {keyvaluehelp}}); +} + +#include "Framework/runDataProcessing.h" + +#include "HMPIDWorkflow/WriteRawFromDigitsSpec.h" + +using namespace o2; +using namespace o2::framework; + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + + DataProcessorSpec consumer = o2::hmpid::getWriteRootFromDigitSpec();// getWriteRawFromDigitsSpec(); + specs.push_back(consumer); + return specs; +} diff --git a/Detectors/HMPID/workflow/src/write-raw-from-digits-workflow.cxx b/Detectors/HMPID/workflow/src/digitstream-to-raw-workflow.cxx similarity index 100% rename from Detectors/HMPID/workflow/src/write-raw-from-digits-workflow.cxx rename to Detectors/HMPID/workflow/src/digitstream-to-raw-workflow.cxx diff --git a/Detectors/HMPID/workflow/src/raw-to-digits-workflow.cxx b/Detectors/HMPID/workflow/src/raw-to-digitstream-workflow.cxx similarity index 100% rename from Detectors/HMPID/workflow/src/raw-to-digits-workflow.cxx rename to Detectors/HMPID/workflow/src/raw-to-digitstream-workflow.cxx diff --git a/Steer/DigitizerWorkflow/src/HMPIDDigitWriterSpec.h b/Steer/DigitizerWorkflow/src/HMPIDDigitWriterSpec.h index 4d66a83fddd82..66c2875f48d3e 100644 --- a/Steer/DigitizerWorkflow/src/HMPIDDigitWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/HMPIDDigitWriterSpec.h @@ -15,6 +15,7 @@ #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "Framework/InputSpec.h" #include "HMPIDBase/Digit.h" +#include "HMPIDBase/Trigger.h" #include "SimulationDataFormat/MCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" @@ -35,6 +36,7 @@ o2::framework::DataProcessorSpec getHMPIDDigitWriterSpec(bool mctruth = true) "o2sim", 1, BranchDefinition>{InputSpec{"digitinput", "HMP", "DIGITS"}, "HMPDigit"}, + BranchDefinition>{InputSpec{"interactionrecods", "HMP", "INTRECORDS"}, "InteractionRecords"}, BranchDefinition>{InputSpec{"labelinput", "HMP", "DIGITLBL"}, "HMPDigitLabels", mctruth ? 1 : 0})(); } diff --git a/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx index 61d298248687f..874650ea55e72 100644 --- a/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx @@ -23,6 +23,7 @@ #include "Framework/Task.h" #include "DataFormatsParameters/GRPObject.h" #include "HMPIDBase/Digit.h" +#include "HMPIDBase/Trigger.h" #include "HMPIDSimulation/HMPIDDigitizer.h" #include "HMPIDSimulation/Detector.h" #include "DetectorsBase/BaseDPLDigitizer.h" @@ -61,7 +62,6 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer context->initSimChains(o2::detectors::DetID::HMP, mSimChains); auto& irecords = context->getEventRecords(); - for (auto& record : irecords) { LOG(INFO) << "HMPID TIME RECEIVED " << record.getTimeNS(); } @@ -69,6 +69,7 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer auto& eventParts = context->getEventParts(); std::vector digitsAccum; // accumulator for digits o2::dataformats::MCTruthContainer labelAccum; // timeframe accumulator for labels + mIntRecord.clear(); auto flushDigitsAndLabels = [this, &digitsAccum, &labelAccum]() { // flush previous buffer @@ -84,13 +85,11 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer // loop over all composite collisions given from context // (aka loop over all the interaction records) for (int collID = 0; collID < irecords.size(); ++collID) { - // try to start new readout cycle by setting the trigger time auto triggeraccepted = mDigitizer.setTriggerTime(irecords[collID].getTimeNS()); if (triggeraccepted) { flushDigitsAndLabels(); // flush previous readout cycle } - auto withinactivetime = mDigitizer.setEventTime(irecords[collID].getTimeNS()); if (withinactivetime) { // for each collision, loop over the constituents event and source IDs @@ -110,6 +109,10 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer mDigitizer.process(hits, mDigits); } + // save info for the triggers accepted + LOG(INFO) << "Trigger Orbit :" << mDigitizer.getOrbit() << " BC:" << mDigitizer.getBc(); + mIntRecord.push_back(o2::hmpid::Trigger(mDigitizer.getBc(), mDigitizer.getOrbit())); + } else { LOG(INFO) << "COLLISION " << collID << "FALLS WITHIN A DEAD TIME"; } @@ -119,6 +122,7 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer // send out to next stage pc.outputs().snapshot(Output{"HMP", "DIGITS", 0, Lifetime::Timeframe}, digitsAccum); + pc.outputs().snapshot(Output{"HMP", "INTRECORDS", 0, Lifetime::Timeframe}, mIntRecord); if (pc.outputs().isAllowed({"HMP", "DIGITLBL", 0})) { pc.outputs().snapshot(Output{"HMP", "DIGITLBL", 0, Lifetime::Timeframe}, labelAccum); } @@ -135,6 +139,7 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer std::vector mSimChains; std::vector mDigits; o2::dataformats::MCTruthContainer mLabels; // labels which get filled + std::vector mIntRecord; // RS: at the moment using hardcoded flag for continuous readout o2::parameters::GRPObject::ROMode mROMode = o2::parameters::GRPObject::CONTINUOUS; // readout mode @@ -149,6 +154,7 @@ o2::framework::DataProcessorSpec getHMPIDDigitizerSpec(int channel, bool mctruth // options that can be used for this processor (here: input file names where to take the hits) std::vector outputs; outputs.emplace_back("HMP", "DIGITS", 0, Lifetime::Timeframe); + outputs.emplace_back("HMP", "INTRECORDS", 0, Lifetime::Timeframe); if (mctruth) { outputs.emplace_back("HMP", "DIGITLBL", 0, Lifetime::Timeframe); }