From 46b6ee580e1158af8eb857dfebebc73d2cf4edc7 Mon Sep 17 00:00:00 2001 From: Dmitri Peresunko Date: Thu, 18 Feb 2021 13:10:54 +0300 Subject: [PATCH 1/8] CPV run3 geometry and readout --- .../CPV/include/DataFormatsCPV/Digit.h | 21 ++- .../CPV/include/DataFormatsCPV/RawFormats.h | 90 +++++++---- DataFormats/Detectors/CPV/src/Digit.cxx | 9 -- Detectors/CPV/base/include/CPVBase/Geometry.h | 18 ++- Detectors/CPV/base/src/Geometry.cxx | 62 ++++---- .../calib/include/CPVCalib/BadChannelMap.h | 2 +- .../CPV/calib/include/CPVCalib/CalibParams.h | 4 +- Detectors/CPV/calib/src/CalibParams.cxx | 2 +- .../include/CPVReconstruction/RawDecoder.h | 10 +- .../CPVReconstruction/RawReaderMemory.h | 4 +- .../CPV/reconstruction/src/RawDecoder.cxx | 112 +++++--------- .../reconstruction/src/RawReaderMemory.cxx | 19 +-- .../include/CPVSimulation/Detector.h | 12 +- .../include/CPVSimulation/Digitizer.h | 3 +- .../include/CPVSimulation/RawWriter.h | 20 +-- Detectors/CPV/simulation/src/Detector.cxx | 16 +- Detectors/CPV/simulation/src/Digitizer.cxx | 144 ++++++------------ Detectors/CPV/simulation/src/RawWriter.cxx | 115 +++++++------- 18 files changed, 302 insertions(+), 361 deletions(-) diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/Digit.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Digit.h index 8c5f83ea6c964..fef5313b10292 100644 --- a/DataFormats/Detectors/CPV/include/DataFormatsCPV/Digit.h +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Digit.h @@ -38,18 +38,8 @@ class Digit : public DigitBase /// particle in case of MC \return constructed Digit Digit(unsigned short cell, float amplitude, int label); - /// \brief Digit constructor from Hit - /// \param CPV Hit - /// \return constructed Digit - Digit(const Hit& hit, int label); - ~Digit() = default; // override - /// \brief Replace content of this digit with new one, from hit - /// \param CPV Hit - /// \return - void fillFromHit(const Hit& hit); - /// \brief Comparison oparator, based on time and absId /// \param another CPV Digit /// \return result of comparison: first time, if time same, then absId @@ -89,7 +79,7 @@ class Digit : public DigitBase bool canAdd(const Digit other) const; /// \brief if addable, adds energy and list of primaries. /// \param another CPV Digit - /// \return digit with sum of energies and longer list of primaries + /// \return digit with sum of energies Digit& operator+=(const Digit& other); // /// \brief Absolute sell id @@ -103,6 +93,15 @@ class Digit : public DigitBase /// \brief index of entry in MCLabels array /// \return ndex of entry in MCLabels array int getLabel() const { return mLabel; } + void setLabel(int l) { mLabel = l; } + + //put all parameters to default + void reset() + { + mAbsId = 0; + mLabel = -1; + mAmplitude = 0.; + } void PrintStream(std::ostream& stream) const; diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/RawFormats.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/RawFormats.h index b1d3b4677d30d..38a5e14b244a7 100644 --- a/DataFormats/Detectors/CPV/include/DataFormatsCPV/RawFormats.h +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/RawFormats.h @@ -17,43 +17,77 @@ namespace o2 namespace cpv { +//Pack information into 24 bit words union PadWord { uint32_t mDataWord; struct { - uint32_t charge : 11; ///< Bits 0 - 10 : charge - uint32_t address : 6; ///< Bits 12 - 17 : address (0..47) - uint32_t dilogic : 4; ///< Bits 18 - 21 : dilogic (1..10) - uint32_t row : 6; ///< Bits 22 - 26 : raw (1..24) - uint32_t zero : 1; ///< Bits 27 - 27 : zeroed so we can distinguish it from the EoE + uint32_t charge : 12; ///< Bits 0 - 11 : charge + uint32_t address : 6; ///< Bits 12 - 17 : address (0..47) + uint32_t gas : 3; ///< Bits 18 - 20 : gasiplex (1..10) + uint32_t dil : 2; ///< Bits 21 - 22 : dilogic (1..24) + uint32_t zero : 1; ///< Bits 23 - 23 : zeroed }; + char bytes[4]; }; -union EoEWord { - uint32_t mDataWord; - struct { - uint32_t nword : 7; ///< Bits 0 - 6 : word counter (0...47) - uint32_t en : 11; ///< Bits 7 - 17 : event number -- not used - uint32_t dilogic : 4; ///< Bits 18 - 21 : dilogic (1..10) - uint32_t row : 6; ///< Bits 22 - 26 : raw (1..24) - uint32_t checkbit : 1; ///< Bits 27 - 27 : bit 27 is always 1 by definition of EoE - }; -}; +class cpvword +{ + public: + cpvword() = default; + cpvword(std::vector::const_iterator b, std::vector::const_iterator e) + { //Reading + //resposibility of coller to esure that + //array will not end while reading + for (int i = 0; i < 16 && b != e; i++, b++) { + bytes[i] = *b; + } + } + ~cpvword() = default; + bool isOK() const + { + return (bytes[9] < static_cast(24)) && + (bytes[15] == 0) && (bytes[14] == 0) && (bytes[13] == 0) && (bytes[12] == 0) && (bytes[11] == 0) && (bytes[10] == 0); + } + short ccId() const { return short(bytes[9]); } + uint32_t cpvPadWord(int i) const + { + PadWord p = {0}; + p.bytes[0] = bytes[3 * i]; + p.bytes[1] = bytes[3 * i + 1]; + p.bytes[2] = bytes[3 * i + 2]; + return p.mDataWord; + } -union SegMarkerWord { - uint32_t mDataWord; - struct { - uint32_t row : 8; ///< Bits 0 - 7 : segment 0,1,2 charge - uint32_t nwords : 12; ///< Bits 8 - 19 : number of words in the segment - uint32_t marker : 12; ///< Bits 20 - 31: ab0 the segment marker word - }; + public: + unsigned char bytes[16] = {0}; }; -union RowMarkerWord { - uint32_t mDataWord; - struct { - uint32_t marker : 16; ///< Bits 0,15); //the marker word - uint32_t nwords : 16; ///< Bits 16 - 31 : number of words written after row marker (digits and EoE) - }; +class cpvtrailer +{ + public: + cpvtrailer() = default; + cpvtrailer(std::vector::const_iterator b, std::vector::const_iterator e) + { //reading + for (int i = 0; i < 16 && b != e; i++, b++) { + bytes[i] = *b; + } + } + cpvtrailer(unsigned short wordCounter) + { //writing + for (int i = 10; i < 16; i++) { + bytes[i] = 0; + } + bytes[9] = char(0xf0); + bytes[1] = (wordCounter & 0xff00) >> 8; + bytes[0] = (wordCounter & 0x00ff); + } + ~cpvtrailer() = default; + bool isOK() const { return (bytes[9] == 0xf0) && (bytes[10] == 0) && (bytes[11] == 0) && (bytes[12] == 0) && (bytes[13] == 0) && (bytes[14] == 0) && (bytes[15] == 0); } + short status() const { return short(bytes[8]); } + unsigned short wordCounter() const { return bytes[0] + (bytes[1] << 8); } + + public: + unsigned char bytes[16] = {0}; }; } // namespace cpv diff --git a/DataFormats/Detectors/CPV/src/Digit.cxx b/DataFormats/Detectors/CPV/src/Digit.cxx index b0968d45d6bb9..e1263f165229f 100644 --- a/DataFormats/Detectors/CPV/src/Digit.cxx +++ b/DataFormats/Detectors/CPV/src/Digit.cxx @@ -21,15 +21,6 @@ Digit::Digit(unsigned short absId, float amplitude, int label) : DigitBase(0), mAmplitude(amplitude), mAbsId(absId), mLabel(label) { } -Digit::Digit(const Hit& hit, int label) : mAbsId(hit.GetDetectorID()), mAmplitude(hit.GetEnergyLoss()), mLabel(label) -{ -} -void Digit::fillFromHit(const Hit& hit) -{ - mAbsId = hit.GetDetectorID(); - mAmplitude = hit.GetEnergyLoss(); -} - bool Digit::canAdd(const Digit other) const { return (mAbsId == other.getAbsId() && fabs(getTimeStamp() - other.getTimeStamp()) <= kTimeGate); diff --git a/Detectors/CPV/base/include/CPVBase/Geometry.h b/Detectors/CPV/base/include/CPVBase/Geometry.h index e3c49ce303ef7..634572043ac2b 100644 --- a/Detectors/CPV/base/include/CPVBase/Geometry.h +++ b/Detectors/CPV/base/include/CPVBase/Geometry.h @@ -31,7 +31,8 @@ class Geometry static constexpr float kCPVPadSizeZ = 2.1093; //for hwaddress static constexpr short kNPAD = 48; - static constexpr short kNDilogic = 10; + static constexpr short kNDilogic = 4; + static constexpr short kNGas = 5; static constexpr short kNRow = 16; static constexpr short kNMod = 4; @@ -87,8 +88,8 @@ class Geometry static void absIdToRelPosInModule(unsigned short absId, float& x, float& z); static bool relToAbsNumbering(const short* relId, unsigned short& absId); - static void hwaddressToAbsId(short ddl, short row, short dilogic, short hw, unsigned short& absId); - static void absIdToHWaddress(unsigned short absId, short& ddl, short& row, short& dilogic, short& hw); + static void hwaddressToAbsId(short ccId, short dil, short gas, short pad, unsigned short& absId); + static void absIdToHWaddress(unsigned short absId, short& ccId, short& dil, short& gas, short& pad); static unsigned short getTotalNPads() { return kNCHANNELS; } static bool IsPadExists(unsigned short absId) @@ -96,6 +97,17 @@ class Geometry return absId >= 0 && absId < getTotalNPads(); } // TODO: evaluate from real geometry + //Pad map per 3Gassiplex + //Fixed mapping + static constexpr short mPadMap[6][8] = {11, 9, 7, 17, 47, 43, 41, 39, + 15, 13, 5, 23, 45, 37, 35, 33, + 14, 12, 4, 25, 46, 38, 34, 32, + 10, 6, 2, 27, 21, 16, 40, 36, + 8, 1, 0, 28, 24, 20, 18, 42, + 3, 31, 30, 29, 26, 22, 19, 44}; + static constexpr short mPadToZ[48] = {4, 4, 3, 5, 2, 1, 3, 0, 4, 0, 3, 0, 2, 1, 2, 1, 3, 0, 4, 5, 4, 3, 5, 1, 4, 2, 5, 3, 4, 5, 5, 5, 2, 1, 2, 1, 3, 1, 2, 0, 3, 0, 4, 0, 5, 1, 2, 0}; + static constexpr short mPadToPhi[48] = {2, 1, 2, 0, 2, 2, 1, 2, 0, 1, 0, 0, 1, 1, 0, 0, 5, 3, 6, 6, 5, 4, 5, 3, 4, 3, 4, 3, 3, 3, 2, 1, 7, 7, 6, 6, 7, 5, 5, 7, 6, 6, 7, 5, 7, 4, 4, 4}; + ClassDefNV(Geometry, 1); }; } // namespace cpv diff --git a/Detectors/CPV/base/src/Geometry.cxx b/Detectors/CPV/base/src/Geometry.cxx index 5128a3be5ac3d..57094afc2ef5f 100644 --- a/Detectors/CPV/base/src/Geometry.cxx +++ b/Detectors/CPV/base/src/Geometry.cxx @@ -101,52 +101,52 @@ bool Geometry::relToAbsNumbering(const short* relId, unsigned short& absId) return true; } -void Geometry::hwaddressToAbsId(short /*ddl*/, short row, short dilog, short hw, unsigned short& absId) +void Geometry::hwaddressToAbsId(short ccId, short dil, short gas, short pad, unsigned short& absId) { - short mod = row / 16; - row = row % 16; - short relid[3] = {short(mod + 2), short(8 * row + hw % 8), short(6 * dilog + hw / 8)}; + + short pZ = mPadToZ[pad]; + short pPhi = mPadToPhi[pad]; + short relid[3] = {short(ccId / 8 + 2), short((ccId % 8) * 16 + (dil / 2) * 8 + 7 - pPhi), short((dil % 2) * 30 + gas * 6 + pZ)}; relToAbsNumbering(relid, absId); } -void Geometry::absIdToHWaddress(unsigned short absId, short& mod, short& row, short& dilogic, short& hw) +void Geometry::absIdToHWaddress(unsigned short absId, short& ccId, short& dil, short& gas, short& pad) { // Convert absId to hw address - // Arguments: w32,mod,row,dilogic,address where to write the results - // return row in range 0...47, packing rows from all modules in common numeration + // Arguments: ccId: 0 -- 7 - mod 2; 8...15 mod 3; 16...23 mod 4 + //dilogic: 0..3, gas=0..5, pad:0..47 short relid[3]; absToRelNumbering(absId, relid); - mod = relid[0]; // DDL# 2..4 - row = relid[1] / 8; // row# 0..16 - dilogic = relid[2] / 6; // Dilogic# 0..10 - hw = relid[1] % 8 + 8 * (relid[2] % 6); // Address 0..47 - - if (hw < 0 || hw > kNPAD) { - LOG(ERROR) << "Wrong hw address: hw=" << hw << " > kNPAD=" << kNPAD; - hw = 0; - dilogic = 0; - row = 0; - mod = 0; + ccId = (relid[0] - 2) * 8 + relid[1] / 16; + dil = 2 * ((relid[1] % 16) / 8) + relid[2] / 30; // Dilogic# 0..3 + gas = (relid[2] % 30) / 6; // gasiplex# 0..4 + pad = mPadMap[relid[2] % 6][7 - relid[1] % 8]; // pad 0..47 + + if (pad < 0 || pad > kNPAD) { + LOG(ERROR) << "Wrong pad address: pad=" << pad << " > kNPAD=" << kNPAD; + pad = 0; + dil = 0; + gas = 0; + ccId = 0; return; } - if (dilogic < 0 || dilogic > kNDilogic) { - LOG(ERROR) << "Wrong dilogic address: dilogic=" << dilogic << " > kNDilogic=" << kNDilogic; - hw = 0; - dilogic = 0; - row = 0; - mod = 0; + if (dil < 0 || dil >= kNDilogic) { + LOG(ERROR) << "Wrong dil address: dil=" << dil << " > kNDilogic=" << kNDilogic; + pad = 0; + dil = 0; + gas = 0; + ccId = 0; return; } - if (row < 0 || row > kNRow) { - LOG(ERROR) << "Wrong row address: row=" << row << " > kNRow=" << kNRow; - hw = 0; - dilogic = 0; - row = 0; - mod = 0; + if (gas < 0 || gas >= kNGas) { + LOG(ERROR) << "Wrong gasiplex address: gas=" << gas << " > kNGas=" << kNGas; + pad = 0; + dil = 0; + gas = 0; + ccId = 0; return; } - row += (mod - 2) * 16; } diff --git a/Detectors/CPV/calib/include/CPVCalib/BadChannelMap.h b/Detectors/CPV/calib/include/CPVCalib/BadChannelMap.h index d2ba63f23346f..f8cde9be80a55 100644 --- a/Detectors/CPV/calib/include/CPVCalib/BadChannelMap.h +++ b/Detectors/CPV/calib/include/CPVCalib/BadChannelMap.h @@ -131,7 +131,7 @@ class BadChannelMap void PrintStream(std::ostream& stream) const; private: - static constexpr unsigned short NCHANNELS = 30720; ///< Number of channels in modules 1-4 starting from 0 (4*128*60) + static constexpr unsigned short NCHANNELS = 23040; ///< Number of channels in modules 2-4 starting from 0 (3*128*60) std::bitset mBadCells; ///< Container for bad cells, 1 means bad sell ClassDefNV(BadChannelMap, 1); diff --git a/Detectors/CPV/calib/include/CPVCalib/CalibParams.h b/Detectors/CPV/calib/include/CPVCalib/CalibParams.h index 24af3097aa667..5ef59307bac8b 100644 --- a/Detectors/CPV/calib/include/CPVCalib/CalibParams.h +++ b/Detectors/CPV/calib/include/CPVCalib/CalibParams.h @@ -58,9 +58,9 @@ class CalibParams bool setGain(TH2* h, short module); private: - static constexpr short NCHANNELS = 28673; ///< Number of channels starting from 1 + static constexpr short NCHANNELS = 23040; ///< Number of channels starting from 0 std::array mGainCalib; ///< Container for the gain calibration coefficients - ClassDefNV(CalibParams, 1); + ClassDefNV(CalibParams, 2); }; } // namespace cpv diff --git a/Detectors/CPV/calib/src/CalibParams.cxx b/Detectors/CPV/calib/src/CalibParams.cxx index c2ee2487e5fca..1be71c1b260b2 100644 --- a/Detectors/CPV/calib/src/CalibParams.cxx +++ b/Detectors/CPV/calib/src/CalibParams.cxx @@ -28,7 +28,7 @@ CalibParams::CalibParams(short /*dummy*/) bool CalibParams::setGain(TH2* h, short module) { const short MAXX = 128, - MAXZ = 56; + MAXZ = 60; if (!h) { LOG(ERROR) << "no input histogam"; return false; diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/RawDecoder.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/RawDecoder.h index 9adfd45848a4d..4dd770c007a55 100644 --- a/Detectors/CPV/reconstruction/include/CPVReconstruction/RawDecoder.h +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/RawDecoder.h @@ -27,14 +27,14 @@ class RawDecoderError { public: RawDecoderError() = default; //Constructors for vector::emplace_back methods - RawDecoderError(short l, short r, short d, short p, RawErrorType_t e) : Ddl(l), Row(r), Dilogic(d), Pad(p), errortype(e) {} + RawDecoderError(short c, short d, short g, short p, RawErrorType_t e) : ccId(c), dil(d), gas(g), pad(p), errortype(e) {} RawDecoderError(const RawDecoderError& e) = default; ~RawDecoderError() = default; - short Ddl; - short Row; - short Dilogic; - short Pad; + short ccId; + short dil; + short gas; + short pad; RawErrorType_t errortype; ClassDefNV(RawDecoderError, 1); }; diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/RawReaderMemory.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/RawReaderMemory.h index 5492fc12086a3..711c2371d7f7c 100644 --- a/Detectors/CPV/reconstruction/include/CPVReconstruction/RawReaderMemory.h +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/RawReaderMemory.h @@ -81,7 +81,7 @@ class RawReaderMemory /// \brief access to the full raw payload (single or multiple DMA pages) /// \return Raw Payload of the data until the stop bit is received. - const std::vector& getPayload() const { return mRawPayload; } + const std::vector& getPayload() const { return mRawPayload; } /// \brief Return size of the payload /// \return size of the payload @@ -106,7 +106,7 @@ class RawReaderMemory private: gsl::span mRawMemoryBuffer; ///< Memory block with multiple DMA pages o2::header::RDHAny mRawHeader; ///< Raw header - std::vector mRawPayload; ///< Raw payload (can consist of multiple pages) + std::vector mRawPayload; ///< Raw payload (can consist of multiple pages) RCUTrailer mCurrentTrailer; ///< RCU trailer uint64_t mTrailerPayloadWords = 0; ///< Payload words in common trailer int mCurrentPosition = 0; ///< Current page in file diff --git a/Detectors/CPV/reconstruction/src/RawDecoder.cxx b/Detectors/CPV/reconstruction/src/RawDecoder.cxx index 8ac0ac45467b4..0f3f3f371159d 100644 --- a/Detectors/CPV/reconstruction/src/RawDecoder.cxx +++ b/Detectors/CPV/reconstruction/src/RawDecoder.cxx @@ -27,13 +27,13 @@ RawErrorType_t RawDecoder::decode() { auto& header = mRawReader.getRawHeader(); - short mod = o2::raw::RDHUtils::getFEEID(header); + short ddl = o2::raw::RDHUtils::getFEEID(header); mDigits.clear(); auto payloadwords = mRawReader.getPayload(); if (payloadwords.size() == 0) { - mErrors.emplace_back(mod, 0, 0, 0, kNO_PAYLOAD); //add error - LOG(ERROR) << "Empty payload for DDL=" << mod; + mErrors.emplace_back(ddl, 0, 0, 0, kNO_PAYLOAD); //add error + LOG(ERROR) << "Empty payload for DDL=" << ddl; return kNO_PAYLOAD; } @@ -56,75 +56,45 @@ RawErrorType_t RawDecoder::readChannels() { mChannelsInitialized = false; auto& header = mRawReader.getRawHeader(); - short mod = o2::raw::RDHUtils::getLinkID(header) + 2; //Current module + // short ddl = o2::raw::RDHUtils::getLinkID(header) ; //Current module auto& payloadwords = mRawReader.getPayload(); - //start reading from the end - auto currentWord = payloadwords.rbegin(); - while (currentWord != payloadwords.rend()) { - SegMarkerWord sw = {*currentWord++}; //first get value, then increment - if (sw.marker != 2736) { //error - LOG(ERROR) << "Seg. marker word not in place: marker=" << sw.marker << " expected " << 2736 << " word=" << sw.mDataWord; - mErrors.emplace_back(mod, 17, 2, 0, kSEGMENT_HEADER_ERROR); //add error for non-existing row - //try adding this as padWord - addDigit(sw.mDataWord, mod); - continue; - } - short nSegWords = sw.nwords; - short nEoE = 0; - while (nSegWords > 0 && currentWord != payloadwords.rend()) { - EoEWord ew = {*currentWord++}; - short currentRow = ew.row; - nSegWords--; - if (ew.checkbit != 1) { //error - LOG(ERROR) << " error EoE, mod" << mod << " row " << currentRow; - mErrors.emplace_back(mod, currentRow, 11, 0, kEOE_HEADER_ERROR); //add error - //try adding this as padWord - addDigit(ew.mDataWord, mod); - continue; - } - nEoE++; - short nEoEwords = ew.nword; - short currentDilogic = ew.dilogic; - if (currentDilogic < 0 || currentDilogic > 10) { - LOG(ERROR) << "wrong Dilogic in EoE=" << currentDilogic; - mErrors.emplace_back(mod, currentRow, currentDilogic, 0, kEOE_HEADER_ERROR); //add error - //try adding this as padWord - addDigit(ew.mDataWord, mod); - continue; - } - while (nEoEwords > 0 && currentWord != payloadwords.rend()) { - PadWord pad = {*currentWord++}; - nEoEwords--; - nSegWords--; - if (pad.zero != 0) { - LOG(ERROR) << "bad pad, word=" << pad.mDataWord; - mErrors.emplace_back(mod, currentRow, currentDilogic, 49, kPADERROR); //add error and skip word - continue; - } - //check paw/pad indexes - if (pad.row != currentRow || pad.dilogic != currentDilogic) { - LOG(ERROR) << "RawPad " << pad.row << " != currentRow=" << currentRow << "dilogicPad=" << pad.dilogic << "!= currentDilogic=" << currentDilogic; - mErrors.emplace_back(mod, short(pad.row), short(pad.dilogic), short(pad.address), kPadAddress); //add error and skip word - //do not skip, try adding using info from pad - } - addDigit(pad.mDataWord, mod); - } //pads in EoE - if (nEoE % 10 == 0) { // kNDilogic = 10; ///< Number of dilogic per row - if (currentWord != payloadwords.rend()) { //Read row HEader - RowMarkerWord rw = {*currentWord++}; - nSegWords--; - currentRow--; - if (rw.marker != 13992) { - LOG(ERROR) << "Error in row marker: " << rw.marker << "!=13992, row header word=" << rw.mDataWord; - mErrors.emplace_back(mod, currentRow, 11, 0, kPadAddress); //add error and skip word - //try adding digit assuming this is pad word - addDigit(rw.mDataWord, mod); + uint32_t wc = 0; + auto b = payloadwords.cbegin(); + auto e = payloadwords.cend(); + while (b != e) { + cpvword w(b, e); + if (w.isOK()) { + for (int i = 0; i < 3; i++) { + PadWord pw = {w.cpvPadWord(i)}; + if (pw.zero == 0) { + addDigit(pw.mDataWord, w.ccId()); + } else { + if (pw.mDataWord != 0xffffff) { //not empty pad + LOG(ERROR) << "no zero bit in data word " << pw.mDataWord; + mErrors.emplace_back(w.ccId(), 0, 0, 0, kPADERROR); //add error for non-existing row } } } - } // in Segment + } else { //this may be trailer + cpvtrailer tr(b, e); + if (tr.isOK()) { + if (tr.wordCounter() != wc) { + //some words lost? + LOG(ERROR) << "Read " << wc << " words, expected " << tr.wordCounter(); + mErrors.emplace_back(w.ccId(), 0, 0, 0, kPAYLOAD_DECODING); + //TODO! should we continuew or brake? + } + } else { + //error + LOG(ERROR) << "Read neither data nor trailer word"; + mErrors.emplace_back(w.ccId(), 0, 0, 0, kPADERROR); //add error for non-existing row + } + } + b += 16; + wc++; } + mChannelsInitialized = true; return kOK; } @@ -145,18 +115,12 @@ const std::vector& RawDecoder::getDigits() const return mDigits; } -void RawDecoder::addDigit(uint32_t w, short mod) +void RawDecoder::addDigit(uint32_t w, short ccId) { PadWord pad = {w}; - if (pad.zero != 0) { - return; - } - short rowPad = pad.row; - short dilogicPad = pad.dilogic; - short hw = pad.address; unsigned short absId; - o2::cpv::Geometry::hwaddressToAbsId(mod, rowPad, dilogicPad, hw, absId); + o2::cpv::Geometry::hwaddressToAbsId(ccId, pad.dil, pad.gas, pad.address, absId); AddressCharge ac = {0}; ac.Address = absId; diff --git a/Detectors/CPV/reconstruction/src/RawReaderMemory.cxx b/Detectors/CPV/reconstruction/src/RawReaderMemory.cxx index 701130be7ff27..0947166ea0854 100644 --- a/Detectors/CPV/reconstruction/src/RawReaderMemory.cxx +++ b/Detectors/CPV/reconstruction/src/RawReaderMemory.cxx @@ -84,7 +84,7 @@ RawErrorType_t RawReaderMemory::next() // Check if the data continues } while (!isDataTerminated); try { - mCurrentTrailer.constructFromPayloadWords(mRawPayload); + mCurrentTrailer.constructFromPayloadWords(gsl::span(reinterpret_cast(mRawPayload.data()), mRawPayload.size() / sizeof(uint32_t))); } catch (...) { return RawErrorType_t::kHEADER_DECODING; } @@ -118,25 +118,14 @@ RawErrorType_t RawReaderMemory::nextPage() return RawErrorType_t::kPAYLOAD_DECODING; } - auto tmp = reinterpret_cast(mRawMemoryBuffer.data()); - int start = (mCurrentPosition + RDHDecoder::getHeaderSize(mRawHeader)) / sizeof(uint32_t); - int end = start + (RDHDecoder::getMemorySize(mRawHeader) - RDHDecoder::getHeaderSize(mRawHeader)) / sizeof(uint32_t); + auto tmp = mRawMemoryBuffer.data(); + int start = (mCurrentPosition + RDHDecoder::getHeaderSize(mRawHeader)); + int end = start + (RDHDecoder::getMemorySize(mRawHeader) - RDHDecoder::getHeaderSize(mRawHeader)); for (auto iword = start; iword < end; iword++) { mRawPayload.push_back(tmp[iword]); } mCurrentPosition += RDHDecoder::getOffsetToNext(mRawHeader); /// Assume fixed 8 kB page size - /* - mCurrentTrailer.setPayloadSize(mCurrentTrailer.getPayloadSize() + trailer.getPayloadSize()); - tralersize = trailer.getTrailerSize(); - } - - gsl::span payloadWithoutTrailer(mRawBuffer.getDataWords().data(), mRawBuffer.getDataWords().size() - tralersize); - mRawPayload.appendPayloadWords(payloadWithoutTrailer); - mRawPayload.increasePageCount(); - } - mCurrentPosition += RDHDecoder::getOffsetToNext(mRawHeader); /// Assume fixed 8 kB page size -*/ return RawErrorType_t::kOK; } diff --git a/Detectors/CPV/simulation/include/CPVSimulation/Detector.h b/Detectors/CPV/simulation/include/CPVSimulation/Detector.h index 882c016c6d01a..8922c9a8cc9cc 100644 --- a/Detectors/CPV/simulation/include/CPVSimulation/Detector.h +++ b/Detectors/CPV/simulation/include/CPVSimulation/Detector.h @@ -68,13 +68,13 @@ class Detector : public o2::base::DetImpl /// /// Initializing detector /// - void InitializeO2Detector() override; + void InitializeO2Detector() final; /// /// Processing hit creation in the CPV crystalls /// /// \param[in] v Current sensitive volume - Bool_t ProcessHits(FairVolume* v = nullptr) override; + Bool_t ProcessHits(FairVolume* v = nullptr) final; /// /// Add CPV hit @@ -109,16 +109,16 @@ class Detector : public o2::base::DetImpl /// Reset /// Clean Hits collection /// - void Reset() override; + void Reset() final; /// Sort final hist - void FinishEvent() override; + void FinishEvent() final; /// /// Steps to be carried out at the end of the event /// For CPV cleaning the hit collection and the lookup table /// - void EndOfEvent() override; + void EndOfEvent() final; /// /// Specifies CPV modules as alignable volumes @@ -146,7 +146,7 @@ class Detector : public o2::base::DetImpl private: /// copy constructor (used in MT) Detector(const Detector& rhs); - Detector& operator=(const Detector&); + Detector& operator=(const Detector& rhs); /// Define the sensitive volumes of the geometry void defineSensitiveVolumes(); diff --git a/Detectors/CPV/simulation/include/CPVSimulation/Digitizer.h b/Detectors/CPV/simulation/include/CPVSimulation/Digitizer.h index 15ed82d696916..10dfc44b893b3 100644 --- a/Detectors/CPV/simulation/include/CPVSimulation/Digitizer.h +++ b/Detectors/CPV/simulation/include/CPVSimulation/Digitizer.h @@ -39,12 +39,13 @@ class Digitizer : public TObject int source, int entry, double dt); protected: - void addNoisyChannels(int start, int end, std::vector& digitsOut); float uncalibrate(float e, int absId); float simulateNoise(); private: + static constexpr short NCHANNELS = 23040; //128*60*3: toatl number of CPV channels std::unique_ptr mCalibParams; /// Calibration coefficients + std::array mArrayD; ClassDefOverride(Digitizer, 2); }; diff --git a/Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h b/Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h index ed72bdb71fc3d..0083572838c84 100644 --- a/Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h +++ b/Detectors/CPV/simulation/include/CPVSimulation/RawWriter.h @@ -33,10 +33,10 @@ namespace o2 namespace cpv { -static constexpr short kNMod = 3; ///< Total number of modules -static constexpr short kFirstMod = 2; ///< First available module +static constexpr short kNcc = 24; ///< Total number of column controllers static constexpr short kNPAD = 48; ///< Nuber of pads per dilogic -static constexpr short kNDilogic = 10; ///< Number of dilogic per row +static constexpr short kNDilogic = 4; ///< Number of dilogics +static constexpr short kNGasiplex = 5; ///< Number of dilogic per row static constexpr short kNRow = 48; ///< number of rows 16*3 mod struct padCharge { @@ -74,13 +74,13 @@ class RawWriter std::vector& trailer, std::vector& header) const; private: - std::vector mPadCharge[kNRow][kNDilogic]; ///< list of signals per event - FileFor_t mFileFor = FileFor_t::kFullDet; ///< Granularity of the output files - std::string mOutputLocation = "./"; ///< Rawfile name - std::unique_ptr mCalibParams; ///< CPV calibration - std::vector mPayload; ///< Payload to be written - gsl::span mDigits; ///< Digits input vector - must be in digitized format including the time response - std::unique_ptr mRawWriter; ///< Raw writer + std::vector mPadCharge[kNcc][kNDilogic][kNGasiplex]; ///< list of signals per event + FileFor_t mFileFor = FileFor_t::kFullDet; ///< Granularity of the output files + std::string mOutputLocation = "./"; ///< Rawfile name + std::unique_ptr mCalibParams; ///< CPV calibration + std::vector mPayload; ///< Payload to be written + gsl::span mDigits; ///< Digits input vector - must be in digitized format including the time response + std::unique_ptr mRawWriter; ///< Raw writer ClassDefNV(RawWriter, 1); }; diff --git a/Detectors/CPV/simulation/src/Detector.cxx b/Detectors/CPV/simulation/src/Detector.cxx index 012b07d665429..0bc36e4b0e9ac 100644 --- a/Detectors/CPV/simulation/src/Detector.cxx +++ b/Detectors/CPV/simulation/src/Detector.cxx @@ -96,12 +96,9 @@ void Detector::FinishEvent() mHits->erase(itr, mHits->end()); - // std::ostream stream(nullptr); - // stream.rdbuf(std::cout.rdbuf()); // uses cout's buffer - // stream.rdbuf(LOG(DEBUG2)); - // for (int i = 0; i < mHits->size(); i++) { - // mHits->at(i).PrintStream(stream); - // } + // printf("hits: %d \n",mHits->size()) ; + // int c=0; + // for(const Hit &h : *mHits){ if(h.GetDetectorID()GetStack(); - const Int_t partID = stack->GetCurrentTrackNumber(); + const int partID = stack->GetCurrentTrackNumber(); for (int iter = 0; iter < nIter; iter++) { @@ -263,19 +260,18 @@ Bool_t Detector::ProcessHits(FairVolume* v) float xg = (float)(ix - nx3) - xc; // Now calculate pad response - float qpad = padResponseFunction(qhit, zg, xg); + double qpad = padResponseFunction(qhit, zg, xg); qpad += cpvparam.mNoise * rnor2; if (qpad < 0) { continue; } // Fill hit with pad response ID and amplitude // hist will be sorted and merged later if necessary - short detID = Geometry::relToAbsId(moduleNumber, kxg, kzg); + int detID = Geometry::relToAbsId(moduleNumber, kxg, kzg); addHit(partID, detID, math_utils::Point3D(xyzm[0], xyzm[1], xyzm[2]), time, qpad); } } } - return true; } diff --git a/Detectors/CPV/simulation/src/Digitizer.cxx b/Detectors/CPV/simulation/src/Digitizer.cxx index f23a7de3aa925..2d0bc19d1227a 100644 --- a/Detectors/CPV/simulation/src/Digitizer.cxx +++ b/Detectors/CPV/simulation/src/Digitizer.cxx @@ -55,122 +55,76 @@ void Digitizer::processHits(const std::vector* hits, const std::vector::const_iterator dBg = digitsBg.cbegin(); - std::vector::const_iterator hBg = hits->cbegin(); - - bool addNoise = !(digitsBg.size()); //If digits list not empty, noise already there - - int currentId = 0; //first digit + if (digitsBg.size() == 0) { // no digits provided: try simulate noise + for (int i = NCHANNELS; i--;) { + float energy = simulateNoise(); + energy = uncalibrate(energy, i); + if (energy > o2::cpv::CPVSimParams::Instance().mZSthreshold) { + mArrayD[i].setAmplitude(energy); + mArrayD[i].setAbsId(i); + } + } + } else { //if digits exist, no noise should be added + for (auto& dBg : digitsBg) { //digits are sorted and unique + mArrayD[dBg.getAbsId()] = dBg; + } + } - while (dBg != digitsBg.cend() && hBg != hits->cend()) { - if (dBg->getAbsId() < hBg->GetDetectorID()) { // copy digit - //Digits already contain noise, no need to add it in this branch - //Digits have correct time, no need to add event time - digitsOut.emplace_back(dBg->getAbsId(), dBg->getAmplitude(), dBg->getLabel()); - currentId = dBg->getAbsId(); - dBg++; + //add Hits + for (auto& h : *hits) { + int i = h.GetDetectorID(); + if (mArrayD[i].getAmplitude() > 0) { + mArrayD[i].setAmplitude(mArrayD[i].getAmplitude() + uncalibrate(h.GetEnergyLoss(), i)); } else { - if (addNoise) { - addNoisyChannels(currentId, hBg->GetDetectorID(), digitsOut); - } - currentId = hBg->GetDetectorID(); - int labelIndex = -1; - if (dBg->getAbsId() == hBg->GetDetectorID()) { - labelIndex = dBg->getLabel(); - } + mArrayD[i].setAmplitude(uncalibrate(h.GetEnergyLoss(), i)); + mArrayD[i].setAbsId(i); + } + if (mArrayD[i].getAmplitude() > o2::cpv::CPVSimParams::Instance().mZSthreshold) { + int labelIndex = mArrayD[i].getLabel(); if (labelIndex == -1) { //no digit or noisy labelIndex = labels.getIndexedSize(); + o2::MCCompLabel label(h.GetTrackID(), collId, source, true); + labels.addElement(labelIndex, label); + mArrayD[i].setLabel(labelIndex); + } else { //check if lable already exist + gsl::span sp = labels.getLabels(labelIndex); + bool found = false; + for (MCCompLabel& te : sp) { + if (te.getTrackID() == h.GetTrackID() && te.getEventID() == collId && te.getSourceID() == source) { + found = true; + break; + } + } + if (!found) { + o2::MCCompLabel label(h.GetTrackID(), collId, source, true); + //Highly inefficient management of Labels: commenting line below reeduces WHOLE digitization time by factor ~30 + labels.addElementRandomAccess(labelIndex, label); + } } - Digit digit(*hBg, labelIndex); - // Add Electroinc noise, apply non-linearity, digitize, de-calibrate, time resolution - float energy = hBg->GetEnergyLoss(); - // Simulate electronic noise - short absId = hBg->GetDetectorID(); - energy += simulateNoise(); - - energy = uncalibrate(energy, absId); - - // Merge with existing digit if any - if (dBg->getAbsId() == hBg->GetDetectorID()) { - digit += *dBg; - dBg++; - } - - hBg++; - if (energy <= o2::cpv::CPVSimParams::Instance().mZSthreshold) { - continue; - } - - //Add primary info: create new MCLabels entry - o2::MCCompLabel label(hBg->GetTrackID(), collId, source, true); - labels.addElementRandomAccess(labelIndex, label); - - digitsOut.push_back(digit); } } - //Fill remainder - while (dBg != digitsBg.cend()) { - digitsOut.push_back(*dBg); - dBg++; - } - - while (hBg != hits->cend()) { - if (addNoise) { - addNoisyChannels(currentId, hBg->GetDetectorID(), digitsOut); - } - currentId = hBg->GetDetectorID(); - int labelIndex = labels.getIndexedSize(); - - Digit digit(*hBg, labelIndex); - // Add Electroinc noise - float energy = hBg->GetEnergyLoss(); - // Simulate electronic noise - short absId = hBg->GetDetectorID(); - energy += simulateNoise(); - energy = uncalibrate(energy, absId); - hBg++; - if (energy <= o2::cpv::CPVSimParams::Instance().mZSthreshold) { - continue; + for (int i = 0; i < NCHANNELS; i++) { + if (mArrayD[i].getAmplitude() > o2::cpv::CPVSimParams::Instance().mZSthreshold) { + digitsOut.push_back(mArrayD[i]); } - - //Add primary info: create new MCLabels entry - o2::MCCompLabel label(hBg->GetTrackID(), collId, source, true); - labels.addElement(labelIndex, label); - - digitsOut.push_back(digit); - } - - //Add noisy channels to the end of CPV - if (addNoise) { - addNoisyChannels(currentId, 128 * 60 * 3, digitsOut); } } float Digitizer::simulateNoise() { return gRandom->Gaus(0., o2::cpv::CPVSimParams::Instance().mNoise); } -//_______________________________________________________________________ -void Digitizer::addNoisyChannels(int start, int end, std::vector& digitsOut) -{ - - // Simulate noise - for (int absId = start + 1; absId < end; absId++) { - float energy = simulateNoise(); - energy = uncalibrate(energy, absId); - if (energy > o2::cpv::CPVSimParams::Instance().mZSthreshold) { - digitsOut.emplace_back(absId, energy, -1); // current AbsId, energy, random time, no primary - } - } -} - //_______________________________________________________________________ float Digitizer::uncalibrate(const float e, const int absId) { // Decalibrate CPV digit, i.e. transform from amplitude to ADC counts a factor read from CDB float calib = mCalibParams->getGain(absId); if (calib > 0) { - return floor(e / calib); + return e / calib; } else { return 0; // TODO apply de-calibration from OCDB } diff --git a/Detectors/CPV/simulation/src/RawWriter.cxx b/Detectors/CPV/simulation/src/RawWriter.cxx index 3c0d90a36f362..533e48d2a6079 100644 --- a/Detectors/CPV/simulation/src/RawWriter.cxx +++ b/Detectors/CPV/simulation/src/RawWriter.cxx @@ -69,79 +69,80 @@ bool RawWriter::processTrigger(const gsl::span digitsbranch, con { //Array used to sort properly digits - for (int j = kNRow; j--;) { - for (int k = kNDilogic; k--;) { - mPadCharge[j][k].clear(); + for (int i = kNcc; i--;) { + for (int j = kNDilogic; j--;) { + for (int k = kNGasiplex; k--;) { + mPadCharge[i][j][k].clear(); + } } } for (auto& dig : gsl::span(digitsbranch.data() + trg.getFirstEntry(), trg.getNumberOfObjects())) { short absId = dig.getAbsId(); - short mod, dilogic, row, hwAddr; - o2::cpv::Geometry::absIdToHWaddress(absId, mod, row, dilogic, hwAddr); + short ccId, dil, gas, pad; + o2::cpv::Geometry::absIdToHWaddress(absId, ccId, dil, gas, pad); //Convert Amp to ADC counts short charge = dig.getAmplitude() / mCalibParams->getGain(absId); - if (charge > 2047) { - charge = 2047; + if (charge > 4095) { + charge = 4095; } - mPadCharge[row][dilogic].emplace_back(charge, hwAddr); + mPadCharge[ccId][dil][gas].emplace_back(charge, pad); } //Do through DLLs and fill raw words in proper order mPayload.clear(); - //write empty header, later will be updated ? - - int nwInSegment = 0; - int posRowMarker = 0; - for (int row = 0; row < kNRow; row++) { - //reserve place for row header - mPayload.emplace_back(uint32_t(0)); - posRowMarker = mPayload.size() - 1; - nwInSegment++; - int nwRow = 0; - for (Int_t dilogic = 0; dilogic < kNDilogic; dilogic++) { - int nPad = 0; - for (padCharge& pc : mPadCharge[row][dilogic]) { - PadWord currentword = {0}; - currentword.charge = pc.charge; - currentword.address = pc.pad; - currentword.dilogic = dilogic; - currentword.row = row; - mPayload.push_back(currentword.mDataWord); - nwInSegment++; - nPad++; - nwRow++; + + int ccWordCounter = 0; + int gbtWordCounter = 0; + for (char ccId = 0; ccId < kNcc; ccId++) { + for (char dil = 0; dil < kNDilogic; dil++) { + for (char gas = 0; gas < kNGasiplex; gas++) { + for (padCharge& pc : mPadCharge[ccId][dil][gas]) { + // Generate 3 CC words, add CC header and empty bits to complete 128 bits; + PadWord currentword = {0}; + currentword.charge = pc.charge; + currentword.address = pc.pad; + currentword.gas = gas; + currentword.dil = dil; + mPayload.push_back(currentword.bytes[0]); + mPayload.push_back(currentword.bytes[1]); + mPayload.push_back(currentword.bytes[2]); + ccWordCounter++; + if (ccWordCounter % 3 == 0) { // complete 3 channels (72 bit) + CC index (8 bits) + 6 empty bits = Generate 128 bits of data + mPayload.push_back(ccId); + for (int i = 6; i--;) { + mPayload.push_back(char(0)); + } + gbtWordCounter++; + } + } + if (ccWordCounter % 3 != 0) { + while (ccWordCounter % 3 != 0) { + mPayload.push_back(char(255)); + mPayload.push_back(char(255)); + mPayload.push_back(char(255)); + ccWordCounter++; + } + mPayload.push_back(ccId); + for (int i = 6; i--;) { + mPayload.push_back(char(0)); + } + gbtWordCounter++; + } } - EoEWord we = {0}; - we.nword = nPad; - we.dilogic = dilogic; - we.row = row; - we.checkbit = 1; - mPayload.push_back(we.mDataWord); - nwInSegment++; - nwRow++; - } - if (row % 2 == 1) { - SegMarkerWord w = {0}; - w.row = row; - w.nwords = nwInSegment; - w.marker = 2736; - mPayload.push_back(w.mDataWord); - nwInSegment = 0; - nwRow++; } - //Now we know number of words, update rawMarker - RowMarkerWord wr = {0}; - wr.marker = 13992; - wr.nwords = nwRow - 1; - mPayload[posRowMarker] = wr.mDataWord; + } + cpvtrailer tr(gbtWordCounter); //cout GBT words + for (int i = 0; i < 16; i++) { + mPayload.push_back(tr.bytes[i]); } // register output data - LOG(DEBUG1) << "Adding payload with size " << mPayload.size() << " (" << mPayload.size() << " ALTRO words)"; - mRawWriter->addData(0, 0, 0, 0, trg.getBCData(), gsl::span(reinterpret_cast(mPayload.data()), mPayload.size() * sizeof(uint32_t))); + LOG(DEBUG1) << "Adding payload with size " << mPayload.size() << " char words)"; + + mRawWriter->addData(0, 0, 0, 0, trg.getBCData(), gsl::span(mPayload.data(), mPayload.size())); return true; } int RawWriter::carryOverMethod(const header::RDHAny* rdh, const gsl::span data, @@ -149,14 +150,14 @@ int RawWriter::carryOverMethod(const header::RDHAny* rdh, const gsl::span std::vector& trailer, std::vector& header) const { - constexpr int phosTrailerSize = 36; + constexpr int cpvTrailerSize = 36; int offs = ptr - &data[0]; // offset wrt the head of the payload assert(offs >= 0 && size_t(offs + maxSize) <= data.size()); // make sure ptr and end of the suggested block are within the payload int leftBefore = data.size() - offs; // payload left before this splitting int leftAfter = leftBefore - maxSize; // what would be left after the suggested splitting int actualSize = maxSize; - if (leftAfter && leftAfter <= phosTrailerSize) { // avoid splitting the trailer or writing only it. - actualSize -= (phosTrailerSize - leftAfter) + 4; // (as we work with int, not char in decoding) + if (leftAfter && leftAfter <= cpvTrailerSize) { // avoid splitting the trailer or writing only it. + actualSize -= (cpvTrailerSize - leftAfter) + 4; // (as we work with int, not char in decoding) } return actualSize; } From e52c10d5508044c0aef2070f8c21a1802b97ddfe Mon Sep 17 00:00:00 2001 From: Dmitri Peresunko Date: Sat, 20 Feb 2021 23:58:19 +0300 Subject: [PATCH 2/8] added digit and cluster readers and writers for PHOS and CPV. Fix PHOS Digitizer to consume un-sorted hits; Fixes in clusterizer. Make one-to-one correspondence between Cells and MCLabels; fix CPV geometry --- .../CPV/include/DataFormatsCPV/Cluster.h | 16 +- .../PHOS/include/DataFormatsPHOS/Digit.h | 12 + DataFormats/Detectors/PHOS/src/Digit.cxx | 9 + .../CPV/simulation/src/GeometryParams.cxx | 10 +- Detectors/CPV/workflow/CMakeLists.txt | 3 +- .../{PublisherSpec.h => ReaderSpec.h} | 20 +- .../include/CPVWorkflow/RecoWorkflow.h | 4 +- .../workflow/include/CPVWorkflow/WriterSpec.h | 31 +++ .../CPV/workflow/src/ClusterizerSpec.cxx | 2 +- Detectors/CPV/workflow/src/PublisherSpec.cxx | 152 ----------- Detectors/CPV/workflow/src/ReaderSpec.cxx | 232 +++++++++++++++++ Detectors/CPV/workflow/src/RecoWorkflow.cxx | 99 ++------ Detectors/CPV/workflow/src/WriterSpec.cxx | 98 ++++++++ .../CPV/workflow/src/cpv-reco-workflow.cxx | 6 +- .../PHOSPedestalCalibDevice.h | 3 + .../src/PHOSPedestalCalibDevice.cxx | 96 +++---- .../PHOS/calib/include/PHOSCalib/Pedestals.h | 13 + .../include/PHOSReconstruction/Clusterer.h | 6 +- .../PHOS/reconstruction/src/Clusterer.cxx | 50 ++-- .../include/PHOSSimulation/Digitizer.h | 10 +- Detectors/PHOS/simulation/src/Digitizer.cxx | 217 ++++++---------- Detectors/PHOS/workflow/CMakeLists.txt | 3 +- .../include/PHOSWorkflow/CellConverterSpec.h | 1 - .../{PublisherSpec.h => ReaderSpec.h} | 22 +- .../include/PHOSWorkflow/RecoWorkflow.h | 4 +- .../include/PHOSWorkflow/WriterSpec.h | 33 +++ .../PHOS/workflow/src/CellConverterSpec.cxx | 23 +- .../PHOS/workflow/src/ClusterizerSpec.cxx | 42 ++-- Detectors/PHOS/workflow/src/PublisherSpec.cxx | 179 ------------- Detectors/PHOS/workflow/src/ReaderSpec.cxx | 236 ++++++++++++++++++ Detectors/PHOS/workflow/src/RecoWorkflow.cxx | 86 +++---- Detectors/PHOS/workflow/src/WriterSpec.cxx | 99 ++++++++ .../PHOS/workflow/src/phos-reco-workflow.cxx | 6 +- .../src/PHOSDigitWriterSpec.h | 23 +- .../src/PHOSDigitizerSpec.cxx | 12 +- 35 files changed, 1095 insertions(+), 763 deletions(-) rename Detectors/CPV/workflow/include/CPVWorkflow/{PublisherSpec.h => ReaderSpec.h} (60%) create mode 100644 Detectors/CPV/workflow/include/CPVWorkflow/WriterSpec.h delete mode 100644 Detectors/CPV/workflow/src/PublisherSpec.cxx create mode 100644 Detectors/CPV/workflow/src/ReaderSpec.cxx create mode 100644 Detectors/CPV/workflow/src/WriterSpec.cxx rename Detectors/PHOS/workflow/include/PHOSWorkflow/{PublisherSpec.h => ReaderSpec.h} (56%) create mode 100644 Detectors/PHOS/workflow/include/PHOSWorkflow/WriterSpec.h delete mode 100644 Detectors/PHOS/workflow/src/PublisherSpec.cxx create mode 100644 Detectors/PHOS/workflow/src/ReaderSpec.cxx create mode 100644 Detectors/PHOS/workflow/src/WriterSpec.cxx diff --git a/DataFormats/Detectors/CPV/include/DataFormatsCPV/Cluster.h b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Cluster.h index 433d64353970c..803a19576f7cd 100644 --- a/DataFormats/Detectors/CPV/include/DataFormatsCPV/Cluster.h +++ b/DataFormats/Detectors/CPV/include/DataFormatsCPV/Cluster.h @@ -41,7 +41,7 @@ class Cluster public: Cluster() = default; - Cluster(char mult, char mod, char exMax, float x, float z, float e) : mMulDigit(mult), mModule(mod), mNExMax(exMax), mLocalPosX(x), mLocalPosZ(z), mEnergy(e) {} + Cluster(unsigned char mult, char mod, char exMax, float x, float z, float e) : mMulDigit(mult), mModule(mod), mNExMax(exMax), mLocalPosX(x), mLocalPosZ(z), mEnergy(e) {} Cluster(const Cluster& clu) = default; ~Cluster() = default; @@ -85,7 +85,7 @@ class Cluster uint8_t getPackedClusterStatus() const { CluStatus s = {0}; - s.multiplicity = mMulDigit; + s.multiplicity = std::min(mMulDigit, static_cast(31)); //5 bits available s.module = mModule; s.unfolded = mNExMax > 1; return s.mBits; @@ -107,12 +107,12 @@ class Cluster } protected: - char mMulDigit = 0; ///< Digit nultiplicity - char mModule = 0; ///< Module number - char mNExMax = -1; ///< number of (Ex-)maxima before unfolding - float mLocalPosX = 0.; ///< Center of gravity position in local module coordunates (phi direction) - float mLocalPosZ = 0.; ///< Center of gravity position in local module coordunates (z direction) - float mEnergy = 0.; ///< full energy of a cluster + unsigned char mMulDigit = 0; ///< Digit nultiplicity + char mModule = 0; ///< Module number + char mNExMax = -1; ///< number of (Ex-)maxima before unfolding + float mLocalPosX = 0.; ///< Center of gravity position in local module coordunates (phi direction) + float mLocalPosZ = 0.; ///< Center of gravity position in local module coordunates (z direction) + float mEnergy = 0.; ///< full energy of a cluster ClassDefNV(Cluster, 1); }; diff --git a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Digit.h b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Digit.h index 3eb61d9e5b837..f68d55ed5a61b 100644 --- a/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Digit.h +++ b/DataFormats/Detectors/PHOS/include/DataFormatsPHOS/Digit.h @@ -92,6 +92,8 @@ class Digit : public DigitBase /// \return digit with sum of energies and longer list of primaries Digit& operator+=(const Digit& other); // + void addEnergyTime(float energy, float time); + /// \brief Absolute sell id short getAbsId() const { return mAbsId; } void setAbsId(short cellId) { mAbsId = cellId; } @@ -111,6 +113,16 @@ class Digit : public DigitBase /// \brief index of entry in MCLabels array /// \return ndex of entry in MCLabels array int getLabel() const { return mLabel; } + void setLabel(int l) { mLabel = l; } + + void reset() + { + mIsHighGain = true; + mAbsId = 0; + mLabel = -1; + mAmplitude = 0; + mTime = 0; + } void PrintStream(std::ostream& stream) const; diff --git a/DataFormats/Detectors/PHOS/src/Digit.cxx b/DataFormats/Detectors/PHOS/src/Digit.cxx index 794c139273510..8cf06d0ba4e7d 100644 --- a/DataFormats/Detectors/PHOS/src/Digit.cxx +++ b/DataFormats/Detectors/PHOS/src/Digit.cxx @@ -58,6 +58,15 @@ Digit& Digit::operator+=(const Digit& other) return *this; } +void Digit::addEnergyTime(float energy, float time) +{ + // Adds the amplitude of digits + // TODO: What about time? Should we assign time of more energetic digit? More complicated treatment? + if (mAmplitude < energy) { + mTime = time; + } + mAmplitude += energy; +} void Digit::PrintStream(std::ostream& stream) const { diff --git a/Detectors/CPV/simulation/src/GeometryParams.cxx b/Detectors/CPV/simulation/src/GeometryParams.cxx index 6f955c7e82190..41ea284f0fced 100644 --- a/Detectors/CPV/simulation/src/GeometryParams.cxx +++ b/Detectors/CPV/simulation/src/GeometryParams.cxx @@ -72,15 +72,15 @@ GeometryParams::GeometryParams(const std::string_view name) double r = mIPtoCPVSurface + mCPVBoxSize[1]; for (Int_t iModule = 2; iModule < mNModules; iModule++) { double angle = moduleAngle * (iModule - 2); //Module 2 just below IP - mCPVAngle[iModule] = -angle; - mModuleCenter[iModule][0] = r * TMath::Sin(-angle / kRADDEG); - mModuleCenter[iModule][1] = -r * TMath::Cos(-angle / kRADDEG); + mCPVAngle[iModule] = angle; + mModuleCenter[iModule][0] = r * TMath::Sin(angle / kRADDEG); + mModuleCenter[iModule][1] = -r * TMath::Cos(angle / kRADDEG); mModuleCenter[iModule][2] = 0.; mModuleAngle[iModule][0][0] = 90; //thetaX polar angle for axis X - mModuleAngle[iModule][0][1] = -angle; //phiX azimuthal angle for axis X + mModuleAngle[iModule][0][1] = angle; //phiX azimuthal angle for axis X mModuleAngle[iModule][1][0] = 90; //thetaY polar angle for axis Y - mModuleAngle[iModule][1][1] = 90 - angle; //phiY azimuthal angle for axis Y + mModuleAngle[iModule][1][1] = 90 + angle; //phiY azimuthal angle for axis Y mModuleAngle[iModule][2][0] = 0; //thetaZ polar angle for axis Z mModuleAngle[iModule][2][1] = 0; //phiZ azimuthal angle for axis Z } diff --git a/Detectors/CPV/workflow/CMakeLists.txt b/Detectors/CPV/workflow/CMakeLists.txt index 8b6a4e6657690..905fa0dd5f2a0 100644 --- a/Detectors/CPV/workflow/CMakeLists.txt +++ b/Detectors/CPV/workflow/CMakeLists.txt @@ -10,7 +10,8 @@ o2_add_library(CPVWorkflow SOURCES src/RecoWorkflow.cxx - src/PublisherSpec.cxx + src/ReaderSpec.cxx + src/WriterSpec.cxx src/ClusterizerSpec.cxx src/DigitsPrinterSpec.cxx src/RawToDigitConverterSpec.cxx diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/PublisherSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/ReaderSpec.h similarity index 60% rename from Detectors/CPV/workflow/include/CPVWorkflow/PublisherSpec.h rename to Detectors/CPV/workflow/include/CPVWorkflow/ReaderSpec.h index 1c15a830ca78f..bc6a51573cf84 100644 --- a/Detectors/CPV/workflow/include/CPVWorkflow/PublisherSpec.h +++ b/Detectors/CPV/workflow/include/CPVWorkflow/ReaderSpec.h @@ -21,24 +21,8 @@ namespace cpv using OutputSpec = framework::OutputSpec; -struct PublisherConf { - struct BranchOptionConfig { - std::string option; - std::string defval; - std::string help; - }; - - std::string processName; - std::string defaultTreeName; - BranchOptionConfig databranch; - BranchOptionConfig datatrbranch; - BranchOptionConfig mcbranch; - OutputSpec dataoutput; - OutputSpec datatroutput; - OutputSpec mcoutput; -}; - -framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC = true); +framework::DataProcessorSpec getDigitsReaderSpec(bool propagateMC = true); +framework::DataProcessorSpec getClustersReaderSpec(bool propagateMC = true); } // namespace cpv } // end namespace o2 diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h b/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h index a8fae7398f615..c0535a89f5c25 100644 --- a/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h +++ b/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h @@ -35,7 +35,9 @@ enum struct OutputType { Digits, }; /// create the workflow for CPV reconstruction -framework::WorkflowSpec getWorkflow(bool propagateMC = true, +framework::WorkflowSpec getWorkflow(bool disableRootInp, + bool disableRootOut, + bool propagateMC = true, bool enableDigitsPrinter = false, std::string const& cfgInput = "digits", // std::string const& cfgOutput = "clusters" // diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/WriterSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/WriterSpec.h new file mode 100644 index 0000000000000..5de1976eba7df --- /dev/null +++ b/Detectors/CPV/workflow/include/CPVWorkflow/WriterSpec.h @@ -0,0 +1,31 @@ +// 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 ClusterWriterSpec.h + +#ifndef O2_CPV_WRITER +#define O2_CPV_WRITER + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace cpv +{ + +/// create a processor spec +/// write CPV clusters to ROOT file +framework::DataProcessorSpec getClusterWriterSpec(bool useMC); +framework::DataProcessorSpec getDigitWriterSpec(bool useMC); + +} // namespace cpv +} // namespace o2 + +#endif /* O2_CPV_WRITER */ \ No newline at end of file diff --git a/Detectors/CPV/workflow/src/ClusterizerSpec.cxx b/Detectors/CPV/workflow/src/ClusterizerSpec.cxx index 7a6ab4cde247f..565d1fb3191b5 100644 --- a/Detectors/CPV/workflow/src/ClusterizerSpec.cxx +++ b/Detectors/CPV/workflow/src/ClusterizerSpec.cxx @@ -30,7 +30,7 @@ void ClusterizerSpec::run(framework::ProcessingContext& ctx) { LOG(INFO) << "Start run "; LOG(DEBUG) << "CPVClusterizer - run on digits called"; - auto digits = ctx.inputs().get>("digits"); + auto digits = ctx.inputs().get>("digits"); // auto digitsTR = ctx.inputs().get>("digitTriggerRecords"); //TODO:: Why span does not work??? // auto digits = ctx.inputs().get>("digits"); auto digitsTR = ctx.inputs().get>("digitTriggerRecords"); diff --git a/Detectors/CPV/workflow/src/PublisherSpec.cxx b/Detectors/CPV/workflow/src/PublisherSpec.cxx deleted file mode 100644 index ee17eed725064..0000000000000 --- a/Detectors/CPV/workflow/src/PublisherSpec.cxx +++ /dev/null @@ -1,152 +0,0 @@ -// 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. - -#include "DataFormatsCPV/CPVBlockHeader.h" -#include "CPVWorkflow/PublisherSpec.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Headers/DataHeader.h" -#include "DPLUtils/RootTreeReader.h" -#include "Framework/DataSpecUtils.h" -#include -#include - -namespace o2 -{ - -namespace cpv -{ - -o2::framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC) -{ - struct ProcessAttributes { - std::shared_ptr reader; - std::string datatype; - bool terminateOnEod; - bool finished; - }; - - auto initFunction = [config, propagateMC](o2::framework::InitContext& ic) { - // get the option from the init context - auto filename = ic.options().get("infile"); - auto treename = ic.options().get("treename"); - auto dtbrName = ic.options().get(config.databranch.option.c_str()); // databranch name - auto dttrbrName = ic.options().get(config.datatrbranch.option.c_str()); // datatrigrec name - auto mcbrName = ic.options().get(config.mcbranch.option.c_str()); // mcbranch name - auto nofEvents = ic.options().get("nevents"); - // auto publishingMode = nofEvents == -1 ? o2::framework::RootTreeReader::PublishingMode::Single : o2::framework::RootTreeReader::PublishingMode::Loop; - auto publishingMode = o2::framework::RootTreeReader::PublishingMode::Single; - - auto processAttributes = std::make_shared(); - { - processAttributes->terminateOnEod = ic.options().get("terminate-on-eod"); - processAttributes->finished = false; - processAttributes->datatype = config.databranch.defval; - auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto dttro = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.datatroutput); - auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - constexpr auto persistency = o2::framework::Lifetime::Timeframe; - o2::header::DataHeader::SubSpecificationType subSpec = 0; - if (propagateMC) { - processAttributes->reader = std::make_shared(treename.c_str(), // tree name - filename.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, - dtbrName.c_str(), // name of data branch - o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, - dttrbrName.c_str(), // name of data triggerrecords branch - o2::framework::Output{mco.origin, mco.description, subSpec, persistency}, - mcbrName.c_str() // name of mc label branch - ); - } else { - processAttributes->reader = std::make_shared(treename.c_str(), // tree name - filename.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, - dtbrName.c_str(), // name of data branch - o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, - dttrbrName.c_str() // name of data tr branch - ); - } - } - - auto processFunction = [processAttributes, propagateMC](o2::framework::ProcessingContext& pc) { - if (processAttributes->finished) { - return; - } - - auto publish = [&processAttributes, &pc, propagateMC]() { - o2::cpv::CPVBlockHeader cpvheader(true); - if (processAttributes->reader->next()) { - (*processAttributes->reader)(pc, cpvheader); - } else { - processAttributes->reader.reset(); - return false; - } - return true; - }; - - bool active(true); - if (!publish()) { - active = false; - // Send dummy header with no payload option - o2::cpv::CPVBlockHeader dummyheader(false); - pc.outputs().snapshot(o2::framework::OutputRef{"output", 0, {dummyheader}}, 0); - pc.outputs().snapshot(o2::framework::OutputRef{"outputTR", 0, {dummyheader}}, 0); - if (propagateMC) { - pc.outputs().snapshot(o2::framework::OutputRef{"outputMC", 0, {dummyheader}}, 0); - } - } - if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { - pc.services().get().endOfStream(); - pc.services().get().readyToQuit(framework::QuitRequest::Me); - } - }; - - return processFunction; - }; - - auto createOutputSpecs = [&config, propagateMC]() { - std::vector outputSpecs; - auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto dttro = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.datatroutput); - auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - outputSpecs.emplace_back(o2::framework::OutputSpec{{"output"}, dto.origin, dto.description, 0, o2::framework::Lifetime::Timeframe}); - outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputTR"}, dttro.origin, dttro.description, 0, o2::framework::Lifetime::Timeframe}); - if (propagateMC) { - outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputMC"}, mco.origin, mco.description, 0, o2::framework::Lifetime::Timeframe}); - } - return std::move(outputSpecs); - }; - - auto& dtb = config.databranch; - auto& dttrb = config.datatrbranch; - auto& mcb = config.mcbranch; - return o2::framework::DataProcessorSpec{ - config.processName.c_str(), - o2::framework::Inputs{}, // no inputs - {createOutputSpecs()}, - o2::framework::AlgorithmSpec(initFunction), - o2::framework::Options{ - {"infile", o2::framework::VariantType::String, "", {"Name of the input file"}}, - {"treename", o2::framework::VariantType::String, config.defaultTreeName.c_str(), {"Name of input tree"}}, - {dtb.option.c_str(), o2::framework::VariantType::String, dtb.defval.c_str(), {dtb.help.c_str()}}, - {dttrb.option.c_str(), o2::framework::VariantType::String, dttrb.defval.c_str(), {dttrb.help.c_str()}}, - {mcb.option.c_str(), o2::framework::VariantType::String, mcb.defval.c_str(), {mcb.help.c_str()}}, - {"nevents", o2::framework::VariantType::Int, -1, {"number of events to run"}}, - {"terminate-on-eod", o2::framework::VariantType::Bool, true, {"terminate on end-of-data"}}, - }}; -} - -} // namespace cpv - -} // namespace o2 diff --git a/Detectors/CPV/workflow/src/ReaderSpec.cxx b/Detectors/CPV/workflow/src/ReaderSpec.cxx new file mode 100644 index 0000000000000..166488752c2e8 --- /dev/null +++ b/Detectors/CPV/workflow/src/ReaderSpec.cxx @@ -0,0 +1,232 @@ +// 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. + +#include "DataFormatsCPV/CPVBlockHeader.h" +#include "CPVWorkflow/ReaderSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Headers/DataHeader.h" +#include "DPLUtils/RootTreeReader.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/DataSpecUtils.h" +#include +#include + +using namespace o2::framework; + +namespace o2 +{ + +namespace cpv +{ + +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; + +struct ProcessAttributes { + std::shared_ptr reader; + std::string datatype; + bool terminateOnEod; + bool finished; +}; + +DataProcessorSpec getDigitsReaderSpec(bool propagateMC) +{ + + auto initFunction = [propagateMC](InitContext& ic) { + // get the option from the init context + auto filename = ic.options().get("infile"); + auto treename = ic.options().get("treename"); + auto nofEvents = ic.options().get("nevents"); + auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; + + auto processAttributes = std::make_shared(); + { + processAttributes->terminateOnEod = ic.options().get("terminate-on-eod"); + processAttributes->finished = false; + processAttributes->datatype = "CPVDigit"; + constexpr auto persistency = Lifetime::Timeframe; + o2::header::DataHeader::SubSpecificationType subSpec = 0; + if (propagateMC) { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"CPV", "DIGITS", subSpec, persistency}, + "CPVDigit", // name of data branch + Output{"CPV", "DIGITTRIGREC", subSpec, persistency}, + "CPVDigitTrigRecords", // name of data triggerrecords branch + Output{"CPV", "DIGITSMCTR", subSpec, persistency}, + "CPVDigitMCTruth"); // name of mc label branch + } else { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"CPV", "DIGITS", subSpec, persistency}, + "CPVDigit", // name of data branch + Output{"CPV", "DIGITTRIGREC", subSpec, persistency}, + "CPVDigitTrigRecords"); // name of data triggerrecords branch + } + } + + auto processFunction = [processAttributes, propagateMC](ProcessingContext& pc) { + if (processAttributes->finished) { + return; + } + + auto publish = [&processAttributes, &pc, propagateMC]() { + o2::cpv::CPVBlockHeader cpvheader(true); + if (processAttributes->reader->next()) { + (*processAttributes->reader)(pc, cpvheader); + } else { + processAttributes->reader.reset(); + return false; + } + return true; + }; + + bool active(true); + if (!publish()) { + active = false; + // Send dummy header with no payload option + o2::cpv::CPVBlockHeader dummyheader(false); + pc.outputs().snapshot(OutputRef{"output", 0, {dummyheader}}, 0); + pc.outputs().snapshot(OutputRef{"outputTR", 0, {dummyheader}}, 0); + if (propagateMC) { + pc.outputs().snapshot(OutputRef{"outputMC", 0, {dummyheader}}, 0); + } + } + if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(framework::QuitRequest::Me); + } + }; + return processFunction; + }; + + std::vector outputSpecs; + outputSpecs.emplace_back(OutputSpec{{"output"}, "CPV", "DIGITS", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"outputTR"}, "CPV", "DIGITTRIGREC", 0, Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(OutputSpec{{"outputMC"}, "CPV", "DIGITSMCTR", 0, Lifetime::Timeframe}); + } + + return DataProcessorSpec{ + "cpv-digit-reader", + Inputs{}, // no inputs + outputSpecs, + AlgorithmSpec(initFunction), + Options{ + {"infile", VariantType::String, "cpvdigits.root", {"Name of the input file"}}, + {"treename", VariantType::String, "o2sim", {"Name of input tree"}}, + {"nevents", VariantType::Int, -1, {"number of events to run, -1: inf loop"}}, + {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} + +DataProcessorSpec getClustersReaderSpec(bool propagateMC) +{ + + auto initFunction = [propagateMC](InitContext& ic) { + // get the option from the init context + auto filename = ic.options().get("infile"); + auto treename = ic.options().get("treename"); + auto nofEvents = ic.options().get("nevents"); + auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; + + auto processAttributes = std::make_shared(); + { + processAttributes->terminateOnEod = ic.options().get("terminate-on-eod"); + processAttributes->finished = false; + processAttributes->datatype = "CPVCluster"; + constexpr auto persistency = Lifetime::Timeframe; + o2::header::DataHeader::SubSpecificationType subSpec = 0; + if (propagateMC) { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"CPV", "CLUSTERS", subSpec, persistency}, + "CPVCluster", // name of data branch + Output{"CPV", "CLUSTERTRIGRECS", subSpec, persistency}, + "CPVClusterTrigRec", // name of data triggerrecords branch + Output{"CPV", "CLUSTERTRUEMC", subSpec, persistency}, + "CPVClusterTrueMC"); // name of mc label branch + } else { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"CPV", "CLUSTERS", subSpec, persistency}, + "CPVCluster", // name of data branch + Output{"CPV", "CLUSTERTRIGRECS", subSpec, persistency}, + "CPVClusterTrueMC"); // name of data triggerrecords branch + } + } + + auto processFunction = [processAttributes, propagateMC](ProcessingContext& pc) { + if (processAttributes->finished) { + return; + } + + auto publish = [&processAttributes, &pc, propagateMC]() { + o2::cpv::CPVBlockHeader cpvheader(true); + if (processAttributes->reader->next()) { + (*processAttributes->reader)(pc, cpvheader); + } else { + processAttributes->reader.reset(); + return false; + } + return true; + }; + + bool active(true); + if (!publish()) { + active = false; + // Send dummy header with no payload option + o2::cpv::CPVBlockHeader dummyheader(false); + pc.outputs().snapshot(OutputRef{"output", 0, {dummyheader}}, 0); + pc.outputs().snapshot(OutputRef{"outputTR", 0, {dummyheader}}, 0); + if (propagateMC) { + pc.outputs().snapshot(OutputRef{"outputMC", 0, {dummyheader}}, 0); + } + } + if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(framework::QuitRequest::Me); + } + }; + return processFunction; + }; + + std::vector outputSpecs; + outputSpecs.emplace_back(OutputSpec{{"output"}, "CPV", "CLUSTERS", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"outputTR"}, "CPV", "CLUSTERTRIGRECS", 0, Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(OutputSpec{{"outputMC"}, "CPV", "CLUSTERTRUEMC", 0, Lifetime::Timeframe}); + } + + return DataProcessorSpec{ + "cpv-cluster-reader", + Inputs{}, // no inputs + outputSpecs, + AlgorithmSpec(initFunction), + Options{ + {"infile", VariantType::String, "cpvclusters.root", {"Name of the input file"}}, + {"treename", VariantType::String, "o2sim", {"Name of input tree"}}, + {"nevents", VariantType::Int, -1, {"number of events to run, -1: inf loop"}}, + {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} + +} // namespace cpv + +} // namespace o2 diff --git a/Detectors/CPV/workflow/src/RecoWorkflow.cxx b/Detectors/CPV/workflow/src/RecoWorkflow.cxx index 927fa032ab5a2..64a3509836dfb 100644 --- a/Detectors/CPV/workflow/src/RecoWorkflow.cxx +++ b/Detectors/CPV/workflow/src/RecoWorkflow.cxx @@ -24,7 +24,8 @@ #include "DataFormatsCPV/TriggerRecord.h" #include "CPVWorkflow/RecoWorkflow.h" #include "CPVWorkflow/ClusterizerSpec.h" -#include "CPVWorkflow/PublisherSpec.h" +#include "CPVWorkflow/ReaderSpec.h" +#include "CPVWorkflow/WriterSpec.h" #include "CPVWorkflow/RawToDigitConverterSpec.h" //#include "CPVWorkflow/RawWriterSpec.h" #include "Framework/DataSpecUtils.h" @@ -45,16 +46,17 @@ namespace reco_workflow { const std::unordered_map InputMap{ + {"raw", InputType::Raw}, {"hits", InputType::Hits}, - {"digits", InputType::Digits}, - {"raw", InputType::Raw}}; + {"digits", InputType::Digits}}; const std::unordered_map OutputMap{ {"digits", OutputType::Digits}, - {"raw", OutputType::Raw}, {"clusters", OutputType::Clusters}}; -o2::framework::WorkflowSpec getWorkflow(bool propagateMC, +o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, + bool disableRootOut, + bool propagateMC, bool enableDigitsPrinter, std::string const& cfgInput, std::string const& cfgOutput) @@ -78,35 +80,31 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, o2::framework::WorkflowSpec specs; - // if (isEnabled(OutputType::Raw)) { - // // add Raw encoder - // specs.emplace_back(o2::cpv::reco_workflow::getRawWriterSpec()); - // } - + // //Raw to .... if (inputType == InputType::Raw) { //no explicit raw reader if (isEnabled(OutputType::Digits)) { specs.emplace_back(o2::cpv::reco_workflow::getRawToDigitConverterSpec()); + if (!disableRootOut) { + specs.emplace_back(o2::cpv::getDigitWriterSpec(false)); + } } if (isEnabled(OutputType::Clusters)) { // add clusterizer specs.emplace_back(o2::cpv::reco_workflow::getRawToDigitConverterSpec()); - specs.emplace_back(o2::cpv::reco_workflow::getClusterizerSpec(propagateMC)); + specs.emplace_back(o2::cpv::reco_workflow::getClusterizerSpec(false)); + if (!disableRootOut) { + specs.emplace_back(o2::cpv::getClusterWriterSpec(false)); + } } } + // Digits to .... if (inputType == InputType::Digits) { - // specs.emplace_back(o2::cpv::getPublisherSpec(PublisherConf{ - // "cpv-digit-reader", - // "o2sim", - // {"digitbranch", "CPVDigit", "Digit branch"}, - // {"digittrigger", "CPVDigitTrigRecords", "TrigRecords branch"}, - // {"mcbranch", "CPVDigitMCTruth", "MC label branch"}, - // o2::framework::OutputSpec{"CPV", "DIGITS"}, - // o2::framework::OutputSpec{"CPV", "DIGITTRIGREC"}, - // o2::framework::OutputSpec{"CPV", "DIGITSMCTR"}}, - // propagateMC)); + if (!disableRootInp) { + specs.emplace_back(o2::cpv::getDigitsReaderSpec(propagateMC)); + } // if (enableDigitsPrinter) { // specs.emplace_back(o2::cpv::reco_workflow::getDigitsPrinterSpec()); @@ -115,65 +113,12 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, if (isEnabled(OutputType::Clusters)) { // add clusterizer specs.emplace_back(o2::cpv::reco_workflow::getClusterizerSpec(propagateMC)); + if (!disableRootOut) { + specs.emplace_back(o2::cpv::getClusterWriterSpec(propagateMC)); + } } - - // if (isEnabled(OutputType::Raw)) { - // // add Raw encoder - // specs.emplace_back(o2::cpv::reco_workflow::getRawWriterSpec()); - // } } - // // check if the process is ready to quit - // // this is decided upon the meta information in the CPV block header, the operation is set - // // value kNoPayload in case of no data or no operation - // // see also PublisherSpec.cxx - // // in this workflow, the EOD is sent after the last real data, and all inputs will receive EOD, - // // so it is enough to check on the first occurence - // // FIXME: this will be changed once DPL can propagate control events like EOD - // auto checkReady = [](o2::framework::DataRef const& ref) { - // auto const* cpvheader = o2::framework::DataRefUtils::getHeader(ref); - // // sector number -1 indicates end-of-data - // if (cpvheader != nullptr) { - // // indicate normal processing if not ready and skip if ready - // if (!cpvheader->mHasPayload) { - // return std::make_tuple(o2::framework::MakeRootTreeWriterSpec::TerminationCondition::Action::SkipProcessing, true); - // } - // } - // return std::make_tuple(o2::framework::MakeRootTreeWriterSpec::TerminationCondition::Action::DoProcessing, false); - // }; - - // if (isEnabled(OutputType::Digits)) { - // using DigitOutputType = std::vector; - // using DTROutputType = std::vector; - - // specs.emplace_back(o2::framework::MakeRootTreeWriterSpec("cpv-digits-writer", "cpvdigits.root", "o2sim", - // -1, - // o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - // BranchDefinition{o2::framework::InputSpec{"data", "CPV", "DIGITS", 0}, - // "CPVDigit", - // "digit-branch-name"}, - // BranchDefinition{o2::framework::InputSpec{"data", "CPV", "DIGITTRIGREC", 0}, - // "CPVDigTR", - // "digittr-branch-name"}, - // BranchDefinition{o2::framework::InputSpec{"mc", "CPV", "DIGITSMCTR", 0}, - // "CPVDigitMCTruth", - // "digitmc-branch-name"})()); - // } - - // if (isEnabled(OutputType::Clusters)) { - // specs.emplace_back(o2::framework::MakeRootTreeWriterSpec("cpv-clusters-writer", "cpvclusters.root", "o2sim", -1, - // o2::framework::MakeRootTreeWriterSpec::TerminationCondition{checkReady}, - // BranchDefinition>{o2::framework::InputSpec{"data", "CPV", "CLUSTERS", 0}, - // "CPVCluster", - // "cluster-branch-name"}, - // BranchDefinition>{o2::framework::InputSpec{"datatr", "CPV", "CLUSTERTRIGRECS", 0}, - // "CPVClusTR", - // "clustertr-branch-name"}, - // BranchDefinition>{o2::framework::InputSpec{"mc", "CPV", "CLUSTERTRUEMC", 0}, - // "CPVClusMC", - // "clustermc-branch-name"})()); - // } - return std::move(specs); } diff --git a/Detectors/CPV/workflow/src/WriterSpec.cxx b/Detectors/CPV/workflow/src/WriterSpec.cxx new file mode 100644 index 0000000000000..cf4d7d9922c5a --- /dev/null +++ b/Detectors/CPV/workflow/src/WriterSpec.cxx @@ -0,0 +1,98 @@ +// 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 ClusterWriterSpec.cxx + +#include + +#include "CPVWorkflow/WriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsCPV/Cluster.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace cpv +{ + +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; +using ClusType = std::vector; +using DigitType = std::vector; +using TriggerRecordType = std::vector; +using MCLabelType = o2::dataformats::MCTruthContainer; +using namespace o2::header; + +DataProcessorSpec getClusterWriterSpec(bool useMC) +{ + // Spectators for logging + // this is only to restore the original behavior + auto ClustersSize = std::make_shared(0); + auto ClustersSizeGetter = [ClustersSize](ClusType const& Clusters) { + *ClustersSize = Clusters.size(); + }; + + if (useMC) { + return MakeRootTreeWriterSpec("cpv-cluster-writer", + "cpvclusters.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with CPV clusters"}, + BranchDefinition{InputSpec{"clus", "CPV", "CLUSTERS", 0}, + "CPVCluster", ClustersSizeGetter}, + BranchDefinition{InputSpec{"clusRecs", "CPV", "CLUSTERTRIGRECS", 0}, + "CPVClusterTrigRec"}, + BranchDefinition{InputSpec{"clusMC", "CPV", "CLUSTERTRUEMC", 0}, + "CPVClusterTrueMC"})(); + } else { + return MakeRootTreeWriterSpec("cpv-cluster-writer", + "cpvclusters.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with CPV clusters"}, + BranchDefinition{InputSpec{"clus", "CPV", "CLUSTERS", 0}, + "CPVCluster", ClustersSizeGetter}, + BranchDefinition{InputSpec{"clusRecs", "CPV", "CLUSTERTRIGRECS", 0}, + "CPVClusterTrigRec"})(); + } +} + +DataProcessorSpec getDigitWriterSpec(bool useMC) +{ + // Spectators for logging + // this is only to restore the original behavior + auto DigitsSize = std::make_shared(0); + auto DigitsSizeGetter = [DigitsSize](DigitType const& Digits) { + *DigitsSize = Digits.size(); + }; + + if (useMC) { + return MakeRootTreeWriterSpec("cpv-digit-writer", + "cpvdigits.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with CPV digits"}, + BranchDefinition{InputSpec{"CPVDigit", "CPV", "DIGITS", 0}, + "CPVDigit", DigitsSizeGetter}, + BranchDefinition{InputSpec{"CPVDigitTrigRecords", "CPV", "DIGITTRIGREC", 0}, + "CPVDigitTrigRecords"}, + BranchDefinition{InputSpec{"clusMC", "CPV", "DIGITSMCTR", 0}, + "CPVDigitMCTruth"})(); + } else { + return MakeRootTreeWriterSpec("cpv-digit-writer", + "cpvdigits.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with CPV digits"}, + BranchDefinition{InputSpec{"CPVDigit", "CPV", "DIGITS", 0}, + "CPVDigit", DigitsSizeGetter}, + BranchDefinition{InputSpec{"CPVDigitTrigRecords", "CPV", "DIGITTRIGREC", 0}, + "CPVDigitTrigRecords"})(); + } +} + +} // namespace cpv +} // namespace o2 \ No newline at end of file diff --git a/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx b/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx index 5e9c40adc17aa..73b5affd1a79b 100644 --- a/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx +++ b/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx @@ -31,6 +31,8 @@ void customize(std::vector& workflowOptions) {"output-type", o2::framework::VariantType::String, "digits", {"digits, clusters"}}, {"enable-digits-printer", o2::framework::VariantType::Bool, false, {"enable digits printer component"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, }; std::swap(workflowOptions, options); } @@ -52,7 +54,9 @@ void customize(std::vector& workflowOptions) o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { // - return o2::cpv::reco_workflow::getWorkflow(not cfgc.options().get("disable-mc"), // + return o2::cpv::reco_workflow::getWorkflow(cfgc.options().get("disable-root-input"), + cfgc.options().get("disable-root-output"), + !cfgc.options().get("disable-mc"), // cfgc.options().get("enable-digits-printer"), // cfgc.options().get("input-type"), // cfgc.options().get("output-type") // diff --git a/Detectors/PHOS/calib/PHOSCalibWorkflow/include/PHOSCalibWorkflow/PHOSPedestalCalibDevice.h b/Detectors/PHOS/calib/PHOSCalibWorkflow/include/PHOSCalibWorkflow/PHOSPedestalCalibDevice.h index 6fc7495e9721c..9fb55dd55d19b 100644 --- a/Detectors/PHOS/calib/PHOSCalibWorkflow/include/PHOSCalibWorkflow/PHOSPedestalCalibDevice.h +++ b/Detectors/PHOS/calib/PHOSCalibWorkflow/include/PHOSCalibWorkflow/PHOSPedestalCalibDevice.h @@ -52,8 +52,11 @@ class PHOSPedestalCalibDevice : public o2::framework::Task bool mUseCCDB = false; bool mForceUpdate = false; /// Update CCDB even if difference to current is large bool mUpdateCCDB = true; /// set is close to current and can update it + static constexpr short kMinorChange = 10; /// ignore if number of channels changed smaller than... + long mRunStartTime = 0; /// start time of the run (sec) std::string mPath{"./"}; ///< path and name of file with collected histograms std::unique_ptr mPedestals; /// Final calibration object + std::unique_ptr mOldPed; /// Pedestals currently stored in CCDB for comparisoin std::unique_ptr mMapping; /// Mapping std::unique_ptr mRawFitter; /// Sample fitting class std::unique_ptr mMeanHG; /// Mean values in High Gain channels diff --git a/Detectors/PHOS/calib/PHOSCalibWorkflow/src/PHOSPedestalCalibDevice.cxx b/Detectors/PHOS/calib/PHOSCalibWorkflow/src/PHOSPedestalCalibDevice.cxx index c46cba1327dad..894de652cf19c 100644 --- a/Detectors/PHOS/calib/PHOSCalibWorkflow/src/PHOSPedestalCalibDevice.cxx +++ b/Detectors/PHOS/calib/PHOSCalibWorkflow/src/PHOSPedestalCalibDevice.cxx @@ -14,6 +14,7 @@ #include #include "FairLogger.h" #include "CommonDataFormat/InteractionRecord.h" +#include "DetectorsCalibration/Utils.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" #include "Framework/WorkflowSpec.h" @@ -53,6 +54,11 @@ void PHOSPedestalCalibDevice::init(o2::framework::InitContext& ic) void PHOSPedestalCalibDevice::run(o2::framework::ProcessingContext& ctx) { + //Read current padestals for comarison + // if (mUseCCDB && mOldPed.get()==nullptr) { + // mOldPed.reset(std::move(ctx.inputs().get("oldPedestals"))); + // } + // for (const auto& rawData : framework::InputRecordWalker(ctx.inputs())) { @@ -78,7 +84,10 @@ void PHOSPedestalCalibDevice::run(o2::framework::ProcessingContext& ctx) auto triggerOrbit = o2::raw::RDHUtils::getTriggerOrbit(header); auto ddl = o2::raw::RDHUtils::getFEEID(header); - o2::InteractionRecord currentIR(triggerBC, triggerOrbit); + if (mRunStartTime == 0) { + o2::InteractionRecord currentIR(triggerBC, triggerOrbit); + mRunStartTime = long(currentIR.bc2ns() * 1.e-9); + } if (ddl > o2::phos::Mapping::NDDL) { //only 14 correct DDLs LOG(ERROR) << "DDL=" << ddl; @@ -129,7 +138,9 @@ void PHOSPedestalCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) LOG(INFO) << "[PHOSPedestalCalibDevice - endOfStream]"; //calculate stuff here - //......... + calculatePedestals(); + + checkPedestals(); sendOutput(ec.outputs()); } @@ -148,19 +159,16 @@ void PHOSPedestalCalibDevice::sendOutput(DataAllocator& output) info.setPath("PHOS/Calib/Pedestals"); info.setObjectType("Pedestals"); info.setFileName(flName); - // TODO: should be changed to time of the run - const auto now = std::chrono::system_clock::now(); - long timeStart = std::chrono::duration_cast(now.time_since_epoch()).count(); - info.setStartValidityTimestamp(timeStart); + info.setStartValidityTimestamp(mRunStartTime); info.setEndValidityTimestamp(99999999999999); std::map md; info.setMetaData(md); LOG(INFO) << "Sending object PHOS/Calib/Pedestals"; - // header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)0}; - // output.snapshot(Output{o2::calibration::Utils::gDataOriginCLB, o2::calibration::Utils::gDataDescriptionCLBPayload, subSpec}, *image.get()); - // output.snapshot(Output{o2::calibration::Utils::gDataOriginCLB, o2::calibration::Utils::gDataDescriptionCLBInfo, subSpec}, info); + header::DataHeader::SubSpecificationType subSpec{(header::DataHeader::SubSpecificationType)0}; + output.snapshot(Output{o2::calibration::Utils::gDataOriginCLB, o2::calibration::Utils::gDataDescriptionCLBPayload, subSpec}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCLB, o2::calibration::Utils::gDataDescriptionCLBInfo, subSpec}, info); } //Anyway send change to QC LOG(INFO) << "[PHOSPedestalCalibDevice - run] Sending QC "; @@ -204,54 +212,50 @@ void PHOSPedestalCalibDevice::checkPedestals() mUpdateCCDB = true; return; } - // //TODO: - // //Get current map - // int nChanged=0; - // for(short i=o2::phos::Mapping::NCHANNELS; --i;){ - // short dp=mPedestals.getHGPedestal(i)-oldPed.getHGPedestal(i); - // mPedHGDiff[i]=dp ; - // if(abs(dp)>1){ //not a fluctuation - // nChanged++; - // } - // dp=mPedestals.getLGPedestal(i)-oldPed.getLGPedestal(i); - // mPedLGDiff[i]=dp ; - // if(abs(dp)>1){ //not a fluctuation - // nChanged++; - // } - // } - // if(nChanged>kMinorChange){ //serious change, do not update CCDB automatically, use "force" option to overwrite - // mUpdateCCDB=false; - // } - // else{ - // mUpdateCCDB=true; - // } + + if (mOldPed.get() == nullptr) { //was not read from CCDB, but expected + mUpdateCCDB = false; + return; + } + + //Compare to current + int nChanged = 0; + for (short i = o2::phos::Mapping::NCHANNELS; --i;) { + short dp = mPedestals->getHGPedestal(i) - mOldPed->getHGPedestal(i); + mPedHGDiff[i] = dp; + if (abs(dp) > 1) { //not a fluctuation + nChanged++; + } + dp = mPedestals->getLGPedestal(i) - mOldPed->getLGPedestal(i); + mPedLGDiff[i] = dp; + if (abs(dp) > 1) { //not a fluctuation + nChanged++; + } + } + if (nChanged > kMinorChange) { //serious change, do not update CCDB automatically, use "force" option to overwrite + mUpdateCCDB = false; + } else { + mUpdateCCDB = true; + } } o2::framework::DataProcessorSpec o2::phos::getPedestalCalibSpec(bool useCCDB, bool forceUpdate, std::string path) { + std::vector inputs; + inputs.emplace_back("RAWDATA", o2::framework::ConcreteDataTypeMatcher{"PHS", "RAWDATA"}, o2::framework::Lifetime::Timeframe); + if (useCCDB) { + // inputs.emplace_back("oldPedestals", "PHOS", "Pedestals"); + inputs.emplace_back("oldPedestals", o2::header::gDataOriginPHS, "Pedestals"); + } + std::vector outputs; outputs.emplace_back("PHS", "PEDCALIBS", 0, o2::framework::Lifetime::Timeframe); outputs.emplace_back("PHS", "PEDDIFF", 0, o2::framework::Lifetime::Timeframe); return o2::framework::DataProcessorSpec{"PedestalCalibSpec", - o2::framework::select("A:PHS/RAWDATA"), + inputs, outputs, o2::framework::adaptFromTask(useCCDB, forceUpdate, path), o2::framework::Options{}}; } - -// void list_files(const char *dirname="./", const char *pattern="collPHOS_*.root", std::vector &vnames) { -// TSystemDirectory dir(dirname, dirname); -// TList *files = dir.GetListOfFiles(); -// if (files){ -// TSystemFile *file; -// TString fname; -// TIter next(files); -// while ((file=(TSystemFile*)next())) { -// fname = file->GetName(); -// if (!file->IsDirectory() && fname.Index(pattern) > -1) { -// vnames.emplace_back(fname.Data()) ; -// } -// } -// } diff --git a/Detectors/PHOS/calib/include/PHOSCalib/Pedestals.h b/Detectors/PHOS/calib/include/PHOSCalib/Pedestals.h index c1debf104b930..efdc9ff417536 100644 --- a/Detectors/PHOS/calib/include/PHOSCalib/Pedestals.h +++ b/Detectors/PHOS/calib/include/PHOSCalib/Pedestals.h @@ -48,6 +48,19 @@ class Pedestals /// \brief Constructor for tests Pedestals(int test); + Pedestals(Pedestals* other) + { + mHGPedestals = other->mHGPedestals; + mLGPedestals = other->mLGPedestals; + } + + Pedestals& operator=(const Pedestals& other) + { + mHGPedestals = other.mHGPedestals; + mLGPedestals = other.mLGPedestals; + return *this; + } + /// \brief Destructor ~Pedestals() = default; diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/Clusterer.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/Clusterer.h index 4e66c0e37c62d..ba20f91666835 100644 --- a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/Clusterer.h +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/Clusterer.h @@ -40,7 +40,7 @@ class Clusterer std::vector* clusters, std::vector* rigRec, o2::dataformats::MCTruthContainer* cluMC); void processCells(gsl::span digits, gsl::span dtr, - const o2::dataformats::MCTruthContainer* dmc, gsl::span mcmap, + const o2::dataformats::MCTruthContainer* dmc, std::vector* clusters, std::vector* rigRec, o2::dataformats::MCTruthContainer* cluMC); @@ -55,7 +55,7 @@ class Clusterer void unfoldOneCluster(FullCluster& iniClu, char nMax, gsl::span digitId, gsl::span digits); protected: - void convertCellsToDigits(gsl::span cells, int firstCellInEvent, int lastCellInEvent, gsl::span mcmap); + void convertCellsToDigits(gsl::span cells, int firstCellInEvent, int lastCellInEvent); //Calibrate energy inline float calibrate(float amp, short absId) { return amp * mCalibParams->getGain(absId); } @@ -73,6 +73,8 @@ class Clusterer inline bool isBadChannel(short absId) { return (!mBadMap->isChannelGood(absId)); } protected: + bool mProcessMC = false; + int miCellLabel = 0; Geometry* mPHOSGeom = nullptr; ///< PHOS geometry std::unique_ptr mCalibParams; ///! Calibration coefficients std::unique_ptr mBadMap; ///! Bad map diff --git a/Detectors/PHOS/reconstruction/src/Clusterer.cxx b/Detectors/PHOS/reconstruction/src/Clusterer.cxx index ef658fb872357..b91f7fe6db6d5 100644 --- a/Detectors/PHOS/reconstruction/src/Clusterer.cxx +++ b/Detectors/PHOS/reconstruction/src/Clusterer.cxx @@ -94,7 +94,7 @@ void Clusterer::process(gsl::span digits, gsl::span cells, gsl::span ctr, - const o2::dataformats::MCTruthContainer* dmc, gsl::span mcmap, + const o2::dataformats::MCTruthContainer* dmc, std::vector* clusters, std::vector* trigRec, o2::dataformats::MCTruthContainer* cluMC) { @@ -102,8 +102,11 @@ void Clusterer::processCells(gsl::span cells, gsl::spanclear(); //final out list of clusters trigRec->clear(); cluMC->clear(); - + mProcessMC = (dmc != nullptr); + miCellLabel = 0; + printf("start clustering \n"); for (const auto& tr : ctr) { + printf(" tf=%d, %d \n", tr.getFirstEntry(), tr.getNumberOfObjects()); int firstCellInEvent = tr.getFirstEntry(); int lastCellInEvent = firstCellInEvent + tr.getNumberOfObjects(); int indexStart = clusters->size(); @@ -113,8 +116,10 @@ void Clusterer::processCells(gsl::span cells, gsl::span cells, gsl::spansize(); @@ -150,33 +160,17 @@ void Clusterer::processCells(gsl::span cells, gsl::span cells, int firstCellInEvent, int lastCellInEvent, gsl::span mcmap) +void Clusterer::convertCellsToDigits(gsl::span cells, int firstCellInEvent, int lastCellInEvent) { mDigits.clear(); if (mDigits.capacity() < lastCellInEvent - firstCellInEvent) { mDigits.reserve(lastCellInEvent - firstCellInEvent); } - // int iLab = 0, nLab = mcmap.size(); - // while (iLab < nLab) { - // if (mcmap[iLab] >= firstCellInEvent) { - // break; - // } - // ++iLab; - // } - for (int i = firstCellInEvent; i < lastCellInEvent; i++) { const Cell c = cells[i]; //short cell, float amplitude, float time, int label - int label = -1; - // if (mcmap[iLab] == i) { - // label = iLab; - // ++iLab; - // if (iLab >= nLab) { - // --iLab; - // } - // } - mDigits.emplace_back(c.getAbsId(), c.getEnergy(), c.getTime(), label); + mDigits.emplace_back(c.getAbsId(), c.getEnergy(), c.getTime(), i); mDigits.back().setHighGain(c.getHighGain()); } mFirstDigitInEvent = 0; @@ -440,7 +434,7 @@ void Clusterer::evalCluProperties(gsl::span digits, std::vectorgetIndexedSize(); } auto clu = mClusters.begin(); @@ -461,7 +455,7 @@ void Clusterer::evalCluProperties(gsl::span digits, std::vectorgetEnergy() > 1.e-4) { //Non-empty cluster clusters->emplace_back(*clu); - if (cluMC) { //Handle labels + if (mProcessMC) { //Handle labels //Calculate list of primaries //loop over entries in digit MCTruthContainer const std::vector* vl = clu->getElementList(); @@ -469,14 +463,18 @@ void Clusterer::evalCluProperties(gsl::span digits, std::vectorend()) { int i = (*ll).label; //index float sc = (*ll).scale; - if (i < 0) { + gsl::span spDigList = dmc->getLabels(i); + if (spDigList.size() == 0 || spDigList.begin()->isFake()) { ++ll; continue; } - gsl::span spDigList = dmc->getLabels(i); gsl::span spCluList = cluMC->getLabels(labelIndex); //get updated list auto digL = spDigList.begin(); while (digL != spDigList.end()) { + if (digL->isFake()) { + digL++; + continue; + } bool merged = false; auto cluL = spCluList.begin(); while (cluL != spCluList.end()) { diff --git a/Detectors/PHOS/simulation/include/PHOSSimulation/Digitizer.h b/Detectors/PHOS/simulation/include/PHOSSimulation/Digitizer.h index 7c78566e3b18f..fef416c3d5d54 100644 --- a/Detectors/PHOS/simulation/include/PHOSSimulation/Digitizer.h +++ b/Detectors/PHOS/simulation/include/PHOSSimulation/Digitizer.h @@ -37,20 +37,24 @@ class Digitizer : public TObject void processHits(const std::vector* mHits, const std::vector& digitsBg, std::vector& digitsOut, o2::dataformats::MCTruthContainer& mLabels, int source, int entry, double dt); + void processMC(bool mc) { mProcessMC = mc; } protected: - void addNoisyChannels(int start, int end, std::vector& digitsOut); float nonLinearity(float e); float uncalibrate(float e, int absId); - float uncalibrateT(float t, int absId, bool isHighGain); + float uncalibrateT(float t, int absId); float timeResolution(float time, float e); float simulateNoiseEnergy(int absId); float simulateNoiseTime(); private: + static constexpr short NCHANNELS = 12544; ///< Number of channels starting from 56*64*(4-0.5) + static constexpr short OFFSET = 1793; ///< Non-existing channels 56*64*0.5+1 + bool mProcessMC = true; std::unique_ptr mCalibParams; /// Calibration coefficients + std::array mArrayD; - ClassDefOverride(Digitizer, 3); + ClassDefOverride(Digitizer, 4); }; } // namespace phos } // namespace o2 diff --git a/Detectors/PHOS/simulation/src/Digitizer.cxx b/Detectors/PHOS/simulation/src/Digitizer.cxx index 7cbbf82e3466f..65bb360c0fe08 100644 --- a/Detectors/PHOS/simulation/src/Digitizer.cxx +++ b/Detectors/PHOS/simulation/src/Digitizer.cxx @@ -56,149 +56,98 @@ void Digitizer::processHits(const std::vector* hits, const std::vector::const_iterator dBg = digitsBg.cbegin(); - std::vector::const_iterator hBg = hits->cbegin(); - - bool addNoise = !(digitsBg.size()); //If digits list not empty, noise already there - - int currentId = 32 * 56; //first digit in half-mod 1 minus 1 - - while (dBg != digitsBg.cend() && hBg != hits->cend()) { - if (dBg->getAbsId() < hBg->GetDetectorID()) { // copy digit - //Digits already contain noise, no need to add it in this branch - //Digits have correct time, no need to add event time - digitsOut.emplace_back(dBg->getAbsId(), dBg->getAmplitude(), dBg->getTime(), dBg->getLabel()); - currentId = dBg->getAbsId(); - dBg++; - } else { - if (addNoise) { - addNoisyChannels(currentId, hBg->GetDetectorID(), digitsOut); - } - currentId = hBg->GetDetectorID(); - int labelIndex = -1; - if (dBg->getAbsId() == hBg->GetDetectorID()) { - labelIndex = dBg->getLabel(); - } - if (labelIndex == -1) { //no digit or noisy - labelIndex = labels.getIndexedSize(); - } - Digit digit(*hBg, labelIndex); - // Add Electroinc noise, apply non-linearity, digitize, de-calibrate, time resolution - float energy = hBg->GetEnergyLoss(); - // Simulate electronic noise - short absId = hBg->GetDetectorID(); - energy += simulateNoiseEnergy(absId); - - if (o2::phos::PHOSSimParams::Instance().mApplyNonLinearity) { - energy = nonLinearity(energy); - } - - energy = uncalibrate(energy, absId); - - digit.setHighGain(energy < o2::phos::PHOSSimParams::Instance().mMCOverflow); //10bit ADC - if (digit.isHighGain()) { - digit.setAmplitude(energy); - } else { - float hglgratio = mCalibParams->getHGLGRatio(absId); - digit.setAmplitude(energy / hglgratio); - } - - float time = hBg->GetTime() + dt * 1.e-9; - if (o2::phos::PHOSSimParams::Instance().mApplyTimeResolution) { - digit.setTime(uncalibrateT(timeResolution(time, energy), absId, digit.isHighGain())); - } - - // Merge with existing digit if any - if (dBg->getAbsId() == hBg->GetDetectorID()) { - digit += *dBg; - dBg++; - } - - hBg++; - if (energy <= o2::phos::PHOSSimParams::Instance().mDigitThreshold) { - continue; + if (digitsBg.size() == 0) { // no digits provided: try simulate noise + for (int i = NCHANNELS; i--;) { + float energy = simulateNoiseEnergy(i + OFFSET); + energy = uncalibrate(energy, i + OFFSET); + if (energy > o2::phos::PHOSSimParams::Instance().mDigitThreshold) { + float time = simulateNoiseTime(); + mArrayD[i].setAmplitude(energy); + mArrayD[i].setTime(time); + mArrayD[i].setAbsId(i + OFFSET); } - - //Add primary info: create new MCLabels entry - o2::phos::MCLabel label(hBg->GetTrackID(), collId, source, true, hBg->GetEnergyLoss()); - labels.addElementRandomAccess(labelIndex, label); - //sort MCLabels according to eDeposited - auto lbls = labels.getLabels(labelIndex); - std::sort(lbls.begin(), lbls.end(), - [](o2::phos::MCLabel a, o2::phos::MCLabel b) { return a.getEdep() > b.getEdep(); }); - - digitsOut.push_back(digit); } - } - //Fill remainder - while (dBg != digitsBg.cend()) { - digitsOut.push_back(*dBg); - dBg++; - } - - while (hBg != hits->cend()) { - if (addNoise) { - addNoisyChannels(currentId, hBg->GetDetectorID(), digitsOut); + } else { //if digits exist, no noise should be added + for (auto& dBg : digitsBg) { //digits are sorted and unique + mArrayD[dBg.getAbsId() - OFFSET] = dBg; } - currentId = hBg->GetDetectorID(); - - int labelIndex = labels.getIndexedSize(); - - Digit digit(*hBg, labelIndex); - // Add Electroinc noise, apply non-linearity, digitize, de-calibrate, time resolution - float energy = hBg->GetEnergyLoss(); - // Simulate electronic noise - short absId = hBg->GetDetectorID(); - energy += simulateNoiseEnergy(absId); + } + //add Hits + for (auto& h : *hits) { + short absId = h.GetDetectorID(); + short i = absId - OFFSET; + float energy = h.GetEnergyLoss(); if (o2::phos::PHOSSimParams::Instance().mApplyNonLinearity) { energy = nonLinearity(energy); } - energy = uncalibrate(energy, absId); - - digit.setHighGain(energy < o2::phos::PHOSSimParams::Instance().mMCOverflow); //10bit ADC - if (digit.isHighGain()) { - digit.setAmplitude(energy); - } else { - float hglgratio = mCalibParams->getHGLGRatio(absId); - digit.setAmplitude(energy / hglgratio); - } - - float time = hBg->GetTime() + dt * 1.e-9; + float time = h.GetTime() + dt * 1.e-9; if (o2::phos::PHOSSimParams::Instance().mApplyTimeResolution) { - digit.setTime(uncalibrateT(timeResolution(time, energy), absId, digit.isHighGain())); + time = uncalibrateT(timeResolution(time, energy), absId); } - - hBg++; - if (energy <= o2::phos::PHOSSimParams::Instance().mDigitThreshold) { - continue; + if (mArrayD[i].getAmplitude() > 0) { + //update energy and time + mArrayD[i].addEnergyTime(energy, time); + //if overflow occured? + if (mArrayD[i].isHighGain()) { + if (mArrayD[i].getAmplitude() > o2::phos::PHOSSimParams::Instance().mMCOverflow) { //10bit ADC + float hglgratio = mCalibParams->getHGLGRatio(absId); + mArrayD[i].setAmplitude(mArrayD[i].getAmplitude() / hglgratio); + mArrayD[i].setHighGain(false); + } + } + } else { + mArrayD[i].setHighGain(energy < o2::phos::PHOSSimParams::Instance().mMCOverflow); //10bit ADC + if (mArrayD[i].isHighGain()) { + mArrayD[i].setAmplitude(energy); + } else { + float hglgratio = mCalibParams->getHGLGRatio(absId); + mArrayD[i].setAmplitude(energy / hglgratio); + } + mArrayD[i].setTime(time); + mArrayD[i].setAbsId(absId); + } + //Add MC info + if (mProcessMC) { + int labelIndex = mArrayD[i].getLabel(); + if (labelIndex == -1) { //no digit or noisy + labelIndex = labels.getIndexedSize(); + MCLabel label(h.GetTrackID(), collId, source, false, h.GetEnergyLoss()); + labels.addElement(labelIndex, label); + mArrayD[i].setLabel(labelIndex); + } else { //check if lable already exist + MCLabel label(h.GetTrackID(), collId, source, false, h.GetEnergyLoss()); + gsl::span sp = labels.getLabels(labelIndex); + bool found = false; + for (MCLabel& te : sp) { + if (te == label) { + found = true; + te.add(label, 1.); + break; + } + } + if (!found) { + //Highly inefficient management of Labels: commenting line below reeduces WHOLE digitization time by factor ~30 + labels.addElementRandomAccess(labelIndex, label); + //sort MCLabels according to eDeposited + sp = labels.getLabels(labelIndex); + std::sort(sp.begin(), sp.end(), + [](o2::phos::MCLabel a, o2::phos::MCLabel b) { return a.getEdep() > b.getEdep(); }); + } + } + } else { + mArrayD[i].setLabel(-1); } - - //Add primary info: create new MCLabels entry - o2::phos::MCLabel label(hBg->GetTrackID(), collId, source, true, hBg->GetEnergyLoss()); - labels.addElement(labelIndex, label); - - digitsOut.push_back(digit); - } - //Add noisy channels to the end of PHOS - if (addNoise) { - addNoisyChannels(currentId, 56 * 64 * 4, digitsOut); } -} - -//_______________________________________________________________________ -void Digitizer::addNoisyChannels(int start, int end, std::vector& digitsOut) -{ - - // Simulate noise - for (int absId = start + 1; absId < end; absId++) { - float energy = simulateNoiseEnergy(absId); - energy = uncalibrate(energy, absId); - if (energy > o2::phos::PHOSSimParams::Instance().mDigitThreshold) { - float time = simulateNoiseTime(); - digitsOut.emplace_back(absId, energy, time, -1); // current AbsId, energy, random time, no primary + for (int i = 0; i < NCHANNELS; i++) { + if (mArrayD[i].getAmplitude() > PHOSSimParams::Instance().mZSthreshold) { + digitsOut.push_back(mArrayD[i]); } } } @@ -223,15 +172,11 @@ float Digitizer::uncalibrate(const float e, const int absId) } } //_______________________________________________________________________ -float Digitizer::uncalibrateT(const float time, const int absId, bool isHighGain) +float Digitizer::uncalibrateT(const float time, const int absId) { // Decalibrate EMC digit, i.e. transform from energy to ADC counts a factor read from CDB // note time in seconds - if (isHighGain) { - return time + mCalibParams->getHGTimeCalib(absId); - } else { - return time + mCalibParams->getLGTimeCalib(absId); - } + return time + mCalibParams->getHGTimeCalib(absId); } //_______________________________________________________________________ float Digitizer::timeResolution(const float time, const float e) diff --git a/Detectors/PHOS/workflow/CMakeLists.txt b/Detectors/PHOS/workflow/CMakeLists.txt index 7d19c6fabaf48..531935fae0c06 100644 --- a/Detectors/PHOS/workflow/CMakeLists.txt +++ b/Detectors/PHOS/workflow/CMakeLists.txt @@ -10,7 +10,7 @@ o2_add_library(PHOSWorkflow SOURCES src/RecoWorkflow.cxx - src/PublisherSpec.cxx + src/ReaderSpec.cxx src/CellConverterSpec.cxx src/RawToCellConverterSpec.cxx src/ClusterizerSpec.cxx @@ -18,6 +18,7 @@ o2_add_library(PHOSWorkflow src/RawWriterSpec.cxx src/EntropyEncoderSpec.cxx src/EntropyDecoderSpec.cxx + src/WriterSpec.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsPHOS O2::DPLUtils O2::PHOSBase diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/CellConverterSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/CellConverterSpec.h index 05f3892684125..556a80a21e2e9 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/CellConverterSpec.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/CellConverterSpec.h @@ -75,7 +75,6 @@ class CellConverterSpec : public framework::Task std::vector mOutputCells; ///< Container with output cells std::vector mOutputCellTrigRecs; ///< Container with trigger records for output cells o2::dataformats::MCTruthContainer mOutputTruthCont; ///< output MC labels - std::vector mOutputTruthMap; ///< output MC labels o2::phos::BadChannelMap* mBadMap = nullptr; ///< Bad channels map }; diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/ReaderSpec.h similarity index 56% rename from Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h rename to Detectors/PHOS/workflow/include/PHOSWorkflow/ReaderSpec.h index f79d38432cfeb..58a127fbd9c48 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/ReaderSpec.h @@ -21,26 +21,8 @@ namespace phos using OutputSpec = framework::OutputSpec; -struct PublisherConf { - struct BranchOptionConfig { - std::string option; - std::string defval; - std::string help; - }; - - std::string processName; - std::string defaultTreeName; - BranchOptionConfig databranch; - BranchOptionConfig datatrbranch; - BranchOptionConfig mcbranch; - BranchOptionConfig mcmapbranch; - OutputSpec dataoutput; - OutputSpec datatroutput; - OutputSpec mcoutput; - OutputSpec mcmapoutput; -}; - -framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC = true, bool createMCMap = false); +framework::DataProcessorSpec getDigitsReaderSpec(bool propagateMC = true); +framework::DataProcessorSpec getCellReaderSpec(bool propagateMC = true); } // namespace phos } // end namespace o2 diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h index 7235ffa805e98..9d0df0973816f 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h @@ -38,7 +38,9 @@ enum struct OutputType { Digits, }; /// create the workflow for PHOS reconstruction -framework::WorkflowSpec getWorkflow(bool propagateMC = true, +framework::WorkflowSpec getWorkflow(bool disableRootInp, + bool disableRootOut, + bool propagateMC = true, bool enableDigitsPrinter = false, std::string const& cfgInput = "hits", // std::string const& cfgOutput = "clusters" // diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/WriterSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/WriterSpec.h new file mode 100644 index 0000000000000..076496bbf676e --- /dev/null +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/WriterSpec.h @@ -0,0 +1,33 @@ +// 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 ClusterWriterSpec.h + +#ifndef O2_PHOS_WRITER +#define O2_PHOS_WRITER + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace phos +{ + +/// create a processor spec +/// write PHOS clusters to ROOT file +framework::DataProcessorSpec getCellWriterSpec(bool useMC); + +/// write PHOS clusters to ROOT file +framework::DataProcessorSpec getClusterWriterSpec(bool useMC); + +} // namespace phos +} // namespace o2 + +#endif /* O2_PHOS_WRITER */ \ No newline at end of file diff --git a/Detectors/PHOS/workflow/src/CellConverterSpec.cxx b/Detectors/PHOS/workflow/src/CellConverterSpec.cxx index 224f61b998a68..45426fef5c4f3 100644 --- a/Detectors/PHOS/workflow/src/CellConverterSpec.cxx +++ b/Detectors/PHOS/workflow/src/CellConverterSpec.cxx @@ -49,9 +49,12 @@ void CellConverterSpec::run(framework::ProcessingContext& ctx) if (mPropagateMC) { truthcont = ctx.inputs().get*>("digitsmctr"); mOutputTruthCont.clear(); - mOutputTruthMap.clear(); } - LOG(INFO) << "[PHOSCellConverter - run] Received " << digits.size() << " digits and " << digitsTR.size() << " TriggerRecords" << truthcont->getNElements() << " MC labels"; + if (mPropagateMC) { + LOG(INFO) << "[PHOSCellConverter - run] Received " << digits.size() << " digits and " << digitsTR.size() << " TriggerRecords" << truthcont->getNElements() << " MC labels"; + } else { + LOG(INFO) << "[PHOSCellConverter - run] Received " << digits.size() << " digits and " << digitsTR.size() << " TriggerRecords"; + } //Get TimeStamp from TriggerRecord if (!mBadMap) { @@ -72,12 +75,12 @@ void CellConverterSpec::run(framework::ProcessingContext& ctx) } //TODO!!! Should we check if BadMap should be updated/validity range still valid??? mOutputCells.reserve(digits.size()); // most of digits will be copied + int icell = 0; int labelIndex = 0; for (const auto& tr : digitsTR) { int iFirstDigit = tr.getFirstEntry(); int iLastDigit = iFirstDigit + tr.getNumberOfObjects(); int indexStart = mOutputCells.size(); - int icell = 0; for (int i = iFirstDigit; i < iLastDigit; i++) { const auto& dig = digits.at(i); @@ -101,14 +104,16 @@ void CellConverterSpec::run(framework::ProcessingContext& ctx) if (mPropagateMC) { //copy MC info, int iLab = dig.getLabel(); if (iLab > -1) { - mOutputTruthCont.addElements(labelIndex, truthcont->getLabels(iLab)); - mOutputTruthMap.emplace_back(icell); //Relate cell index and label index - labelIndex++; + mOutputTruthCont.addElements(icell, truthcont->getLabels(iLab)); + } else { + MCLabel label(0, 0, 0, true, 0); + label.setNoise(); + mOutputTruthCont.addElement(icell, label); } + icell++; } - icell++; } - mOutputCellTrigRecs.emplace_back(tr.getBCData(), indexStart, mOutputCells.size()); + mOutputCellTrigRecs.emplace_back(tr.getBCData(), indexStart, mOutputCells.size() - indexStart); } LOG(INFO) << "[PHOSCellConverter - run] Writing " << mOutputCells.size() << " cells, " << mOutputCellTrigRecs.size() << " Trig Records " << mOutputTruthCont.getNElements() << " PHOS labels "; ; @@ -116,7 +121,6 @@ void CellConverterSpec::run(framework::ProcessingContext& ctx) ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLTRIGREC", 0, o2::framework::Lifetime::Timeframe}, mOutputCellTrigRecs); if (mPropagateMC) { ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLSMCTR", 0, o2::framework::Lifetime::Timeframe}, mOutputTruthCont); - ctx.outputs().snapshot(o2::framework::Output{"PHS", "CELLSMCMAP", 0, o2::framework::Lifetime::Timeframe}, mOutputTruthMap); } } @@ -131,7 +135,6 @@ o2::framework::DataProcessorSpec o2::phos::reco_workflow::getCellConverterSpec(b if (propagateMC) { inputs.emplace_back("digitsmctr", "PHS", "DIGITSMCTR", 0, o2::framework::Lifetime::Timeframe); outputs.emplace_back("PHS", "CELLSMCTR", 0, o2::framework::Lifetime::Timeframe); - outputs.emplace_back("PHS", "CELLSMCMAP", 0, o2::framework::Lifetime::Timeframe); } return o2::framework::DataProcessorSpec{"PHOSCellConverterSpec", inputs, diff --git a/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx b/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx index a3ca5d7d2306f..77f5c87f0f465 100644 --- a/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx +++ b/Detectors/PHOS/workflow/src/ClusterizerSpec.cxx @@ -38,34 +38,45 @@ void ClusterizerSpec::run(framework::ProcessingContext& ctx) return; } - // auto digits = ctx.inputs().get>("digits"); - // results in [7968:PHOSClusterizerSpec]: [20:51:44][ERROR] Exception caught: Inconsistent serialization method for extracting span + // auto digits = ctx.inputs().get>("digits"); auto digits = ctx.inputs().get>("digits"); auto digitsTR = ctx.inputs().get>("digitTriggerRecords"); LOG(DEBUG) << "[PHOSClusterizer - run] Received " << digitsTR.size() << " TR, running clusterizer ..."; // const o2::dataformats::MCTruthContainer* truthcont=nullptr; - // if(mPropagateMC){ - // truthcont = ctx.inputs().get*>("digitsmctr"); - // } - // mClusterizer.process(digits, digitsTR, truthcont.get(), &mOutputClusters, &mOutputClusterTrigRecs, &mOutputTruthCont); // Find clusters on digits (pass by ref) + if (mPropagateMC) { + std::unique_ptr> truthcont(ctx.inputs().get*>("digitsmctr")); + mClusterizer.process(digits, digitsTR, truthcont.get(), &mOutputClusters, &mOutputClusterTrigRecs, &mOutputTruthCont); // Find clusters on digits (pass by ref) + } else { + mClusterizer.process(digits, digitsTR, nullptr, &mOutputClusters, &mOutputClusterTrigRecs, &mOutputTruthCont); // Find clusters on digits (pass by ref) + } } else { LOG(DEBUG) << "PHOSClusterizer - run run on cells called"; - auto cells = ctx.inputs().get>("cells"); + printf("Getting cells \n"); + auto cells = ctx.inputs().get>("cells"); + // auto cells = ctx.inputs().get>("cells"); LOG(DEBUG) << "[PHOSClusterizer - run] Received " << cells.size() << " cells, running clusterizer ..."; - auto cellsTR = ctx.inputs().get>("cellTriggerRecords"); - - std::unique_ptr> truthcont; - gsl::span truthmap; + printf("Getting TR \n"); + // auto cellsTR = ctx.inputs().get>("cellTriggerRecords"); + auto cellsTR = ctx.inputs().get>("cellTriggerRecords"); if (mPropagateMC) { - truthcont = ctx.inputs().get*>("cellsmctr"); - truthmap = ctx.inputs().get>("cellssmcmap"); + printf("Getting MC \n"); + std::unique_ptr> truthcont(ctx.inputs().get*>("cellsmctr")); + // truthmap = ctx.inputs().get>("cellssmcmap"); + printf("Clustering \n"); + mClusterizer.processCells(cells, cellsTR, truthcont.get(), &mOutputClusters, &mOutputClusterTrigRecs, &mOutputTruthCont); // Find clusters on digits (pass by ref) + } else { + printf("Clustering2 \n"); + mClusterizer.processCells(cells, cellsTR, nullptr, &mOutputClusters, &mOutputClusterTrigRecs, &mOutputTruthCont); // Find clusters on digits (pass by ref) } - mClusterizer.processCells(cells, cellsTR, truthcont.get(), truthmap, &mOutputClusters, &mOutputClusterTrigRecs, &mOutputTruthCont); // Find clusters on digits (pass by ref) } - LOG(DEBUG) << "[PHOSClusterizer - run] Writing " << mOutputClusters.size() << " clusters, " << mOutputClusterTrigRecs.size() << "TR and " << mOutputTruthCont.getIndexedSize() << " Labels"; + if (mPropagateMC) { + LOG(DEBUG) << "[PHOSClusterizer - run] Writing " << mOutputClusters.size() << " clusters, " << mOutputClusterTrigRecs.size() << "TR and " << mOutputTruthCont.getIndexedSize() << " Labels"; + } else { + LOG(DEBUG) << "[PHOSClusterizer - run] Writing " << mOutputClusters.size() << " clusters and " << mOutputClusterTrigRecs.size() << " TR"; + } ctx.outputs().snapshot(o2::framework::Output{"PHS", "CLUSTERS", 0, o2::framework::Lifetime::Timeframe}, mOutputClusters); ctx.outputs().snapshot(o2::framework::Output{"PHS", "CLUSTERTRIGRECS", 0, o2::framework::Lifetime::Timeframe}, mOutputClusterTrigRecs); if (mPropagateMC) { @@ -105,7 +116,6 @@ o2::framework::DataProcessorSpec o2::phos::reco_workflow::getCellClusterizerSpec inputs.emplace_back("cellTriggerRecords", o2::header::gDataOriginPHS, "CELLTRIGREC", 0, o2::framework::Lifetime::Timeframe); if (propagateMC) { inputs.emplace_back("cellsmctr", "PHS", "CELLSMCTR", 0, o2::framework::Lifetime::Timeframe); - inputs.emplace_back("cellssmcmap", "PHS", "CELLSMCMAP", 0, o2::framework::Lifetime::Timeframe); } outputs.emplace_back("PHS", "CLUSTERS", 0, o2::framework::Lifetime::Timeframe); outputs.emplace_back("PHS", "CLUSTERTRIGRECS", 0, o2::framework::Lifetime::Timeframe); diff --git a/Detectors/PHOS/workflow/src/PublisherSpec.cxx b/Detectors/PHOS/workflow/src/PublisherSpec.cxx deleted file mode 100644 index a170eb8aa73fd..0000000000000 --- a/Detectors/PHOS/workflow/src/PublisherSpec.cxx +++ /dev/null @@ -1,179 +0,0 @@ -// 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. - -#include "DataFormatsPHOS/PHOSBlockHeader.h" -#include "PHOSWorkflow/PublisherSpec.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Headers/DataHeader.h" -#include "DPLUtils/RootTreeReader.h" -#include "Framework/DataSpecUtils.h" -#include -#include - -namespace o2 -{ - -namespace phos -{ - -o2::framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC, bool createMCMap) -{ - struct ProcessAttributes { - std::shared_ptr reader; - std::string datatype; - bool terminateOnEod; - bool finished; - }; - - auto initFunction = [config, propagateMC, createMCMap](o2::framework::InitContext& ic) { - // get the option from the init context - auto filename = ic.options().get("infile"); - auto treename = ic.options().get("treename"); - auto dtbrName = ic.options().get(config.databranch.option.c_str()); // databranch name - auto dttrbrName = ic.options().get(config.datatrbranch.option.c_str()); // datatrigrec name - auto mcbrName = ic.options().get(config.mcbranch.option.c_str()); // mcbranch name - auto mcmapbrName = ic.options().get(config.mcmapbranch.option.c_str()); // mc map branch name - auto nofEvents = ic.options().get("nevents"); - // auto publishingMode = nofEvents == -1 ? o2::framework::RootTreeReader::PublishingMode::Single : o2::framework::RootTreeReader::PublishingMode::Loop; - auto publishingMode = o2::framework::RootTreeReader::PublishingMode::Single; - - auto processAttributes = std::make_shared(); - { - processAttributes->terminateOnEod = ic.options().get("terminate-on-eod"); - processAttributes->finished = false; - processAttributes->datatype = config.databranch.defval; - auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto dttro = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.datatroutput); - auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - auto mcmapo = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcmapoutput); - constexpr auto persistency = o2::framework::Lifetime::Timeframe; - o2::header::DataHeader::SubSpecificationType subSpec = 0; - if (propagateMC) { - if (!createMCMap) { - processAttributes->reader = std::make_shared(treename.c_str(), // tree name - filename.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, - dtbrName.c_str(), // name of data branch - o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, - dttrbrName.c_str(), // name of data triggerrecords branch - o2::framework::Output{mco.origin, mco.description, subSpec, persistency}, - mcbrName.c_str() // name of mc label branch - ); - } else { - processAttributes->reader = std::make_shared(treename.c_str(), // tree name - filename.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, - dtbrName.c_str(), // name of data branch - o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, - dttrbrName.c_str(), // name of data triggerrecords branch - o2::framework::Output{mco.origin, mco.description, subSpec, persistency}, - mcbrName.c_str(), // name of mc label branch - o2::framework::Output{mcmapo.origin, mcmapo.description, subSpec, persistency}, - mcmapbrName.c_str() // name of mc label branch - ); - } - } else { - processAttributes->reader = std::make_shared(treename.c_str(), // tree name - filename.c_str(), // input file name - nofEvents, // number of entries to publish - publishingMode, - o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, - dtbrName.c_str(), // name of data branch - o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, - dttrbrName.c_str() // name of data tr branch - ); - } - } - - auto processFunction = [processAttributes, propagateMC, createMCMap](o2::framework::ProcessingContext& pc) { - if (processAttributes->finished) { - return; - } - - auto publish = [&processAttributes, &pc, propagateMC, createMCMap]() { - o2::phos::PHOSBlockHeader phosheader(true); - if (processAttributes->reader->next()) { - (*processAttributes->reader)(pc, phosheader); - } else { - processAttributes->reader.reset(); - return false; - } - return true; - }; - - bool active(true); - if (!publish()) { - active = false; - // Send dummy header with no payload option - o2::phos::PHOSBlockHeader dummyheader(false); - pc.outputs().snapshot(o2::framework::OutputRef{"output", 0, {dummyheader}}, 0); - pc.outputs().snapshot(o2::framework::OutputRef{"outputTR", 0, {dummyheader}}, 0); - if (propagateMC) { - pc.outputs().snapshot(o2::framework::OutputRef{"outputMC", 0, {dummyheader}}, 0); - if (createMCMap) { - pc.outputs().snapshot(o2::framework::OutputRef{"outputMCmap", 0, {dummyheader}}, 0); - } - } - } - if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { - pc.services().get().endOfStream(); - pc.services().get().readyToQuit(framework::QuitRequest::Me); - } - }; - - return processFunction; - }; - - auto createOutputSpecs = [&config, propagateMC, createMCMap]() { - std::vector outputSpecs; - auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); - auto dttro = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.datatroutput); - auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); - auto mcmapo = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcmapoutput); - outputSpecs.emplace_back(o2::framework::OutputSpec{{"output"}, dto.origin, dto.description, 0, o2::framework::Lifetime::Timeframe}); - outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputTR"}, dttro.origin, dttro.description, 0, o2::framework::Lifetime::Timeframe}); - if (propagateMC) { - outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputMC"}, mco.origin, mco.description, 0, o2::framework::Lifetime::Timeframe}); - if (createMCMap) { - outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputMCmap"}, mcmapo.origin, mcmapo.description, 0, o2::framework::Lifetime::Timeframe}); - } - } - return std::move(outputSpecs); - }; - - auto& dtb = config.databranch; - auto& dttrb = config.datatrbranch; - auto& mcb = config.mcbranch; - auto& mcmapb = config.mcmapbranch; - return o2::framework::DataProcessorSpec{ - config.processName.c_str(), - o2::framework::Inputs{}, // no inputs - {createOutputSpecs()}, - o2::framework::AlgorithmSpec(initFunction), - o2::framework::Options{ - {"infile", o2::framework::VariantType::String, "phosdigits.root", {"Name of the input file"}}, - {"treename", o2::framework::VariantType::String, config.defaultTreeName.c_str(), {"Name of input tree"}}, - {dtb.option.c_str(), o2::framework::VariantType::String, dtb.defval.c_str(), {dtb.help.c_str()}}, - {dttrb.option.c_str(), o2::framework::VariantType::String, dttrb.defval.c_str(), {dttrb.help.c_str()}}, - {mcb.option.c_str(), o2::framework::VariantType::String, mcb.defval.c_str(), {mcb.help.c_str()}}, - {mcmapb.option.c_str(), o2::framework::VariantType::String, mcmapb.defval.c_str(), {mcmapb.help.c_str()}}, - {"nevents", o2::framework::VariantType::Int, -1, {"number of events to run"}}, - {"terminate-on-eod", o2::framework::VariantType::Bool, true, {"terminate on end-of-data"}}, - }}; -} - -} // namespace phos - -} // namespace o2 diff --git a/Detectors/PHOS/workflow/src/ReaderSpec.cxx b/Detectors/PHOS/workflow/src/ReaderSpec.cxx new file mode 100644 index 0000000000000..b2bb1f37bd2a2 --- /dev/null +++ b/Detectors/PHOS/workflow/src/ReaderSpec.cxx @@ -0,0 +1,236 @@ +// 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. + +#include "DataFormatsPHOS/PHOSBlockHeader.h" +#include "PHOSWorkflow/ReaderSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Headers/DataHeader.h" +#include "DPLUtils/RootTreeReader.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "Framework/DataSpecUtils.h" +#include +#include + +using namespace o2::framework; + +namespace o2 +{ + +namespace phos +{ + +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; + +struct ProcessAttributes { + std::shared_ptr reader; + std::string datatype; + bool terminateOnEod; + bool finished; +}; + +DataProcessorSpec getDigitsReaderSpec(bool propagateMC) +{ + + auto initFunction = [propagateMC](InitContext& ic) { + // get the option from the init context + auto filename = ic.options().get("infile"); + auto treename = ic.options().get("treename"); + auto nofEvents = ic.options().get("nevents"); + auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; + + auto processAttributes = std::make_shared(); + { + processAttributes->terminateOnEod = ic.options().get("terminate-on-eod"); + processAttributes->finished = false; + processAttributes->datatype = "PHOSDigit"; + constexpr auto persistency = Lifetime::Timeframe; + o2::header::DataHeader::SubSpecificationType subSpec = 0; + if (propagateMC) { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"PHS", "DIGITS", subSpec, persistency}, + "PHOSDigit", // name of data branch + Output{"PHS", "DIGITTRIGREC", subSpec, persistency}, + "PHOSDigitTrigRecords", // name of data triggerrecords branch + Output{"PHS", "DIGITSMCTR", subSpec, persistency}, + "PHOSDigitMCTruth"); // name of mc label branch + } else { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"PHS", "DIGITS", subSpec, persistency}, + "PHOSDigit", // name of data branch + Output{"PHS", "DIGITTRIGREC", subSpec, persistency}, + "PHOSDigitTrigRecords"); // name of data triggerrecords branch + } + } + + auto processFunction = [processAttributes, propagateMC](ProcessingContext& pc) { + if (processAttributes->finished) { + return; + } + + auto publish = [&processAttributes, &pc, propagateMC]() { + o2::phos::PHOSBlockHeader phosheader(true); + if (processAttributes->reader->next()) { + (*processAttributes->reader)(pc, phosheader); + } else { + processAttributes->reader.reset(); + return false; + } + return true; + }; + + bool active(true); + if (!publish()) { + active = false; + // Send dummy header with no payload option + o2::phos::PHOSBlockHeader dummyheader(false); + pc.outputs().snapshot(OutputRef{"output", 0, {dummyheader}}, 0); + pc.outputs().snapshot(OutputRef{"outputTR", 0, {dummyheader}}, 0); + if (propagateMC) { + pc.outputs().snapshot(OutputRef{"outputMC", 0, {dummyheader}}, 0); + } + } + if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(framework::QuitRequest::Me); + } + }; + return processFunction; + }; + + std::vector outputSpecs; + outputSpecs.emplace_back(OutputSpec{{"output"}, "PHS", "DIGITS", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"outputTR"}, "PHS", "DIGITTRIGREC", 0, Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(OutputSpec{{"outputMC"}, "PHS", "DIGITSMCTR", 0, Lifetime::Timeframe}); + } + + return DataProcessorSpec{ + "phos-digit-reader", + Inputs{}, // no inputs + outputSpecs, + AlgorithmSpec(initFunction), + Options{ + {"infile", VariantType::String, "phosdigits.root", {"Name of the input file"}}, + {"treename", VariantType::String, "o2sim", {"Name of input tree"}}, + {"nevents", VariantType::Int, -1, {"number of events to run, -1: inf loop"}}, + {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} + +///////////////Cell reader + +DataProcessorSpec getCellReaderSpec(bool propagateMC) +{ + + auto initFunction = [propagateMC](InitContext& ic) { + // get the option from the init context + auto filename = ic.options().get("infile"); + auto treename = ic.options().get("treename"); + auto nofEvents = ic.options().get("nevents"); + auto publishingMode = nofEvents == -1 ? RootTreeReader::PublishingMode::Single : RootTreeReader::PublishingMode::Loop; + + auto processAttributes = std::make_shared(); + { + processAttributes->terminateOnEod = ic.options().get("terminate-on-eod"); + processAttributes->finished = false; + processAttributes->datatype = "PHOSCell"; + constexpr auto persistency = Lifetime::Timeframe; + o2::header::DataHeader::SubSpecificationType subSpec = 0; + if (propagateMC) { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"PHS", "CELLS", subSpec, persistency}, + "PHOSCell", // name of data branch + Output{"PHS", "CELLTRIGREC", subSpec, persistency}, + "PHOSCellTrigRec", // name of data triggerrecords branch + Output{"PHS", "CELLSMCTR", subSpec, persistency}, + "PHOSCellTrueMC"); // name of mc label branch + } else { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + Output{"PHS", "CELLS", subSpec, persistency}, + "PHOSCell", // name of data branch + Output{"PHS", "CELLTRIGREC", subSpec, persistency}, + "PHOSCellTrigRec"); // name of data triggerrecords branch + } + } + + auto processFunction = [processAttributes, propagateMC](ProcessingContext& pc) { + if (processAttributes->finished) { + return; + } + + auto publish = [&processAttributes, &pc, propagateMC]() { + PHOSBlockHeader phosheader(true); + if (processAttributes->reader->next()) { + (*processAttributes->reader)(pc, phosheader); + } else { + processAttributes->reader.reset(); + return false; + } + return true; + }; + + bool active(true); + if (!publish()) { + active = false; + // Send dummy header with no payload option + PHOSBlockHeader dummyheader(false); + pc.outputs().snapshot(OutputRef{"output", 0, {dummyheader}}, 0); + pc.outputs().snapshot(OutputRef{"outputTR", 0, {dummyheader}}, 0); + if (propagateMC) { + pc.outputs().snapshot(OutputRef{"outputMC", 0, {dummyheader}}, 0); + pc.outputs().snapshot(OutputRef{"outputMCmap", 0, {dummyheader}}, 0); + } + } + if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(framework::QuitRequest::Me); + } + }; + return processFunction; + }; + + std::vector outputSpecs; + outputSpecs.emplace_back(OutputSpec{{"output"}, "PHS", "CELLS", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"outputTR"}, "PHS", "CELLTRIGREC", 0, Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(OutputSpec{{"outputMC"}, "PHS", "CELLSMCTR", 0, Lifetime::Timeframe}); + outputSpecs.emplace_back(OutputSpec{{"outputMCmap"}, "PHS", "CELLSMCMAP", 0, Lifetime::Timeframe}); + } + + return DataProcessorSpec{ + "phos-cell-reader", + Inputs{}, // no inputs + outputSpecs, + AlgorithmSpec(initFunction), + Options{ + {"infile", VariantType::String, "phoscells.root", {"Name of the input file"}}, + {"treename", VariantType::String, "o2sim", {"Name of input tree"}}, + {"nevents", VariantType::Int, -1, {"number of events to run, -1: inf loop"}}, + {"terminate-on-eod", VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} + +} // namespace phos + +} // namespace o2 diff --git a/Detectors/PHOS/workflow/src/RecoWorkflow.cxx b/Detectors/PHOS/workflow/src/RecoWorkflow.cxx index 793cfd3ad844d..0d8d5e63eeac0 100644 --- a/Detectors/PHOS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/PHOS/workflow/src/RecoWorkflow.cxx @@ -25,7 +25,8 @@ #include "PHOSWorkflow/CellConverterSpec.h" #include "PHOSWorkflow/ClusterizerSpec.h" #include "PHOSWorkflow/DigitsPrinterSpec.h" -#include "PHOSWorkflow/PublisherSpec.h" +#include "PHOSWorkflow/ReaderSpec.h" +#include "PHOSWorkflow/WriterSpec.h" #include "PHOSWorkflow/RawToCellConverterSpec.h" #include "PHOSWorkflow/RawWriterSpec.h" #include "Framework/DataSpecUtils.h" @@ -44,18 +45,17 @@ namespace reco_workflow { const std::unordered_map InputMap{ - {"hits", InputType::Hits}, + {"raw", InputType::Raw}, {"digits", InputType::Digits}, - {"cells", InputType::Cells}, - {"raw", InputType::Raw}}; + {"cells", InputType::Cells}}; const std::unordered_map OutputMap{ - {"digits", OutputType::Digits}, {"cells", OutputType::Cells}, - {"raw", OutputType::Raw}, {"clusters", OutputType::Clusters}}; -o2::framework::WorkflowSpec getWorkflow(bool propagateMC, +o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, + bool disableRootOut, + bool propagateMC, bool enableDigitsPrinter, std::string const& cfgInput, std::string const& cfgOutput) @@ -79,63 +79,57 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, o2::framework::WorkflowSpec specs; - // if (isEnabled(OutputType::Raw)) { - // // add Raw encoder - // specs.emplace_back(o2::phos::reco_workflow::getRawWriterSpec()); - // } - + //Raw to .... if (inputType == InputType::Raw) { - //no explicit raw reader + //no explicit raw reader ?? if (isEnabled(OutputType::Cells)) { specs.emplace_back(o2::phos::reco_workflow::getRawToCellConverterSpec()); + if (!disableRootOut) { + specs.emplace_back(o2::phos::getCellWriterSpec(false)); + } + } + if (isEnabled(OutputType::Clusters)) { + specs.emplace_back(o2::phos::reco_workflow::getRawToCellConverterSpec()); + specs.emplace_back(o2::phos::reco_workflow::getClusterizerSpec(false)); //no MC propagation + if (!disableRootOut) { + specs.emplace_back(o2::phos::getClusterWriterSpec(propagateMC)); + } } } + // Digits to .... if (inputType == InputType::Digits) { + if (!disableRootInp) { + specs.emplace_back(o2::phos::getDigitsReaderSpec(propagateMC)); + } if (isEnabled(OutputType::Cells)) { - specs.emplace_back(o2::phos::getPublisherSpec(PublisherConf{ - "phos-digit-reader", - "o2sim", - {"digitbranch", "PHOSDigit", "Digit branch"}, - {"digittrigger", "PHOSDigitTrigRecords", "TrigRecords branch"}, - {"mcbranch", "PHOSDigitMCTruth", "MC label branch"}, - {"mcmapbranch", "", "Dummy branch"}, - o2::framework::OutputSpec{"PHS", "DIGITS"}, - o2::framework::OutputSpec{"PHS", "DIGITTRIGREC"}, - o2::framework::OutputSpec{"PHS", "DIGITSMCTR"}, - o2::framework::OutputSpec{"PHS", ""}}, // it empty, do not create - propagateMC, false)); // add converter for cells specs.emplace_back(o2::phos::reco_workflow::getCellConverterSpec(propagateMC)); - } - - if (isEnabled(OutputType::Clusters)) { - specs.emplace_back(o2::phos::getPublisherSpec(PublisherConf{ - "phos-digit-reader", - "o2sim", - {"digitbranch", "PHOSDigit", "Digit branch"}, - {"digittrigger", "PHOSDigitTrigRecords", "TrigRecords branch"}, - {"mcbranch", "PHOSDigitMCTruth", "MC label branch"}, - {"mcmapbranch", "", "Dummy branch"}, - o2::framework::OutputSpec{"PHS", "DIGITS"}, - o2::framework::OutputSpec{"PHS", "DIGITTRIGREC"}, - o2::framework::OutputSpec{"PHS", "DIGITSMCTR"}, - o2::framework::OutputSpec{"PHS", ""}}, // it empty, do not create - propagateMC, false)); - // add clusterizer - specs.emplace_back(o2::phos::reco_workflow::getClusterizerSpec(propagateMC)); - } - - if (enableDigitsPrinter) { - specs.emplace_back(o2::phos::reco_workflow::getPhosDigitsPrinterSpec()); + if (!disableRootOut) { + specs.emplace_back(o2::phos::getCellWriterSpec(propagateMC)); + } + } else { + if (isEnabled(OutputType::Clusters)) { + specs.emplace_back(o2::phos::reco_workflow::getClusterizerSpec(propagateMC)); + if (!disableRootOut) { + specs.emplace_back(o2::phos::getClusterWriterSpec(propagateMC)); + } + } } } + //Cells to if (inputType == InputType::Cells) { + if (!disableRootInp) { + specs.emplace_back(o2::phos::getCellReaderSpec(propagateMC)); + } if (isEnabled(OutputType::Clusters)) { // add clusterizer specs.emplace_back(o2::phos::reco_workflow::getCellClusterizerSpec(propagateMC)); + if (!disableRootOut) { + specs.emplace_back(o2::phos::getClusterWriterSpec(propagateMC)); + } } } diff --git a/Detectors/PHOS/workflow/src/WriterSpec.cxx b/Detectors/PHOS/workflow/src/WriterSpec.cxx new file mode 100644 index 0000000000000..e3eb8f77d7100 --- /dev/null +++ b/Detectors/PHOS/workflow/src/WriterSpec.cxx @@ -0,0 +1,99 @@ +// 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 ClusterWriterSpec.cxx + +#include + +#include "PHOSWorkflow/WriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsPHOS/Cell.h" +#include "DataFormatsPHOS/Cluster.h" +#include "DataFormatsPHOS/MCLabel.h" +#include "DataFormatsPHOS/TriggerRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace phos +{ + +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; +using ClusType = std::vector; +using CellType = std::vector; +using TriggerRecordType = std::vector; +using MCLabelType = o2::dataformats::MCTruthContainer; +using namespace o2::header; + +DataProcessorSpec getClusterWriterSpec(bool useMC) +{ + // Spectators for logging + // this is only to restore the original behavior + auto ClustersSize = std::make_shared(0); + auto ClustersSizeGetter = [ClustersSize](ClusType const& Clusters) { + *ClustersSize = Clusters.size(); + }; + + if (useMC) { + return MakeRootTreeWriterSpec("phos-cluster-writer", + "phosclusters.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with PHOS clusters"}, + BranchDefinition{InputSpec{"clus", "PHS", "CLUSTERS", 0}, + "PHOSCluster", ClustersSizeGetter}, + BranchDefinition{InputSpec{"clusRecs", "PHS", "CLUSTERTRIGRECS", 0}, + "PHOSClusterTrigRec"}, + BranchDefinition{InputSpec{"clusMC", "PHS", "CLUSTERTRUEMC", 0}, + "PHOSClusterTrueMC"})(); + } else { + return MakeRootTreeWriterSpec("phos-cluster-writer", + "phosclusters.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with PHOS clusters"}, + BranchDefinition{InputSpec{"clus", "PHS", "CLUSTERS", 0}, + "PHOSCluster", ClustersSizeGetter}, + BranchDefinition{InputSpec{"clusRecs", "PHS", "CLUSTERTRIGRECS", 0}, + "PHOSClusterTrigRec"})(); + } +} + +DataProcessorSpec getCellWriterSpec(bool useMC) +{ + // Spectators for logging + // this is only to restore the original behavior + auto CellSize = std::make_shared(0); + auto CellSizeGetter = [CellSize](CellType const& Cells) { + *CellSize = Cells.size(); + }; + + if (useMC) { + return MakeRootTreeWriterSpec("phos-cell-writer", + "phoscells.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with PHOS cells"}, + BranchDefinition{InputSpec{"cell", "PHS", "CELLS", 0}, + "PHOSCell", CellSizeGetter}, + BranchDefinition{InputSpec{"PHOSCellTR", "PHS", "CELLTRIGREC", 0}, + "PHOSCellTrigRec"}, + BranchDefinition{InputSpec{"PHOSCellMCTruth", "PHS", "CELLSMCTR", 0}, + "PHOSCellTrueMC"})(); + } else { + return MakeRootTreeWriterSpec("phos-cell-writer", + "phoscells.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with PHOS cells"}, + BranchDefinition{InputSpec{"cell", "PHS", "CELLS", 0}, + "PHOSCell", CellSizeGetter}, + BranchDefinition{InputSpec{"PHOSCellTR", "PHS", "CELLTRIGREC", 0}, + "PHOSCellTrigRec"})(); + } +} +} // namespace phos +} // namespace o2 \ No newline at end of file diff --git a/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx b/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx index a81b3d1e9ea38..4b4221d2780de 100644 --- a/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx +++ b/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx @@ -31,6 +31,8 @@ void customize(std::vector& workflowOptions) {"output-type", o2::framework::VariantType::String, "digits", {"digits, raw, clusters, cells"}}, {"enable-digits-printer", o2::framework::VariantType::Bool, false, {"enable digits printer component"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, }; std::swap(workflowOptions, options); } @@ -52,7 +54,9 @@ void customize(std::vector& workflowOptions) o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { // - return o2::phos::reco_workflow::getWorkflow(not cfgc.options().get("disable-mc"), // + return o2::phos::reco_workflow::getWorkflow(cfgc.options().get("disable-root-input"), + cfgc.options().get("disable-root-output"), + !cfgc.options().get("disable-mc"), // cfgc.options().get("enable-digits-printer"), // cfgc.options().get("input-type"), // cfgc.options().get("output-type") // diff --git a/Steer/DigitizerWorkflow/src/PHOSDigitWriterSpec.h b/Steer/DigitizerWorkflow/src/PHOSDigitWriterSpec.h index 21055f5ef9142..d621f6f2d23ef 100644 --- a/Steer/DigitizerWorkflow/src/PHOSDigitWriterSpec.h +++ b/Steer/DigitizerWorkflow/src/PHOSDigitWriterSpec.h @@ -32,13 +32,22 @@ o2::framework::DataProcessorSpec getPHOSDigitWriterSpec(bool mctruth) { using InputSpec = framework::InputSpec; using MakeRootTreeWriterSpec = framework::MakeRootTreeWriterSpec; - return MakeRootTreeWriterSpec("PHOSDigitWriter", - "phosdigits.root", - "o2sim", - 1, - BranchDefinition>{InputSpec{"phosdigits", "PHS", "DIGITS"}, "PHOSDigit"}, - BranchDefinition>{InputSpec{"phosdigitstrigrec", "PHS", "DIGITTRIGREC"}, "PHOSDigitTrigRecords"}, - BranchDefinition>{InputSpec{"phosdigitsmc", "PHS", "DIGITSMCTR"}, "PHOSDigitMCTruth", mctruth ? 1 : 0})(); + if (mctruth) { + return MakeRootTreeWriterSpec("PHOSDigitWriter", + "phosdigits.root", + "o2sim", + 1, + BranchDefinition>{InputSpec{"phosdigits", "PHS", "DIGITS"}, "PHOSDigit"}, + BranchDefinition>{InputSpec{"phosdigitstrigrec", "PHS", "DIGITTRIGREC"}, "PHOSDigitTrigRecords"}, + BranchDefinition>{InputSpec{"phosdigitsmc", "PHS", "DIGITSMCTR"}, "PHOSDigitMCTruth"})(); + } else { + return MakeRootTreeWriterSpec("PHOSDigitWriter", + "phosdigits.root", + "o2sim", + 1, + BranchDefinition>{InputSpec{"phosdigits", "PHS", "DIGITS"}, "PHOSDigit"}, + BranchDefinition>{InputSpec{"phosdigitstrigrec", "PHS", "DIGITTRIGREC"}, "PHOSDigitTrigRecords"})(); + } } } // namespace phos diff --git a/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.cxx index 1af09ca4a7e49..6152b6c3a6ce3 100644 --- a/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/PHOSDigitizerSpec.cxx @@ -49,6 +49,10 @@ void DigitizerSpec::initDigitizerTask(framework::InitContext& ic) // init digitizer mDigitizer.init(); + auto mctruth = ic.options().get("mctruth"); + if (!mctruth) { + mDigitizer.processMC(false); + } if (mHits) { delete mHits; @@ -72,7 +76,6 @@ void DigitizerSpec::retrieveHits(const char* brname, void DigitizerSpec::run(framework::ProcessingContext& pc) { - // read collision context from input auto context = pc.inputs().get("collisioncontext"); context->initSimChains(o2::detectors::DetID::PHS, mSimChains); @@ -94,13 +97,14 @@ void DigitizerSpec::run(framework::ProcessingContext& pc) int indexStart = mDigitsOut.size(); auto& eventParts = context->getEventParts(); //if this is last stream of hits and we can write directly to final vector of digits? Otherwize use temporary vectors + mDigitsFinal.clear(); + mDigitsTmp.clear(); bool isLastStream = true; double eventTime = timesview[0].getTimeNS() - o2::phos::PHOSSimParams::Instance().mDeadTime; //checked above that list not empty int eventId; // loop over all composite collisions given from context // (aka loop over all the interaction records) for (int collID = 0; collID < n; ++collID) { - double dt = timesview[collID].getTimeNS() - eventTime; //start new PHOS readout, continue current or dead time? if (dt > mReadoutTime && dt < mDeadTime) { //dead time, skip event continue; @@ -137,7 +141,6 @@ void DigitizerSpec::run(framework::ProcessingContext& pc) // Add trigger record triggers.emplace_back(timesview[eventId], indexStart, mDigitsOut.size() - indexStart); indexStart = mDigitsOut.size(); - mDigitsFinal.clear(); } else { //Fill intermediate digitvector mDigitsTmp.swap(mDigitsFinal); mDigitizer.processHits(mHits, mDigitsTmp, mDigitsFinal, mLabels, collID, source, dt); @@ -184,7 +187,8 @@ DataProcessorSpec getPHOSDigitizerSpec(int channel, bool mctruth) "PHOSDigitizer", Inputs{InputSpec{"collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast(channel), Lifetime::Timeframe}}, outputs, AlgorithmSpec{o2::framework::adaptFromTask()}, - Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}}}; + Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}, + {"mctruth", VariantType::Bool, true, {"whether to process MC info"}}}}; } } // namespace phos } // namespace o2 From dcf4a7bc5830306a52166aa5f29a928b5da8887e Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 23 Feb 2021 21:06:17 +0100 Subject: [PATCH 3/8] Make options consistent --- .../include/CPVWorkflow/RecoWorkflow.h | 1 - Detectors/CPV/workflow/src/RecoWorkflow.cxx | 5 ----- .../CPV/workflow/src/cpv-reco-workflow.cxx | 18 ++++++++++-------- .../include/PHOSWorkflow/RecoWorkflow.h | 1 - Detectors/PHOS/workflow/src/RecoWorkflow.cxx | 2 -- .../PHOS/workflow/src/phos-reco-workflow.cxx | 18 ++++++++++-------- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h b/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h index c0535a89f5c25..900e40c080e2d 100644 --- a/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h +++ b/Detectors/CPV/workflow/include/CPVWorkflow/RecoWorkflow.h @@ -38,7 +38,6 @@ enum struct OutputType { Digits, framework::WorkflowSpec getWorkflow(bool disableRootInp, bool disableRootOut, bool propagateMC = true, - bool enableDigitsPrinter = false, std::string const& cfgInput = "digits", // std::string const& cfgOutput = "clusters" // ); diff --git a/Detectors/CPV/workflow/src/RecoWorkflow.cxx b/Detectors/CPV/workflow/src/RecoWorkflow.cxx index 64a3509836dfb..0f6f241843374 100644 --- a/Detectors/CPV/workflow/src/RecoWorkflow.cxx +++ b/Detectors/CPV/workflow/src/RecoWorkflow.cxx @@ -57,7 +57,6 @@ const std::unordered_map OutputMap{ o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, bool disableRootOut, bool propagateMC, - bool enableDigitsPrinter, std::string const& cfgInput, std::string const& cfgOutput) { @@ -106,10 +105,6 @@ o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, specs.emplace_back(o2::cpv::getDigitsReaderSpec(propagateMC)); } - // if (enableDigitsPrinter) { - // specs.emplace_back(o2::cpv::reco_workflow::getDigitsPrinterSpec()); - // } - if (isEnabled(OutputType::Clusters)) { // add clusterizer specs.emplace_back(o2::cpv::reco_workflow::getClusterizerSpec(propagateMC)); diff --git a/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx b/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx index 73b5affd1a79b..d74275e344775 100644 --- a/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx +++ b/Detectors/CPV/workflow/src/cpv-reco-workflow.cxx @@ -17,6 +17,7 @@ #include "Framework/ConfigParamSpec.h" #include "CPVWorkflow/RecoWorkflow.h" #include "Algorithm/RangeTokenizer.h" +#include "CommonUtils/ConfigurableParam.h" #include #include @@ -27,13 +28,12 @@ void customize(std::vector& workflowOptions) { std::vector options{ - {"input-type", o2::framework::VariantType::String, "hits", {"hits, digits, raw, clusters"}}, - {"output-type", o2::framework::VariantType::String, "digits", {"digits, clusters"}}, - {"enable-digits-printer", o2::framework::VariantType::Bool, false, {"enable digits printer component"}}, + {"input-type", o2::framework::VariantType::String, "digits", {"hits, digits, raw, clusters"}}, + {"output-type", o2::framework::VariantType::String, "clusters", {"digits, clusters"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information"}}, {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, - }; + {"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; std::swap(workflowOptions, options); } @@ -54,11 +54,13 @@ void customize(std::vector& workflowOptions) o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { // + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); + return o2::cpv::reco_workflow::getWorkflow(cfgc.options().get("disable-root-input"), cfgc.options().get("disable-root-output"), - !cfgc.options().get("disable-mc"), // - cfgc.options().get("enable-digits-printer"), // - cfgc.options().get("input-type"), // - cfgc.options().get("output-type") // + !cfgc.options().get("disable-mc"), // + cfgc.options().get("input-type"), // + cfgc.options().get("output-type") // ); } diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h index 9d0df0973816f..8e94cad70672e 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/RecoWorkflow.h @@ -41,7 +41,6 @@ enum struct OutputType { Digits, framework::WorkflowSpec getWorkflow(bool disableRootInp, bool disableRootOut, bool propagateMC = true, - bool enableDigitsPrinter = false, std::string const& cfgInput = "hits", // std::string const& cfgOutput = "clusters" // ); diff --git a/Detectors/PHOS/workflow/src/RecoWorkflow.cxx b/Detectors/PHOS/workflow/src/RecoWorkflow.cxx index 0d8d5e63eeac0..5bd0359bbd0e6 100644 --- a/Detectors/PHOS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/PHOS/workflow/src/RecoWorkflow.cxx @@ -24,7 +24,6 @@ #include "PHOSWorkflow/RecoWorkflow.h" #include "PHOSWorkflow/CellConverterSpec.h" #include "PHOSWorkflow/ClusterizerSpec.h" -#include "PHOSWorkflow/DigitsPrinterSpec.h" #include "PHOSWorkflow/ReaderSpec.h" #include "PHOSWorkflow/WriterSpec.h" #include "PHOSWorkflow/RawToCellConverterSpec.h" @@ -56,7 +55,6 @@ const std::unordered_map OutputMap{ o2::framework::WorkflowSpec getWorkflow(bool disableRootInp, bool disableRootOut, bool propagateMC, - bool enableDigitsPrinter, std::string const& cfgInput, std::string const& cfgOutput) { diff --git a/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx b/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx index 4b4221d2780de..c37909c1c21d9 100644 --- a/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx +++ b/Detectors/PHOS/workflow/src/phos-reco-workflow.cxx @@ -17,6 +17,7 @@ #include "Framework/ConfigParamSpec.h" #include "PHOSWorkflow/RecoWorkflow.h" #include "Algorithm/RangeTokenizer.h" +#include "CommonUtils/ConfigurableParam.h" #include #include @@ -27,13 +28,12 @@ void customize(std::vector& workflowOptions) { std::vector options{ - {"input-type", o2::framework::VariantType::String, "hits", {"hits, digits, raw, clusters"}}, - {"output-type", o2::framework::VariantType::String, "digits", {"digits, raw, clusters, cells"}}, - {"enable-digits-printer", o2::framework::VariantType::Bool, false, {"enable digits printer component"}}, + {"input-type", o2::framework::VariantType::String, "digits", {"hits, digits, raw, clusters"}}, + {"output-type", o2::framework::VariantType::String, "cells", {"digits, raw, clusters, cells"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information"}}, {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, - }; + {"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; std::swap(workflowOptions, options); } @@ -54,11 +54,13 @@ void customize(std::vector& workflowOptions) o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { // + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); + return o2::phos::reco_workflow::getWorkflow(cfgc.options().get("disable-root-input"), cfgc.options().get("disable-root-output"), - !cfgc.options().get("disable-mc"), // - cfgc.options().get("enable-digits-printer"), // - cfgc.options().get("input-type"), // - cfgc.options().get("output-type") // + !cfgc.options().get("disable-mc"), // + cfgc.options().get("input-type"), // + cfgc.options().get("output-type") // ); } From 8efe3801c55e05f1e2db640058226c0b1af508d9 Mon Sep 17 00:00:00 2001 From: peressounko Date: Wed, 24 Feb 2021 13:44:47 +0300 Subject: [PATCH 4/8] placeholder --- .../include/PHOSWorkflow/PublisherSpec.h | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h new file mode 100644 index 0000000000000..1499eae230787 --- /dev/null +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h @@ -0,0 +1,47 @@ +// 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. + +#include "Framework/DataProcessorSpec.h" +#include "Framework/OutputSpec.h" +#include +#include + +namespace o2 +{ + +namespace phos +{ + +using OutputSpec = framework::OutputSpec; + +struct PublisherConf { + struct BranchOptionConfig { + std::string option; + std::string defval; + std::string help; + }; + + std::string processName; + std::string defaultTreeName; + BranchOptionConfig databranch; + BranchOptionConfig datatrbranch; + BranchOptionConfig mcbranch; + BranchOptionConfig mcmapbranch; + OutputSpec dataoutput; + OutputSpec datatroutput; + OutputSpec mcoutput; + OutputSpec mcmapoutput; +}; + +framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC = true, bool createMCMap = false); + +} // namespace phos +} // end namespace o2 + From e75cd91aa0ff89100fd312ea1704a6f55816eef6 Mon Sep 17 00:00:00 2001 From: peressounko Date: Wed, 24 Feb 2021 13:49:54 +0300 Subject: [PATCH 5/8] clang Publisher --- Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h index 1499eae230787..f79d38432cfeb 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/PublisherSpec.h @@ -44,4 +44,3 @@ framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool } // namespace phos } // end namespace o2 - From 8c1a3c3330e9f787e77e02ce2d294388f4096622 Mon Sep 17 00:00:00 2001 From: peressounko Date: Wed, 24 Feb 2021 14:27:39 +0300 Subject: [PATCH 6/8] Create PublisherSpec.cxx --- Detectors/PHOS/workflow/src/PublisherSpec.cxx | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 Detectors/PHOS/workflow/src/PublisherSpec.cxx diff --git a/Detectors/PHOS/workflow/src/PublisherSpec.cxx b/Detectors/PHOS/workflow/src/PublisherSpec.cxx new file mode 100644 index 0000000000000..a170eb8aa73fd --- /dev/null +++ b/Detectors/PHOS/workflow/src/PublisherSpec.cxx @@ -0,0 +1,179 @@ +// 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. + +#include "DataFormatsPHOS/PHOSBlockHeader.h" +#include "PHOSWorkflow/PublisherSpec.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Headers/DataHeader.h" +#include "DPLUtils/RootTreeReader.h" +#include "Framework/DataSpecUtils.h" +#include +#include + +namespace o2 +{ + +namespace phos +{ + +o2::framework::DataProcessorSpec getPublisherSpec(PublisherConf const& config, bool propagateMC, bool createMCMap) +{ + struct ProcessAttributes { + std::shared_ptr reader; + std::string datatype; + bool terminateOnEod; + bool finished; + }; + + auto initFunction = [config, propagateMC, createMCMap](o2::framework::InitContext& ic) { + // get the option from the init context + auto filename = ic.options().get("infile"); + auto treename = ic.options().get("treename"); + auto dtbrName = ic.options().get(config.databranch.option.c_str()); // databranch name + auto dttrbrName = ic.options().get(config.datatrbranch.option.c_str()); // datatrigrec name + auto mcbrName = ic.options().get(config.mcbranch.option.c_str()); // mcbranch name + auto mcmapbrName = ic.options().get(config.mcmapbranch.option.c_str()); // mc map branch name + auto nofEvents = ic.options().get("nevents"); + // auto publishingMode = nofEvents == -1 ? o2::framework::RootTreeReader::PublishingMode::Single : o2::framework::RootTreeReader::PublishingMode::Loop; + auto publishingMode = o2::framework::RootTreeReader::PublishingMode::Single; + + auto processAttributes = std::make_shared(); + { + processAttributes->terminateOnEod = ic.options().get("terminate-on-eod"); + processAttributes->finished = false; + processAttributes->datatype = config.databranch.defval; + auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); + auto dttro = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.datatroutput); + auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); + auto mcmapo = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcmapoutput); + constexpr auto persistency = o2::framework::Lifetime::Timeframe; + o2::header::DataHeader::SubSpecificationType subSpec = 0; + if (propagateMC) { + if (!createMCMap) { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, + dtbrName.c_str(), // name of data branch + o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, + dttrbrName.c_str(), // name of data triggerrecords branch + o2::framework::Output{mco.origin, mco.description, subSpec, persistency}, + mcbrName.c_str() // name of mc label branch + ); + } else { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, + dtbrName.c_str(), // name of data branch + o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, + dttrbrName.c_str(), // name of data triggerrecords branch + o2::framework::Output{mco.origin, mco.description, subSpec, persistency}, + mcbrName.c_str(), // name of mc label branch + o2::framework::Output{mcmapo.origin, mcmapo.description, subSpec, persistency}, + mcmapbrName.c_str() // name of mc label branch + ); + } + } else { + processAttributes->reader = std::make_shared(treename.c_str(), // tree name + filename.c_str(), // input file name + nofEvents, // number of entries to publish + publishingMode, + o2::framework::Output{dto.origin, dto.description, subSpec, persistency}, + dtbrName.c_str(), // name of data branch + o2::framework::Output{dttro.origin, dttro.description, subSpec, persistency}, + dttrbrName.c_str() // name of data tr branch + ); + } + } + + auto processFunction = [processAttributes, propagateMC, createMCMap](o2::framework::ProcessingContext& pc) { + if (processAttributes->finished) { + return; + } + + auto publish = [&processAttributes, &pc, propagateMC, createMCMap]() { + o2::phos::PHOSBlockHeader phosheader(true); + if (processAttributes->reader->next()) { + (*processAttributes->reader)(pc, phosheader); + } else { + processAttributes->reader.reset(); + return false; + } + return true; + }; + + bool active(true); + if (!publish()) { + active = false; + // Send dummy header with no payload option + o2::phos::PHOSBlockHeader dummyheader(false); + pc.outputs().snapshot(o2::framework::OutputRef{"output", 0, {dummyheader}}, 0); + pc.outputs().snapshot(o2::framework::OutputRef{"outputTR", 0, {dummyheader}}, 0); + if (propagateMC) { + pc.outputs().snapshot(o2::framework::OutputRef{"outputMC", 0, {dummyheader}}, 0); + if (createMCMap) { + pc.outputs().snapshot(o2::framework::OutputRef{"outputMCmap", 0, {dummyheader}}, 0); + } + } + } + if ((processAttributes->finished = (active == false)) && processAttributes->terminateOnEod) { + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(framework::QuitRequest::Me); + } + }; + + return processFunction; + }; + + auto createOutputSpecs = [&config, propagateMC, createMCMap]() { + std::vector outputSpecs; + auto dto = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.dataoutput); + auto dttro = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.datatroutput); + auto mco = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcoutput); + auto mcmapo = o2::framework::DataSpecUtils::asConcreteDataTypeMatcher(config.mcmapoutput); + outputSpecs.emplace_back(o2::framework::OutputSpec{{"output"}, dto.origin, dto.description, 0, o2::framework::Lifetime::Timeframe}); + outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputTR"}, dttro.origin, dttro.description, 0, o2::framework::Lifetime::Timeframe}); + if (propagateMC) { + outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputMC"}, mco.origin, mco.description, 0, o2::framework::Lifetime::Timeframe}); + if (createMCMap) { + outputSpecs.emplace_back(o2::framework::OutputSpec{{"outputMCmap"}, mcmapo.origin, mcmapo.description, 0, o2::framework::Lifetime::Timeframe}); + } + } + return std::move(outputSpecs); + }; + + auto& dtb = config.databranch; + auto& dttrb = config.datatrbranch; + auto& mcb = config.mcbranch; + auto& mcmapb = config.mcmapbranch; + return o2::framework::DataProcessorSpec{ + config.processName.c_str(), + o2::framework::Inputs{}, // no inputs + {createOutputSpecs()}, + o2::framework::AlgorithmSpec(initFunction), + o2::framework::Options{ + {"infile", o2::framework::VariantType::String, "phosdigits.root", {"Name of the input file"}}, + {"treename", o2::framework::VariantType::String, config.defaultTreeName.c_str(), {"Name of input tree"}}, + {dtb.option.c_str(), o2::framework::VariantType::String, dtb.defval.c_str(), {dtb.help.c_str()}}, + {dttrb.option.c_str(), o2::framework::VariantType::String, dttrb.defval.c_str(), {dttrb.help.c_str()}}, + {mcb.option.c_str(), o2::framework::VariantType::String, mcb.defval.c_str(), {mcb.help.c_str()}}, + {mcmapb.option.c_str(), o2::framework::VariantType::String, mcmapb.defval.c_str(), {mcmapb.help.c_str()}}, + {"nevents", o2::framework::VariantType::Int, -1, {"number of events to run"}}, + {"terminate-on-eod", o2::framework::VariantType::Bool, true, {"terminate on end-of-data"}}, + }}; +} + +} // namespace phos + +} // namespace o2 From 134028f67797318f9ab732091e4f923b744f1be2 Mon Sep 17 00:00:00 2001 From: peressounko Date: Wed, 24 Feb 2021 14:28:59 +0300 Subject: [PATCH 7/8] Update CMakeLists.txt --- Detectors/PHOS/workflow/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Detectors/PHOS/workflow/CMakeLists.txt b/Detectors/PHOS/workflow/CMakeLists.txt index 531935fae0c06..43ac0c51cf17d 100644 --- a/Detectors/PHOS/workflow/CMakeLists.txt +++ b/Detectors/PHOS/workflow/CMakeLists.txt @@ -10,6 +10,7 @@ o2_add_library(PHOSWorkflow SOURCES src/RecoWorkflow.cxx + src/PublisherSpec.cxx src/ReaderSpec.cxx src/CellConverterSpec.cxx src/RawToCellConverterSpec.cxx From e2a46c8821a527a097567d5a07a2ae3a14be98e1 Mon Sep 17 00:00:00 2001 From: peressounko Date: Wed, 24 Feb 2021 17:34:30 +0300 Subject: [PATCH 8/8] build/O2/fullCI complilation warning fix --- Detectors/PHOS/calib/include/PHOSCalib/Pedestals.h | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Detectors/PHOS/calib/include/PHOSCalib/Pedestals.h b/Detectors/PHOS/calib/include/PHOSCalib/Pedestals.h index efdc9ff417536..a893f36680c22 100644 --- a/Detectors/PHOS/calib/include/PHOSCalib/Pedestals.h +++ b/Detectors/PHOS/calib/include/PHOSCalib/Pedestals.h @@ -48,18 +48,7 @@ class Pedestals /// \brief Constructor for tests Pedestals(int test); - Pedestals(Pedestals* other) - { - mHGPedestals = other->mHGPedestals; - mLGPedestals = other->mLGPedestals; - } - - Pedestals& operator=(const Pedestals& other) - { - mHGPedestals = other.mHGPedestals; - mLGPedestals = other.mLGPedestals; - return *this; - } + Pedestals& operator=(const Pedestals& other) = default; /// \brief Destructor ~Pedestals() = default;