From b3d82a6bb4188cd4508b605417da4f912f392a91 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Sun, 10 Jul 2022 18:19:52 +0200 Subject: [PATCH 1/5] TRD TRAP add Q2 shift --- Detectors/TRD/simulation/src/TrapSimulator.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/Detectors/TRD/simulation/src/TrapSimulator.cxx b/Detectors/TRD/simulation/src/TrapSimulator.cxx index 97ba8cc0a9ade..a6fc166b4e18f 100644 --- a/Detectors/TRD/simulation/src/TrapSimulator.cxx +++ b/Detectors/TRD/simulation/src/TrapSimulator.cxx @@ -1759,6 +1759,7 @@ void TrapSimulator::fitTracklet() temp = q2; // temporarily move to 64bit variable temp *= mScaleQ; q2 = temp >> 32; + q2 >>= 1; // q2 needs additional shift, since we want the same range as q0 and q1 and q2 is only 6 bit wide // clip the charges if (q0 > mMaskQ0Q1) { From 7f0eec3e27f98b076a8386873ded4589d7dae4af Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Sun, 10 Jul 2022 18:20:09 +0200 Subject: [PATCH 2/5] TRD TRAP report rejected digits --- Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx b/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx index 206148b1596f6..b1c6a60337401 100644 --- a/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx @@ -252,6 +252,7 @@ void TRDDPLTrapSimulatorTask::run(o2::framework::ProcessingContext& pc) auto parallelTime = std::chrono::high_resolution_clock::now() - timeParallelStart; // accumulate results and add MC labels + int nDigitsRejected = 0; for (size_t iTrig = 0; iTrig < triggerRecords.size(); ++iTrig) { if (mUseMC) { int currDigitIndex = 0; // counter for all digits which are associated to tracklets @@ -293,6 +294,7 @@ void TRDDPLTrapSimulatorTask::run(o2::framework::ProcessingContext& pc) triggerRecords[iTrig].setDigitRange(digitsOut.size() - triggerRecords[iTrig].getNumberOfDigits(), triggerRecords[iTrig].getNumberOfDigits()); } else { // digits are not kept, we just need to update the trigger record + nDigitsRejected += triggerRecords[iTrig].getNumberOfDigits(); triggerRecords[iTrig].setDigitRange(digitsOut.size(), 0); } } @@ -300,6 +302,7 @@ void TRDDPLTrapSimulatorTask::run(o2::framework::ProcessingContext& pc) auto processingTime = std::chrono::high_resolution_clock::now() - timeProcessingStart; LOG(info) << "Trap simulator found " << tracklets.size() << " tracklets from " << digits.size() << " Digits."; + LOG(info) << "In total " << nDigitsRejected << " digits were rejected due to digit downscaling factor of " << mDigitDownscaling; if (mUseMC) { LOG(info) << "In total " << lblTracklets.getNElements() << " MC labels are associated to the " << lblTracklets.getIndexedSize() << " tracklets"; } From b1aa8e8b185c0bb5aa61d1fea4c2104aa0497a31 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Sun, 10 Jul 2022 18:21:16 +0200 Subject: [PATCH 3/5] TRD mapping of Link ID to HCID --- .../TRD/include/DataFormatsTRD/Constants.h | 5 +- .../include/DataFormatsTRD/HelperMethods.h | 72 ++++++++++--------- Detectors/TRD/base/include/TRDBase/FeeParam.h | 3 - Detectors/TRD/base/src/FeeParam.cxx | 28 -------- 4 files changed, 43 insertions(+), 65 deletions(-) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h index d616d0e570780..08c8534a4858d 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h @@ -26,12 +26,14 @@ constexpr int NSECTOR = 18; // the number of sectors constexpr int NSTACK = 5; // the number of stacks per sector constexpr int NLAYER = 6; // the number of layers constexpr int NCHAMBERPERSEC = 30; // the number of chambers per sector +constexpr int NHCPERSEC = 60; // the number of half-chambers per sector constexpr int MAXCHAMBER = 540; // the maximum number of installed chambers constexpr int MAXHALFCHAMBER = 1080; // the maximum number of installed half-chambers constexpr int NCHAMBER = 521; // the number of chambers actually installed constexpr int NHALFCRU = 72; // the number of half cru (link bundles) constexpr int NLINKSPERHALFCRU = 15; // the number of links per half cru or cru end point. -constexpr int NRU = 36; // the number of CRU we have +constexpr int NLINKSPERCRU = 30; // the number of links per CRU (two CRUs serve one supermodule) +constexpr int NCRU = 36; // the number of CRU we have constexpr int NFLP = 12; // the number of FLP we have. constexpr int NCRUPERFLP = 3; // the number of CRU per FLP constexpr int TRDLINKID = 15; // hard coded link id, specific to TRD @@ -77,6 +79,7 @@ constexpr int CRUPADDING32 = 0xeeeeeeee; // padding word used in the cru. constexpr int CHANNELNRNOTRKLT = 23; // this marks channels in the ADC mask which don't contribute to a tracklet constexpr int NOTRACKLETFIT = 31; // this value is assigned to the fit pointer in case no tracklet is available constexpr int TRACKLETENDMARKER = 0x10001000; // marker for the end of tracklets in raw data, 2 of these. +constexpr int PADDINGWORD = 0xeeeeeeee; // half-CRU links will be padded with this words to get an even number of 256bit words constexpr int DIGITENDMARKER = 0x0; // marker for the end of digits in raw data, 2 of these constexpr int MAXDATAPERLINK32 = 13824; // max number of 32 bit words per link ((21x12+2+4)*64) 64 mcm, 21 channels, 10 words per channel 2 header words(DigitMCMHeader DigitMCMADCmask) 4 words for tracklets. constexpr int MAXDATAPERLINK256 = 1728; // max number of linkwords per cru link. (256bit words) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h index 08e1fc9290d8b..709c5978ab7d9 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/HelperMethods.h @@ -94,53 +94,59 @@ struct HelperMethods { return (layer + stack * constants::NLAYER + sector * constants::NLAYER * constants::NSTACK); } - static int getORIinSuperModule(int detector, int readoutboard) + static int getORIinSuperModule(int hcid) { - //given a detector and readoutboard + // given a half chamber ID compute the link ID from [0..59] + // where link ID [0..29] is for A-side CRU and [30..59] for C-side CRU int ori = -1; - int trdstack = HelperMethods::getStack(detector); - int trdlayer = HelperMethods::getLayer(detector); - int side = HelperMethods::getROBSide(readoutboard); - //TODO ccdb lookup of detector/stack/layer/side for link id. - bool aside = false; - if (trdstack == 0 || trdstack == 1) { - aside = true; //aside - } else { - if (trdstack != 2) { - aside = false; //cside - } else { - if (side == 0) { - aside = true; //stack - } else { - aside = false; //stack2, halfchamber 1 - } - } + int stack = getStack(hcid / 2); + int layer = getLayer(hcid / 2); + int side = (hcid % 2 == 0) ? 0 : 1; + bool isAside = false; + if (stack < 2 || (stack == 2 && side == 0)) { + isAside = true; } - if (aside) { - ori = trdstack * 12 + (5 - trdlayer + side * 5) + trdlayer / 6 + side; // <- that is correct for A side at least for now, probably not for very long LUT as that will come form CCDB ni anycase. + if (isAside) { + ori = stack * constants::NLAYER * 2 + side * constants::NLAYER + 5 - layer; } else { - //cside - int newside = side; - if (trdstack == 2) { - newside = 0; // the last part of C side CRU is a special case. + // C-side + ori = (4 - stack) * constants::NLAYER * 2 + side * constants::NLAYER + 5 - layer; + if (stack == 2) { + ori -= constants::NLAYER; } - ori = (4 - trdstack) * 12 + (5 - trdlayer + newside * 5) + trdlayer / 6 + newside; - ori += 30; // 30 to offset if from the a side link , 69 links in total + ori += constants::NLINKSPERCRU; } - //see TDP for explanation of mapping TODO should probably come from CCDB + // TODO: put mapping into TDP and prepare for alternative mapping (CCDB?) return ori; } + static int getHCIDFromLinkID(int link) + { + // link = halfcrulink [0..14] + halfcru [0..71] * constants::NLINKSPERHALFCRU (15) -> [0..1079] + + int sector = link / constants::NHCPERSEC; + int linkSector = link % constants::NHCPERSEC; // [0..59] + int linkCRU = linkSector % constants::NLINKSPERCRU; // [0..29] + int stack = linkCRU / (constants::NLAYER * 2); + int layer = 5 - (linkCRU % constants::NLAYER); + int side = (linkCRU / constants::NLAYER) % 2; + if (linkSector >= constants::NLINKSPERCRU) { + // C-side + stack = 4 - stack; + if (stack == 2) { + side = 1; + } + } + return sector * constants::NHCPERSEC + stack * constants::NLAYER * 2 + layer * 2 + side; + } + static int getLinkIDfromHCID(int hcid) { //return a number in range [0:29] for the link related to this hcid with in its respective CRU //lower 15 is endpoint 0 and upper 15 is endpoint 1 //a side has 30, c side has 30 to give 60 links for a supermodule - int detector = hcid / 2; - int supermodule = hcid / 60; - int chamberside = hcid % 2; // 0 for side 0, 1 for side 1; - // now offset for supermodule (+60*supermodule); - return HelperMethods::getORIinSuperModule(detector, chamberside) + 60 * supermodule; // it takes readoutboard but only cares if its odd or even hence side here. + int sector = hcid / constants::NHCPERSEC; + return getORIinSuperModule(hcid) + constants::NHCPERSEC * sector; } inline static void swapByteOrder(unsigned int& word) diff --git a/Detectors/TRD/base/include/TRDBase/FeeParam.h b/Detectors/TRD/base/include/TRDBase/FeeParam.h index cf4206acdeb71..650acbc350d6d 100644 --- a/Detectors/TRD/base/include/TRDBase/FeeParam.h +++ b/Detectors/TRD/base/include/TRDBase/FeeParam.h @@ -69,9 +69,6 @@ class FeeParam static int getORI(int detector, int readoutboard); static void unpackORI(int link, int side, int& stack, int& layer, int& halfchamberside); // void createORILookUpTable(); - static int getORIinSuperModule(int detector, int readoutboard); - static int getLinkIDfromHCID(int hcid); - static int getHCIDfromORI(int ori, int readoutboard); // TODO we need more info than just ori, for now readoutboard is there ... might change // tracklet simulation bool getTracklet() const { return mTracklet; } diff --git a/Detectors/TRD/base/src/FeeParam.cxx b/Detectors/TRD/base/src/FeeParam.cxx index b25464042c4c6..1e81fd61ea015 100644 --- a/Detectors/TRD/base/src/FeeParam.cxx +++ b/Detectors/TRD/base/src/FeeParam.cxx @@ -406,34 +406,6 @@ void FeeParam::unpackORI(int link, int side, int& stack, int& layer, int& halfch } } -int FeeParam::getORI(int detector, int readoutboard) -{ - /// LOG(info) << "getORI : " << detector << " :: " << readoutboard << " -- " << getORIinSM(detector, readoutboard) << " " << getORIinSM(detector, readoutboard) + NCHAMBERPERSEC * 2 * detector; - return getORIinSuperModule(detector, readoutboard) + NCHAMBER * 2 * detector; // 60 ORI per supermodule -} - -int FeeParam::getORIinSuperModule(int detector, int readoutboard) -{ - return HelperMethods::getORIinSuperModule(detector, readoutboard); -} - -int FeeParam::getLinkIDfromHCID(int hcid) -{ - return HelperMethods::getLinkIDfromHCID(hcid); - //return a number in range [0:29] for the link related to this hcid with in its respective CRU - //lower 15 is endpoint 0 and upper 15 is endpoint 1 - //a side has 30, c side has 30 to give 60 links for a supermodule -} - -int FeeParam::getHCIDfromORI(int ori, int readoutboard) -{ - // ori = 60*SM+offset[0-29 A, 30-59 C] - // from the offset, we can derive the stack/layer/side combination giving the decector. - //TODO do we need this, currently I dont, others might? come back if need be. - // - return 1; -} - short FeeParam::chipmaskToMCMlist(unsigned int cmA, unsigned int cmB, unsigned short linkpair, int* mcmList, int listSize) { // Converts the chipmask to a list of MCMs From cd27052410e5a1e5f94c5cdd3fd64537435bee76 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Fri, 8 Jul 2022 14:23:40 +0200 Subject: [PATCH 4/5] Cleanup TRD sim to raw conversion --- .../TRD/include/DataFormatsTRD/RawData.h | 12 +- .../TRD/include/DataFormatsTRD/RawDataStats.h | 1 - DataFormats/Detectors/TRD/src/RawData.cxx | 78 +-- Detectors/TRD/reconstruction/README.md | 16 +- .../TRD/reconstruction/src/DataReader.cxx | 2 - .../reconstruction/src/TrackletsParser.cxx | 3 - .../include/TRDSimulation/Trap2CRU.h | 111 ++-- Detectors/TRD/simulation/src/Trap2CRU.cxx | 617 ++++++------------ Detectors/TRD/simulation/src/trap2raw.cxx | 13 +- .../TRD/workflow/src/TRDDigitizerSpec.cxx | 1 + 10 files changed, 289 insertions(+), 565 deletions(-) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h index c5811143c0d93..3e39d59a6acf9 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h @@ -427,8 +427,6 @@ uint32_t getlinkdatasize(const HalfCRUHeader& cruhead, const uint32_t link); uint32_t getlinkerrorflags(const HalfCRUHeader& cruheader, std::array& linkerrorflags); uint32_t getlinkdatasizes(const HalfCRUHeader& cruheader, std::array& linksizes); uint32_t getQFromRaw(const o2::trd::TrackletMCMHeader* header, const o2::trd::TrackletMCMData* data, int pidindex, int trackletindex); -uint32_t getHCIDFromTrackletHCHeader(const TrackletHCHeader& header); -uint32_t getHCIDFromTrackletHCHeader(const uint32_t& headerword); std::ostream& operator<<(std::ostream& stream, const TrackletHCHeader& halfchamberheader); std::ostream& operator<<(std::ostream& stream, const TrackletMCMHeader& mcmhead); std::ostream& operator<<(std::ostream& stream, const TrackletMCMData& tracklet); @@ -436,9 +434,6 @@ void printTrackletMCMData(o2::trd::TrackletMCMData& tracklet); void printTrackletMCMHeader(o2::trd::TrackletMCMHeader& mcmhead); void printHalfChamber(o2::trd::TrackletHCHeader& halfchamber); void dumpHalfChamber(o2::trd::TrackletHCHeader& halfchamber); -void printHalfCRUHeader(o2::trd::HalfCRUHeader& halfcru); -void dumpHalfCRUHeader(o2::trd::HalfCRUHeader& halfcru); -void clearHalfCRUHeader(o2::trd::HalfCRUHeader& halfcru); std::ostream& operator<<(std::ostream& stream, const HalfCRUHeader& halfcru); bool trackletMCMHeaderSanityCheck(o2::trd::TrackletMCMHeader& header); bool trackletHCHeaderSanityCheck(o2::trd::TrackletHCHeader& header); @@ -452,13 +447,10 @@ void printDigitHCHeader(o2::trd::DigitHCHeader& header, uint32_t headers[3]); //functions updated/checked/new for new raw reader. //above methods left for cross checking what changes have occured. -void constructTrackletHCHeader(TrackletHCHeader& header, int sector, int stack, int layer, int side, int chipclock, int format); -void constructTrackletHCHeaderd(TrackletHCHeader& header, int detector, int rob, int chipclock, int format); +void constructTrackletHCHeader(TrackletHCHeader& header, int hcid, int chipclock, int format); uint16_t constructTRDFeeID(int supermodule, int side, int endpoint); uint32_t setHalfCRUHeaderFirstWord(HalfCRUHeader& cruhead, int crurdhversion, int bunchcrossing, int stopbits, int endpoint, int eventtype, int feeid, int cruid); void setHalfCRUHeaderLinkSizeAndFlags(HalfCRUHeader& cruhead, int link, int size, int errors); -void constructTrackletMCMData(TrackletMCMData& trackletword, const int format, const uint slope, const uint pos, const uint q0, const uint q1, const uint q2); -void constructTrackletMCMData(TrackletMCMData& trackletword, const Tracklet64& tracklet); DigitMCMADCMask constructBlankADCMask(); uint32_t getHalfCRULinkInfo(const HalfCRUHeader& cruhead, const uint32_t link, const bool data); @@ -468,7 +460,6 @@ void getHalfCRULinkErrorFlags(const HalfCRUHeader& cruheader, std::array& linksizes); uint32_t getChargeFromRawHeaders(const o2::trd::TrackletHCHeader& hcheader, const o2::trd::TrackletMCMHeader* header, const std::array& data, int pidindex, int trackletindex); uint32_t getHCIDFromTrackletHCHeader(const TrackletHCHeader& header); -uint32_t getHCIDFromTrackletHCHeader(const uint32_t& headerword); std::ostream& operator<<(std::ostream& stream, const TrackletHCHeader& halfchamberheader); std::ostream& operator<<(std::ostream& stream, const TrackletMCMHeader& tracklmcmhead); std::ostream& operator<<(std::ostream& stream, const TrackletMCMData& trackletmcmdata); @@ -502,7 +493,6 @@ int getDigitHCHeaderWordType(uint32_t word); void printDigitHCHeaders(o2::trd::DigitHCHeader& header, uint32_t headers[3], int index, int offset, bool good); void printDigitHCHeader(o2::trd::DigitHCHeader& header, uint32_t headers[3]); int getNumberOfTrackletsFromHeader(o2::trd::TrackletMCMHeader* header, bool verbose = false); -void setNumberOfTrackletsInHeader(o2::trd::TrackletMCMHeader& header, int numberoftracklets); int getNextMCMADCfromBP(uint32_t& bp, int channel); inline bool isTrackletHCHeader(uint32_t& header) { return (((header >> 12) & 0x1) == 0x1); } diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h index 0b9301ee7a29a..cabd119a60a21 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawDataStats.h @@ -107,7 +107,6 @@ enum OptionBits { TRDIgnoreDigitHCHeaderBit, TRDIgnoreTrackletHCHeaderBit, TRDEnableRootOutputBit, - TRDFixSM1617Bit, TRDIgnore2StageTrigger, TRDGenerateStats, TRDM1Debug diff --git a/DataFormats/Detectors/TRD/src/RawData.cxx b/DataFormats/Detectors/TRD/src/RawData.cxx index e921ea4fd71a7..8879ce42d1931 100644 --- a/DataFormats/Detectors/TRD/src/RawData.cxx +++ b/DataFormats/Detectors/TRD/src/RawData.cxx @@ -149,8 +149,13 @@ std::ostream& operator<<(std::ostream& stream, const HalfCRUHeader& halfcru) //Tracklet HC Header -void constructTrackletHCHeader(TrackletHCHeader& header, int sector, int stack, int layer, int side, int chipclock, int format) +void constructTrackletHCHeader(TrackletHCHeader& header, int hcid, int chipclock, int format) { + int detector = hcid / 2; + int sector = (detector % (constants::NLAYER * constants::NSTACK)); + int stack = (detector % constants::NLAYER); + int layer = ((detector % (constants::NLAYER * constants::NSTACK)) / constants::NLAYER); + int side = hcid % 2; header.word = 0; header.format = format; header.supermodule = ~sector; @@ -161,27 +166,11 @@ void constructTrackletHCHeader(TrackletHCHeader& header, int sector, int stack, header.one = 1; } -void constructTrackletHCHeaderd(TrackletHCHeader& header, int detector, int rob, int chipclock, int format) -{ - int sector = (detector % (constants::NLAYER * constants::NSTACK)); - int stack = (detector % constants::NLAYER); - int layer = ((detector % (constants::NLAYER * constants::NSTACK)) / constants::NLAYER); - int side = rob % 2; - constructTrackletHCHeader(header, sector, stack, layer, side, chipclock, format); -} - uint32_t getHCIDFromTrackletHCHeader(const TrackletHCHeader& header) { return header.layer * 2 + header.stack * constants::NLAYER * 2 + header.supermodule * constants::NLAYER * constants::NSTACK * 2 + header.side; } -uint32_t getHCIDFromTrackletHCHeader(const uint32_t& headerword) -{ - TrackletHCHeader header; - header.word = headerword; - return header.layer * 2 + header.stack * constants::NLAYER * 2 + header.supermodule * constants::NLAYER * constants::NSTACK * 2 + header.side; -} - uint32_t getChargeFromRawHeaders(const o2::trd::TrackletHCHeader& hcheader, const o2::trd::TrackletMCMHeader* header, const std::array& data, int pidindex, int trackletindex) { uint32_t pid = 0; @@ -219,14 +208,14 @@ uint32_t getChargeFromRawHeaders(const o2::trd::TrackletHCHeader& hcheader, cons } lowPID = data[trackletindex].pid; //lowPID is 6 bits Q0 and 6 bits of Q1 - int pidword = (highPID << 12) + lowPID; // the entire original 20 bit pid in the trap chips + uint32_t pidword = (highPID << 12) | lowPID; // the entire original 20 bit pid in the trap chips int dynamicq = hcheader.format & 0x1; // last bit of format (lsb) defines the version of tracklet charge calculation uint32_t pidoffset = ((pidword >> 18) & 0x3); //<<6; // used for dynamic ranged charge windows, may or may not be used below. //pidword is here to make this code more readible and less error prone. switch (pidindex) { case 2: //Q2 if (!dynamicq) { - pid = (pidword >> 13) & 0x7f; // 7 bits at the top of all of pid (MSB) + pid = (pidword >> 14) & 0x3f; // 6 bits at the top of all of pid (MSB) } else { pid = (pidword >> 12) & 0x3f; // 6 bits of Q2 and a shift pid |= pidoffset << 6; @@ -235,7 +224,7 @@ uint32_t getChargeFromRawHeaders(const o2::trd::TrackletHCHeader& hcheader, cons break; case 1: //Q1 if (!dynamicq) { - pid = (pidword >> 6) & 0x7f; // 7 bits Q1 above the 6 bits of Q0 + pid = (pidword >> 7) & 0x7f; // 7 bits Q1 above the 7 bits of Q0 } else { pid = (pidword >> 6) & 0x3f; // 6 bits of Q1 and a shift pid |= pidoffset << 6; @@ -244,7 +233,7 @@ uint32_t getChargeFromRawHeaders(const o2::trd::TrackletHCHeader& hcheader, cons break; case 0: //Q0 if (!dynamicq) { - pid = pidword & 0x3f; // 6 least significant bits + pid = pidword & 0x7f; // 7 least significant bits } else { pid = pidword & 0x3f; // 6 bits of Q0 pid |= pidoffset << 6; @@ -273,28 +262,6 @@ uint16_t constructTRDFeeID(int supermodule, int side, int endpoint) return feeid.word; } -void constructTrackletMCMData(TrackletMCMData& trackletword, const int format, const uint slope, const uint pos, const uint q0, const uint q1, const uint q2) -{ - trackletword.word = 0; - // create a tracklet word as it would be sent from the FEE - // slope and position have the 8-th bit flipped each - trackletword.slope = slope ^ 0x80; - trackletword.pos = pos ^ 0x80; - trackletword.checkbit = 0; - if (format & 0x1) { - //length of q1 and q2 are 6 with a 2 bit offset sitting in the header. - trackletword.pid = (q0 & 0x3f) | ((q1 & 0x3f) << 6); - } else { - //q2 sits with upper 1 bit of q1 in the header pid word, hence the 0x3f so 6 bits of q1 are used here, shifted up above the 6 bits of q0. - trackletword.pid = (int)(q0 & 0x3f) | ((q1 & 0x3f) << 6); - } -} - -void constructTrackletMCMData(TrackletMCMData& trackletword, const Tracklet64& tracklet) -{ - constructTrackletMCMData(trackletword, tracklet.getFormat(), tracklet.getSlope(), tracklet.getPosition(), tracklet.getQ0(), tracklet.getQ1(), tracklet.getQ2()); -} - DigitMCMADCMask constructBlankADCMask() { //set the default values for the mask. @@ -303,6 +270,7 @@ DigitMCMADCMask constructBlankADCMask() mask.c = 0x1f; mask.n = 0x1; mask.j = 0xc; + mask.adcmask = 0; // actual mask will beset somewhere else, the above values are *always* that. return mask; } @@ -668,30 +636,6 @@ int getNumberOfTrackletsFromHeader(o2::trd::TrackletMCMHeader* header, bool verb return headertrackletcount; } -void setNumberOfTrackletsInHeader(o2::trd::TrackletMCMHeader& header, int numberoftracklets) -{ - //header.word |= 0xff<< (1+numberoftracklets*8); - switch (numberoftracklets) { - case 0: - LOG(error) << "tracklet header but no tracklets???"; - header.pid0 = 0xff; - header.pid1 = 0xff; - header.pid2 = 0xff; - break; - case 1: - header.pid1 = 0xff; - header.pid2 = 0xff; - break; - case 2: - header.pid2 = 0xff; - break; - case 3: - break; - default: - LOG(error) << "we have more than 3 tracklets for an mcm in " << __func__ << ". This should never happen: tracklet count=" << numberoftracklets; - } -} - int getNextMCMADCfromBP(uint32_t& bp, int channel) { //given a bitpattern (adcmask) find next channel with in the mask starting from the current channel. diff --git a/Detectors/TRD/reconstruction/README.md b/Detectors/TRD/reconstruction/README.md index be51afaa76891..e6a1007a1c976 100644 --- a/Detectors/TRD/reconstruction/README.md +++ b/Detectors/TRD/reconstruction/README.md @@ -16,12 +16,21 @@ Reconstruction is made up of different parts. There are things that run on the f - Generate raw data from montecarlo: ``` -o2-sim -n 200 -g pythia8 --skipModules ZDC -o2-sim-digitizer-workflow -b -o2-trd-trap2raw -d trddigits.root -t trdtracklets.root -l halfcru -o ./ -x -r 6 -e +o2-sim -n 200 -g pythia8pp --skipModules ZDC +o2-sim-digitizer-workflow -b --onlyDet TRD +o2-trd-trap2raw -o raw/TRD --file-per cru |& tee trdraw.log ``` + - Parse raw data : +In order to simply read the generated raw data and extract the digits and tracklets you can do the following. Remember to first rename the original digits and tracklets files in order not to overwrite them. This way you can compare afterwards that you in fact read back the same data that you have put in. + +``` +mv trddigits.root trddigitsOrig.root +mv trdtracklets.root trdtrackletsOrig.root +o2-raw-file-reader-workflow --detect-tf0 --delay 100 --max-tf 0 --input-conf raw/TRD/TRDraw.cfg | o2-trd-datareader -b | o2-trd-digittracklet-writer --run |& tee trdrec.log +``` + You will need the datadistribution installed as well which has an O2 dependency. ``` @@ -54,4 +63,3 @@ o2-dpl-raw-proxy --session default -b --dataspec "A:TRD/RAWDATA" --channel-confi ``` StfSender --id stfs --session default --transport shmem --stand-alone --input-channel-name=from-dpl --channel-config "name=from-dpl,type=pull,method=connect,address=ipc:///tmp/dpl-to-stfs,rateLogging=1,transport=shmem" ``` - diff --git a/Detectors/TRD/reconstruction/src/DataReader.cxx b/Detectors/TRD/reconstruction/src/DataReader.cxx index 8bcedf62ec837..10b589bbcffd8 100644 --- a/Detectors/TRD/reconstruction/src/DataReader.cxx +++ b/Detectors/TRD/reconstruction/src/DataReader.cxx @@ -47,7 +47,6 @@ void customize(std::vector& workflowOptions) {"halfchamberwords", VariantType::Int, 0, {"Fix half chamber for when it is version is 0.0 integer value of additional header words, ignored if version is not 0.0"}}, {"halfchambermajor", VariantType::Int, 0, {"Fix half chamber for when it is version is 0.0 integer value of major version, ignored if version is not 0.0"}}, {"ignore-digithcheader", VariantType::Bool, false, {"Ignore the digithalf chamber header for cross referencing, take rdh/cru as authorative."}}, - {"fixsm1617", VariantType::Bool, false, {"Fix the missing bit in the tracklet hc header of supermodules 16 and 17. Requires option tracklethcheader 2"}}, {"fixforoldtrigger", VariantType::Bool, false, {"Fix for the old data not having a 2 stage trigger stored in the cru header."}}, {"tracklethcheader", VariantType::Int, 2, {"Status of TrackletHalfChamberHeader 0 off always, 1 iff tracklet data, 2 on always"}}, {"histogramsfile", VariantType::String, "histos.root", {"Name of the histogram file, so one can run multiple per node"}}, @@ -100,7 +99,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) binaryoptions[o2::trd::TRDIgnoreTrackletHCHeaderBit] = cfgc.options().get("ignore-tracklethcheader"); binaryoptions[o2::trd::TRDEnableRootOutputBit] = cfgc.options().get("enable-root-output"); binaryoptions[o2::trd::TRDByteSwapBit] = cfgc.options().get("trd-datareader-enablebyteswapdata"); - //binaryoptions[o2::trd::TRDFixSM1617Bit] = cfgc.options().get("fixsm1617"); binaryoptions[o2::trd::TRDIgnore2StageTrigger] = cfgc.options().get("fixforoldtrigger"); //binaryoptions[o2::trd::TRDGenerateStats] = cfgc.options().get("generate-stats"); binaryoptions[o2::trd::TRDGenerateStats] = true; //cfgc.options().get("generate-stats"); diff --git a/Detectors/TRD/reconstruction/src/TrackletsParser.cxx b/Detectors/TRD/reconstruction/src/TrackletsParser.cxx index 6ad54711fbf14..ffc27636a4858 100644 --- a/Detectors/TRD/reconstruction/src/TrackletsParser.cxx +++ b/Detectors/TRD/reconstruction/src/TrackletsParser.cxx @@ -226,9 +226,6 @@ int TrackletsParser::Parse() a.word = *word; printTrackletHCHeader(a); } - if ((mFEEID.supermodule > 15) && mOptions[TRDFixSM1617Bit] && mTrackletHCHeaderState == 2) { - *word |= 1 << 12; //flip bit twelth bit for the tracklethcheader for the last 2 supermodules (bug/misconfiguration/broken/other) not sure why its like this yet, but it is. - } //LOG(info) << "mFEEID : 0x"<< std::hex << mFEEID.word << " supermodule : 0x" << (int)mFEEID.supermodule << " tracklethcheader : 0x" << *word; } //now for Tracklet hc header diff --git a/Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h b/Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h index 5d3bfdd87287e..25052502f0dbd 100644 --- a/Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h +++ b/Detectors/TRD/simulation/include/TRDSimulation/Trap2CRU.h @@ -12,8 +12,8 @@ /////////////////////////////////////////////////////////////////////////////// // // // TRD Trap2CRU class // -// Class to take the trap output that arrives at the cru and produce // -// the cru output. I suppose a cru simulator // +// Convert simulated digits and tracklets into a CRU data stream // +// // /////////////////////////////////////////////////////////////////////////////// #ifndef ALICE_O2_TRD_TRAP2CRU_H @@ -25,7 +25,7 @@ #include "DataFormatsTRD/RawData.h" #include "DataFormatsTRD/Tracklet64.h" #include "DataFormatsTRD/Digit.h" -//#include "DetectorsRaw/HBFUtils.h" +#include "DataFormatsTRD/Constants.h" #include "DetectorsRaw/RawFileWriter.h" namespace o2 @@ -38,87 +38,80 @@ class Trap2CRU public: Trap2CRU() = default; Trap2CRU(const std::string& outputDir, const std::string& inputDigitsFilename, const std::string& inputTrackletsFilename); - //Trap2CRU(const std::string& outputDir, const std::string& inputFilename, const std::string& inputDigitsFilename, const std::string& inputTrackletsFilename); + + // entry point for processing, is called from trap2raw.cxx void readTrapData(); + + // sort digits and tracklets by link ID + void sortDataToLinks(); + + // open digits and tracklets files for reading + void openInputFiles(); + + // main processing function, called for every TRD trigger and creates the raw data stream for each half CRU void convertTrapData(o2::trd::TriggerRecord const& trigrecord, const int& triggercount); - // default for now will be file per half cru as per the files Guido did for us. + + // settings void setFilePer(std::string fileper) { mFilePer = fileper; }; - std::string getFilePer() { return mFilePer; }; void setOutputDir(std::string outdir) { mOutputDir = outdir; }; - std::string getOutputDir() { return mOutputDir; }; - void setDigitRate(int digitrate) { mDigitRate = digitrate; }; - int getDigitRate() { return mDigitRate; }; - int getVerbosity() { return mVerbosity; } void setVerbosity(int verbosity) { mVerbosity = verbosity; } - void sortDataToLinks(); - o2::raw::RawFileWriter& getWriter() { return mWriter; } - uint32_t buildHalfCRUHeader(HalfCRUHeader& header, const uint32_t bc, const uint32_t halfcru); // build the half cru header holding the lengths of all links amongst other things. - void linkSizePadding(uint32_t linksize, uint32_t& crudatasize, uint32_t& padding); // pad the link data stream to align with 256 bit words. - void openInputFiles(); void setTrackletHCHeader(int tracklethcheader) { mUseTrackletHCHeader = tracklethcheader; } - bool isTrackletOnLink(int link, int trackletpos); // is the current tracklet on the the current link - bool isDigitOnLink(int link, int digitpos); // is the current digit on the current link - int buildDigitRawData(const int digitstartindex, const int digitendindex, const int mcm, const int rob, const uint32_t triggercount); - int buildTrackletRawData(const int trackletindex, const int linkid); // from the current position in the tracklet vector, build the outgoing data for the current mcm the tracklet is on. - int writeDigitEndMarker(); // write the digit end marker 0x0 0x0 - int writeTrackletEndMarker(); // write the tracklet end maker 0x10001000 0x10001000 - int writeDigitHCHeader(const int eventcount, uint32_t linkid); // write the Digit HalfChamberHeader into the stream, after the tracklet endmarker and before the digits. - int writeTrackletHCHeader(const int eventcount); // write the Tracklet HalfChamberHeader into the stream, at the beginning of data iff there is tracklet data. - bool digitindexcompare(const o2::trd::Digit& A, const o2::trd::Digit& B); - //boohhl digitindexcompare(const unsigned int A, const unsigned int B); - o2::trd::Digit& getDigitAt(const int i) { return mDigits[mDigitsIndex[i]]; }; + // make the writer available in trap2raw.cxx for configuration + o2::raw::RawFileWriter& getWriter() { return mWriter; } + // build the half cru header holding the lengths of all links amongst other things. + uint32_t buildHalfCRUHeader(HalfCRUHeader& header, const uint32_t bc, const uint32_t halfcru); - void mergetriggerDigitRanges(); + // write digits for single MCM into raw stream (include DigitMCMHeader and ADC mask) + int buildDigitRawData(const int digitstartindex, const int digitendindex, const int mcm, const int rob, const uint32_t triggercount); + // write tracklets for single MCM into raw stream (includes TrackletMCMHeader) + int buildTrackletRawData(int trackletIndexStart); + // write two digit end markers + void writeDigitEndMarkers(); + // write two tracklet end markers + void writeTrackletEndMarkers(); + // write digit HC header (two headers are written) + void writeDigitHCHeaders(const int eventcount, uint32_t hcId); + // write tracklet HC header + void writeTrackletHCHeader(int hcid, int eventcount); private: - int mfileGranularity; /// per link or per half cru for each file - uint8_t mLinkID; // always 15 for TRD - uint16_t mCruID; // built into the FeeID - uint16_t mFeeID; // front end id defining the cru sm:8 bits, blank 3 bits, side:1,blank 3 bits, end point:1 - uint8_t mEndPointID; // end point on the cru in question, there are 2 pci end points per cru + uint8_t mLinkID{constants::TRDLINKID}; // always 15 for TRD + uint16_t mCruID{0}; // built into the FeeID + uint16_t mFeeID{0}; // front end id defining the cru sm:8 bits, blank 3 bits, side:1,blank 3 bits, end point:1 + uint8_t mEndPointID{0}; // end point on the cru in question, there are 2 pci end points per cru + + // settings std::string mFilePer; // how to split up the raw data files, sm:per supermodule, halfcru: per half cru, cru: per cru, all: singular file. - // std::string mInputFileName; - std::string mOutputFileName; - int mVerbosity{0}; + int mVerbosity{0}; // currently only 2 levels: 0 - OFF, 1 - verbose output std::string mOutputDir; - uint32_t mSuperPageSizeInB; - int mDigitRate = 1000; - int mEventDigitCount = 0; - //HalfCRUHeader mHalfCRUHeader; - //TrackletMCMHeader mTrackletMCMHeader; - // TrackletMCMData mTrackletMCMData; - int mUseTrackletHCHeader{0}; - std::vector mRawData; // store for building data event for a single half cru - uint32_t mRawDataPos = 0; - char* mRawDataPtr{nullptr}; - // locations to store the incoming data branches - - // incoming digit information + int mUseTrackletHCHeader{0}; // 0 - don't write header, 1 - write header if tracklets available, 2 - always write header + + // input + // digits std::string mInputDigitsFileName; TFile* mDigitsFile; TTree* mDigitsTree; std::vector mDigits, *mDigitsPtr = &mDigits; - std::vector mDigitsIndex; - std::vector mDigitTriggerRecords; - std::vector* mDigitTriggerRecordsPtr = &mDigitTriggerRecords; - - //incoming tracklet information + // tracklets and trigger records std::string mInputTrackletsFileName; TFile* mTrackletsFile; TTree* mTrackletsTree; - std::vector mTracklets; - std::vector* mTrackletsPtr = &mTracklets; - std::vector mTrackletsIndex; - std::vector mTrackletTriggerRecords; - std::vector* mTrackletTriggerRecordsPtr = &mTrackletTriggerRecords; + std::vector mTracklets, *mTrackletsPtr{&mTracklets}; + std::vector mTrackletTriggerRecords, *mTrackletTriggerRecordsPtr{&mTrackletTriggerRecords}; + + // helpers + std::vector mDigitsIndex; // input digits are sorted using this index array + char* mRawDataPtr{nullptr}; // points to the current position in the raw data where we are writing uint64_t mCurrentTracklet{0}; //the tracklet we are currently busy adding uint64_t mCurrentDigit{0}; //the digit we are currently busy adding + uint64_t mTotalTrackletsWritten{0}; // count the total number of tracklets written to the raw data + uint64_t mTotalDigitsWritten{0}; // count the total number of digits written to the raw data const o2::raw::HBFUtils& mSampler = o2::raw::HBFUtils::Instance(); o2::raw::RawFileWriter mWriter{"TRD"}; - ClassDefNV(Trap2CRU, 3); + ClassDefNV(Trap2CRU, 4); }; } // end namespace trd diff --git a/Detectors/TRD/simulation/src/Trap2CRU.cxx b/Detectors/TRD/simulation/src/Trap2CRU.cxx index 1eced07fa54bb..34e6d523c68ee 100644 --- a/Detectors/TRD/simulation/src/Trap2CRU.cxx +++ b/Detectors/TRD/simulation/src/Trap2CRU.cxx @@ -61,7 +61,7 @@ struct TRDCRUMapping { //this should probably come from ccdb or some authoritive source. //I doubt this is going to change very often, but ... famous last words. // -const TRDCRUMapping trdHWMap[o2::trd::constants::NHALFCRU / 2] = +const TRDCRUMapping trdHWMap[constants::NHALFCRU / 2] = { {166, 250, 0}, {166, 583, 0}, @@ -103,7 +103,6 @@ const TRDCRUMapping trdHWMap[o2::trd::constants::NHALFCRU / 2] = Trap2CRU::Trap2CRU(const std::string& outputDir, const std::string& inputdigitsfilename, const std::string& inputtrackletsfilename) { mOutputDir = outputDir; - mSuperPageSizeInB = 1024 * 1024; mInputDigitsFileName = inputdigitsfilename; mInputTrackletsFileName = inputtrackletsfilename; mCurrentDigit = 0; @@ -115,8 +114,7 @@ void Trap2CRU::openInputFiles() mDigitsFile = TFile::Open(mInputDigitsFileName.data()); if (mDigitsFile != nullptr && !mDigitsFile->IsZombie()) { mDigitsTree = (TTree*)mDigitsFile->Get("o2sim"); - mDigitsTree->SetBranchAddress("TRDDigit", &mDigitsPtr); // the branch with the actual digits - mDigitsTree->SetBranchAddress("TriggerRecord", &mDigitTriggerRecordsPtr); // branch with trigger records for digits + mDigitsTree->SetBranchAddress("TRDDigit", &mDigitsPtr); // the branch with the actual digits } else { LOG(warn) << " cant open file containing digit tree"; } @@ -166,8 +164,8 @@ void Trap2CRU::sortDataToLinks() } std::stable_sort(mDigitsIndex.begin() + trig.getFirstDigit(), mDigitsIndex.begin() + trig.getNumberOfDigits() + trig.getFirstDigit(), [this](const uint32_t i, const uint32_t j) { - int link1=HelperMethods::getLinkIDfromHCID(mDigits[i].getDetector() * 2 + (mDigits[i].getROB() % 2)); - int link2=HelperMethods::getLinkIDfromHCID(mDigits[j].getDetector() * 2 + (mDigits[j].getROB() % 2)); + int link1=HelperMethods::getLinkIDfromHCID(mDigits[i].getHCId()); + int link2=HelperMethods::getLinkIDfromHCID(mDigits[j].getHCId()); if(link1!=link2){return link1 duration = std::chrono::high_resolution_clock::now() - sortstart; if (mVerbosity) { + std::chrono::duration duration = std::chrono::high_resolution_clock::now() - sortstart; LOG(info) << "TRD Digit/Tracklet Sorting took " << duration.count() << " s"; int triggercount = 0; for (auto& trig : mTrackletTriggerRecords) { - LOG(info) << "Trigger: " << triggercount << " with T" << trig.getBCData().asString(); + LOG(info) << "Trigger: " << triggercount << " with T " << trig.getBCData().asString(); LOG(info) << "Tracklets from:" << trig.getFirstTracklet() << " with " << trig.getNumberOfTracklets(); LOG(info) << "Digits from:" << trig.getFirstDigit() << " with " << trig.getNumberOfDigits(); if (trig.getNumberOfTracklets() > 0) { @@ -218,30 +216,10 @@ void Trap2CRU::sortDataToLinks() } // if verbose } -void Trap2CRU::mergetriggerDigitRanges() -{ - // pass through the digit ranges of the incoming tracklet triggers. - // this most handles the old data. - // trapsim should now be sending out the trigger with both information. - bool fixdigitinfo = false; - for (auto trig : mTrackletTriggerRecords) { - if (trig.getNumberOfDigits() == 0) { - fixdigitinfo = true; - } - } - if (fixdigitinfo) { - int counter = 0; - for (auto trig : mTrackletTriggerRecords) { - trig.setDigitRange(mDigitTriggerRecords[counter].getFirstDigit(), mDigitTriggerRecords[counter].getNumberOfDigits()); - } - } -} - void Trap2CRU::readTrapData() { - //set things up, read the file and then deligate to convertTrapdata to do the conversion. + // set things up, read the file and then deligate to convertTrapdata to do the conversion. // - mRawData.reserve(1024 * 1024); //TODO take out the hardcoded 1MB its supposed to come in from the options if (mVerbosity) { LOG(info) << "Trap2CRU::readTrapData"; } @@ -255,7 +233,7 @@ void Trap2CRU::readTrapData() prefix += '/'; } - for (int link = 0; link < o2::trd::constants::NHALFCRU; link++) { + for (int link = 0; link < constants::NHALFCRU; link++) { // FeeID *was* 0xFEED, now is indicates the cru Supermodule, side (A/C) and endpoint. See RawData.cxx for details. int supermodule = link / 4; int endpoint = link % 2; @@ -265,7 +243,6 @@ void Trap2CRU::readTrapData() LOG(info) << "FEEID;" << std::hex << mFeeID; mCruID = link / 2; mEndPointID = endpoint; - mLinkID = o2::trd::constants::TRDLINKID; std::string outFileLink; std::string outPrefix = "TRD_"; @@ -283,16 +260,13 @@ void Trap2CRU::readTrapData() std::string supermodule = ss.str(); outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, "_sm_", supermodule, outSuffix); } else if (mFilePer == "cru") { - outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, std::to_string(flpid), "_cru", std::to_string(cruhwid), "_", std::to_string(mEndPointID), outSuffix); + outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, std::to_string(flpid), "_cru", std::to_string(cruhwid), outSuffix); } else if (mFilePer == "halfcru") { outFileLink = o2::utils::Str::concat_string(mOutputDir, "/", outPrefix, std::to_string(flpid), "_cru", std::to_string(cruhwid), "_", std::to_string(mEndPointID), outSuffix); } else { throw std::runtime_error("invalid option provided for file grouping"); } - - //std::string outputFilelink = o2::utils::Str::concat_string(prefix, "trd_cru_", std::to_string(mCruID), "_", trdside, "_", whichrun, ".raw"); LOG(info) << "registering links"; - mWriter.registerLink(mFeeID, mCruID, mLinkID, mEndPointID, outFileLink); } @@ -301,65 +275,33 @@ void Trap2CRU::readTrapData() if (mTrackletsTree->GetEntries() != mDigitsTree->GetEntries()) { LOG(fatal) << "Entry counts in mTrackletsTree and Digits Tree dont match " << mTrackletsTree->GetEntries() << "!=" << mDigitsTree->GetEntries(); } - uint32_t totaltracklets = 0; - uint32_t totaldigits = 0; + int nTrackletsTotal = 0; + int nDigitsTotal = 0; + int nTriggerRecordsTotal = 0; int triggercount = 42; // triggercount is here so that we can span timeframes. The actual number is of no consequence,but must increase. for (int entry = 0; entry < mTrackletsTree->GetEntries(); entry++) { mTrackletsTree->GetEntry(entry); mDigitsTree->GetEntry(entry); - totaltracklets += mTracklets.size(); - totaldigits += mDigits.size(); - //migrate digit trigger information into the tracklettrigger (historical) + nTrackletsTotal += mTracklets.size(); + nDigitsTotal += mDigits.size(); + nTriggerRecordsTotal += mTrackletTriggerRecords.size(); sortDataToLinks(); // each entry is a timeframe uint32_t linkcount = 0; for (auto tracklettrigger : mTrackletTriggerRecords) { convertTrapData(tracklettrigger, triggercount); // tracklettrigger assumed to be authoritive triggercount++; - mEventDigitCount++; - } - } - LOG(info) << " Total digits : " << totaldigits; - LOG(info) << " Total tracklets : " << totaltracklets; -} - -void Trap2CRU::linkSizePadding(uint32_t linksize, uint32_t& crudatasize, uint32_t& padding) -{ - - // if zero the whole 256 bit must be padded (empty link) - // crudatasize is the size to be stored in the cruheader, i.e. units of 256bits. - // linksize is the incoming link size from the linkrecord, - // padding is of course the amount of padding in 32bit words. - uint32_t rem = 0; - if (linksize != 0) { - //data, so figure out padding cru word, the other case is simple, full padding if size=0 - rem = linksize % 8; - if (rem != 0) { - crudatasize = linksize / 8 + 1; - padding = 8 - rem; - } else { - - crudatasize = linksize / 8; // 32 bit word to 256 bit word. - padding = 0; - } - if (mVerbosity) { - LOG(info) << "We have data with linkdatasize=" << linksize << " with size number in header of:" << crudatasize << " padded with " << padding << " 32bit words"; - } - } else { - //linksize is zero so no data, pad fully. - crudatasize = 1; - padding = 8; - if (mVerbosity) { - LOG(info) << "We have data with linkdatasize=" << linksize << " with size number in header of:" << crudatasize << " padded with " << padding << " 32bit words"; } } + LOGF(info, "In the input files there were %u tracklets and %u digits in %u trigger records", nTrackletsTotal, nDigitsTotal, nTriggerRecordsTotal); + LOGF(info, "Wrote %lu tracklets and %lu digits into the raw data", mTotalTrackletsWritten, mTotalDigitsWritten); } uint32_t Trap2CRU::buildHalfCRUHeader(HalfCRUHeader& header, const uint32_t bc, const uint32_t halfcru) { int bunchcrossing = bc; int stopbits = 0x01; // do we care about this and eventtype in simulations? - int eventtype = o2::trd::constants::ETYPECALIBRATIONTRIGGER; + int eventtype = constants::ETYPECALIBRATIONTRIGGER; int crurdhversion = 6; int feeid = 0; int cruid = 0; @@ -374,33 +316,6 @@ uint32_t Trap2CRU::buildHalfCRUHeader(HalfCRUHeader& header, const uint32_t bc, return 1; } -bool Trap2CRU::isTrackletOnLink(const int linkid, const int currenttrackletpos) -{ - //hcid is simply the halfcru*15+linkid - if (currenttrackletpos == mTracklets.size()) { - return false; - } - int link = HelperMethods::getLinkIDfromHCID(mTracklets[currenttrackletpos].getHCID()); - if (linkid == link) { - // this tracklet is on this link. - return true; - } - return false; -} - -bool Trap2CRU::isDigitOnLink(const int linkid, const int currentdigitpos) -{ - if (currentdigitpos >= mDigits.size()) { - return false; - } - Digit* digit = &mDigits[mDigitsIndex[currentdigitpos]]; - int link = HelperMethods::getLinkIDfromHCID(digit->getDetector() * 2 + (digit->getROB() % 2)); - if (link == linkid) { - return true; - } - return false; -} - int Trap2CRU::buildDigitRawData(const int digitstartindex, const int digitendindex, const int mcm, const int rob, const uint32_t triggerrecordcount) { //this is not zero suppressed. @@ -408,17 +323,11 @@ int Trap2CRU::buildDigitRawData(const int digitstartindex, const int digitendind int digitswritten = 0; // Digit DigitMCMHeader header; + DigitMCMADCMask adcmask; DigitMCMData data; - int startdet = mDigits[mDigitsIndex[digitstartindex]].getDetector(); - int startrob = mDigits[mDigitsIndex[digitstartindex]].getROB(); - int startmcm = mDigits[mDigitsIndex[digitstartindex]].getMCM(); - if (startrob != rob && startmcm != mcm) { - LOG(error) << "buildDigitRawData but startmcm and rob are not correct : " << startrob << "!=" << rob << " and mcm: " << startmcm << "!=" << mcm; - } - int digitcounter = 0; header.res = 0xc; //1100 - header.mcm = startmcm; - header.rob = startrob; + header.mcm = mcm; + header.rob = rob; header.yearflag = 1; // >10.2007 header.eventcount = triggerrecordcount; memcpy(mRawDataPtr, (char*)&header, sizeof(DigitMCMHeader)); // uint32 -- 4 bytes. @@ -426,8 +335,7 @@ int Trap2CRU::buildDigitRawData(const int digitstartindex, const int digitendind //LOG(info) << "Digt Header word: 0x" << std::hex << headerptr->word; mRawDataPtr += 4; digitwordswritten++; - //we are writing zero suppressed so - DigitMCMADCMask adcmask; + // we are writing zero suppressed so we need adcmask adcmask = constructBlankADCMask(); memcpy(mRawDataPtr, (char*)&adcmask, sizeof(DigitMCMADCMask)); DigitMCMADCMask* adcmaskptr = (DigitMCMADCMask*)mRawDataPtr; @@ -437,17 +345,10 @@ int Trap2CRU::buildDigitRawData(const int digitstartindex, const int digitendind for (int digitindex = digitstartindex; digitindex < digitendindex; ++digitindex) { Digit* d = &mDigits[mDigitsIndex[digitindex]]; ArrayADC adcdata = d->getADC(); - //write these 2 now as we only have it now. - if (startmcm != d->getMCM()) { - LOG(error) << " we are on the wrong mcm:" << startmcm << "!=" << d->getMCM(); - } - if (startrob != d->getROB()) { - LOG(error) << " we are on the wrong rob:" << startrob << "!=" << d->getROB(); - } int channel = d->getChannel(); //set adcmask for the channel we currently have. incrementADCMask(*adcmaskptr, channel); //adcmaskptr->adcmask |= 1UL << channel; - for (int timebin = 0; timebin < o2::trd::constants::TIMEBINS; timebin += 3) { + for (int timebin = 0; timebin < constants::TIMEBINS; timebin += 3) { data.z = adcdata[timebin]; data.y = adcdata[timebin + 1]; data.x = adcdata[timebin + 2]; @@ -459,14 +360,13 @@ int Trap2CRU::buildDigitRawData(const int digitstartindex, const int digitendind if (mVerbosity) { LOG(info) << "DDDD " << d->getDetector() << ":" << d->getROB() << ":" << d->getMCM() << ":" << d->getChannel() << ":" << d->getADCsum() << ":" << d->getADC()[0] << ":" << d->getADC()[1] << ":" << d->getADC()[2] << "::" << d->getADC()[27] << ":" << d->getADC()[28] << ":" << d->getADC()[29]; } - if (d->getMCM() != startmcm) { - LOG(fatal) << "digit getmcm = " << d->getMCM() << " while startmcm=" << startmcm; - } digitswritten++; } + // sanityCheckDigitMCMADCMask(*adcmaskptr, digitswritten); if (digitswritten != digitendindex - digitstartindex) { LOG(error) << " something wrong the number of digitswritten does not correspond to the the loop count"; } + mTotalDigitsWritten += digitswritten; if (digitwordswritten != (digitswritten * 10 + 2)) { LOG(error) << "something wrong with writing the digits the following should be equal " << digitwordswritten << "==" << (digitswritten * 10 + 2) << " with digitswritten=" << digitswritten; LOG(error) << "digit start index distance to digit end index :" << digitendindex - digitstartindex; @@ -474,162 +374,132 @@ int Trap2CRU::buildDigitRawData(const int digitstartindex, const int digitendind return digitwordswritten; } -int Trap2CRU::buildTrackletRawData(const int trackletindex, const int linkid) +int Trap2CRU::buildTrackletRawData(int trackletIndexStart) { - TrackletMCMHeader header; - bool destroytracklets = false; - std::array trackletdata; + int hcid = mTracklets[trackletIndexStart].getHCID(); + TrackletMCMHeader header; // header with common tracklet information and upper 8 bit of PID information for each tracklet + std::array tracklets; // the up to three tracklet words - header.col = mTracklets[trackletindex].getColumn(); - header.padrow = mTracklets[trackletindex].getPadRow(); + header.col = mTracklets[trackletIndexStart].getColumn(); + header.padrow = mTracklets[trackletIndexStart].getPadRow(); header.onea = 1; header.oneb = 1; header.pid0 = 0xff; header.pid1 = 0xff; header.pid2 = 0xff; - unsigned int trackletcounter = 0; - if (mVerbosity) { - LOG(info) << "After instantiation header is : 0x" << header.word << " " << header << " Trackletindex:" << trackletindex << " max tracklet:" << mTracklets.size(); - LOG(info) << "mTracklet:" << mCurrentTracklet << " ==?? trackletindex" << trackletindex << " max tracklet:" << mTracklets.size(); - } - while (linkid == HelperMethods::getLinkIDfromHCID(mTracklets[trackletindex + trackletcounter].getHCID()) && header.col == mTracklets[trackletindex + trackletcounter].getColumn() && header.padrow == mTracklets[trackletindex + trackletcounter].getPadRow()) { - int trackletoffset = trackletindex + trackletcounter; - constructTrackletMCMData(trackletdata[trackletcounter], mTracklets[trackletoffset]); - unsigned int headerqpart = ((mTracklets[trackletoffset].getQ2() & 0x7f) << 1) + ((mTracklets[trackletoffset].getQ1() >> 6) & 0x3); - //all 6 bits of Q1 and 2 upper bits of 7bit Q1 - if (mVerbosity) { - if (mTracklets[trackletoffset].getQ2() > 0x3f) { - LOGP(warning, "Tracklet Q2 out of range for raw data {0:#x}", mTracklets[trackletoffset].getQ2()); - } - if (mTracklets[trackletoffset].getQ1() > 0x7f) { - LOGP(warning, "Tracklet Q1 out of range for raw data {0:#x}", mTracklets[trackletoffset].getQ1()); + int iCurrTracklet = 0; + + while (hcid == mTracklets[trackletIndexStart + iCurrTracklet].getHCID() && + header.col == mTracklets[trackletIndexStart + iCurrTracklet].getColumn() && + header.padrow == mTracklets[trackletIndexStart + iCurrTracklet].getPadRow()) { // we are still on the same MCM + int trackletIndex = trackletIndexStart + iCurrTracklet; + auto& trackletData = tracklets[iCurrTracklet]; + trackletData.word = 0; + // slope and position have the 8-th bit flipped each + trackletData.slope = mTracklets[trackletIndex].getSlope() ^ 0x80; + trackletData.pos = mTracklets[trackletIndex].getPosition() ^ 0x80; + trackletData.checkbit = 0; + int pidHeader = 0; + bool qDynamicRange = mTracklets[trackletIndex].getFormat() & 0x1; + if (qDynamicRange) { + // Dynamic charge range, the tracklet PID contains all 6 bits of q0 and q1 + // TODO add scaling factor + LOG(warning) << "Trying to add PID information for dynamic charge range, which is not yet verified"; + trackletData.pid = ((mTracklets[trackletIndex].getQ1() & 0x3f) << 6) | (mTracklets[trackletIndex].getQ0() & 0x3f); + pidHeader = mTracklets[trackletIndex].getQ2() & 0x3f; + } else { + // Fixed charge range, the tracklet PID contains all 7 bits of q0 and 5 out of 7 bits for q1 + trackletData.pid = ((mTracklets[trackletIndex].getQ1() & 0x1f) << 7) | (mTracklets[trackletIndex].getQ0() & 0x7f); + pidHeader = ((mTracklets[trackletIndex].getQ2() & 0x3f) << 2) | ((mTracklets[trackletIndex].getQ1() >> 5) & 0x3); + } + if (iCurrTracklet == 0) { + header.pid0 = pidHeader; + } else if (iCurrTracklet == 1) { + header.pid1 = pidHeader; + if (header.pid0 == 0xff) { + LOG(error) << "Adding PID info for second tracklet, but first is marked as not available"; } - if (mTracklets[trackletoffset].getQ0() > 0x7f) { - LOGP(warning, "Tracklet Q0 out of range for raw data {0:#x}", mTracklets[trackletoffset].getQ0()); + } else if (iCurrTracklet == 2) { + header.pid2 = pidHeader; + if (header.pid1 == 0xff || header.pid0 == 0xff) { + LOG(error) << "Adding PID info for third tracklet, but first or second is marked as not available"; } + } else { + LOG(fatal) << "Cannot have more than 3 tracklets for single trigger and single MCM"; } - switch (trackletcounter) { - case 0: - header.pid0 = headerqpart; - break; - case 1: - header.pid1 = headerqpart; - if (header.pid0 == 0xff) { - LOG(warn) << "we are setting pid1 but pid0 is not set, a second tracklet but no first one?"; - } - break; - case 2: - header.pid2 = headerqpart; - if (header.pid1 == 0xff || header.pid0 == 0xff) { - LOG(warn) << "we are setting pid2 but pid0/1 is not set, a second tracklet but no first one?" << header.pid0 << " " << header.pid1; - } - break; - default: - LOG(warn) << ">3 tracklets when building the Tracklet raw data stream for hcid=" << mTracklets[trackletindex + trackletcounter].getHCID() << " col:" << mTracklets[trackletindex + trackletcounter].getColumn() << " padrow:" << mTracklets[trackletindex + trackletcounter].getPadRow(); - destroytracklets = true; - break; - } - trackletcounter++; - if (trackletcounter + trackletindex >= mTracklets.size()) { + iCurrTracklet++; + if (trackletIndexStart + iCurrTracklet >= mTracklets.size()) { break; } } - //now copy the mcmheader and mcmdata. - if (!destroytracklets) { - setNumberOfTrackletsInHeader(header, trackletcounter); - if (trackletcounter > 0) { // dont write header if there are no tracklets. - if (mVerbosity) { - LOG(info) << " TTT TrackletMCMHeader : 0x" << std::hex << header << " pid : " << header.pid0 << " pid1: " << header.pid1; - printTrackletMCMHeader(header); - } - memcpy((char*)mRawDataPtr, (char*)&header, sizeof(TrackletMCMHeader)); - mRawDataPtr += sizeof(TrackletMCMHeader); - for (int i = 0; i < trackletcounter; ++i) { - if (mVerbosity) { - LOG(info) << " TTTx TrackletMCMData : 0x" << std::hex << trackletdata[i]; - printTrackletMCMData(trackletdata[i]); - } - memcpy((char*)mRawDataPtr, (char*)&trackletdata[i], sizeof(TrackletMCMData)); - mRawDataPtr += sizeof(TrackletMCMData); - } + // MCM header and MCM data are assembled, write it now + if (iCurrTracklet == 0) { + LOG(fatal) << "Not writing any tracklet. This cannot happen, there must be at least one or this function would not be called"; + } + if (mVerbosity) { + printTrackletMCMHeader(header); + } + memcpy((char*)mRawDataPtr, (char*)&header, sizeof(TrackletMCMHeader)); + mRawDataPtr += sizeof(TrackletMCMHeader); + for (int i = 0; i < iCurrTracklet; ++i) { + if (mVerbosity) { + printTrackletMCMData(tracklets[i]); } - } else { - LOG(warn) << "something wrong with these tracklets, there are too many. You might want to take a closer look. Rejecting for now, and moving on."; + memcpy((char*)mRawDataPtr, (char*)&tracklets[i], sizeof(TrackletMCMData)); + mRawDataPtr += sizeof(TrackletMCMData); } - return trackletcounter; + return iCurrTracklet; } -int Trap2CRU::writeDigitEndMarker() +void Trap2CRU::writeDigitEndMarkers() { - int wordswritten = 0; + // append 0x00000000 0x00000000 uint32_t digitendmarker = 0; - memcpy(mRawDataPtr, (char*)&digitendmarker, 4); mRawDataPtr += 4; - wordswritten++; memcpy(mRawDataPtr, (char*)&digitendmarker, 4); mRawDataPtr += 4; - wordswritten++; - - return wordswritten; } -int Trap2CRU::writeTrackletEndMarker() +void Trap2CRU::writeTrackletEndMarkers() { - int wordswritten = 0; - uint32_t trackletendmarker = 0x10001000; - + // append 0x10001000 0x10001000 + uint32_t trackletendmarker = constants::TRACKLETENDMARKER; memcpy(mRawDataPtr, (char*)&trackletendmarker, 4); mRawDataPtr += 4; - wordswritten++; memcpy(mRawDataPtr, (char*)&trackletendmarker, 4); mRawDataPtr += 4; - wordswritten++; - return wordswritten; } -int Trap2CRU::writeTrackletHCHeader(const int eventcount) +void Trap2CRU::writeTrackletHCHeader(int hcid, int eventcount) { - int wordswritten = 0; - //from linkid we can get supermodule, stack, layer, side - int hcid = mTracklets[mCurrentTracklet].getHCID(); - int detector = mTracklets[mCurrentTracklet].getHCID() / 2; - TrackletHCHeader tracklethcheader; - unsigned int supermodule = hcid / 60; - unsigned int stack = (detector % (o2::trd::constants::NLAYER * o2::trd::constants::NSTACK)) / o2::trd::constants::NLAYER; - unsigned int layer = (detector % o2::trd::constants::NLAYER); - unsigned int side = (hcid % 2) ? 1 : 0; + // from linkid we can get supermodule, stack, layer, side unsigned int chipclock = eventcount * 42; // just has to be a constant increasing number per event for our purposes in sim to raw. unsigned int format = 12; - constructTrackletHCHeader(tracklethcheader, supermodule, stack, layer, side, chipclock, format); + TrackletHCHeader tracklethcheader; + constructTrackletHCHeader(tracklethcheader, hcid, chipclock, format); if (mVerbosity) { printTrackletHCHeader(tracklethcheader); } - if (mUseTrackletHCHeader) { // run 3 we also have a TrackletHalfChamber. - memcpy(mRawDataPtr, (char*)&tracklethcheader, sizeof(TrackletHCHeader)); - if (mVerbosity) { - LOG(info) << "writing tracklethcheader of 0x" << std::hex << tracklethcheader.word; - } - mRawDataPtr += 4; - wordswritten++; + memcpy(mRawDataPtr, (char*)&tracklethcheader, sizeof(TrackletHCHeader)); + if (mVerbosity) { + LOG(info) << "writing tracklethcheader of 0x" << std::hex << tracklethcheader.word; } - return wordswritten; + mRawDataPtr += 4; } -int Trap2CRU::writeDigitHCHeader(const int eventcount, const uint32_t linkid) +void Trap2CRU::writeDigitHCHeaders(const int eventcount, const uint32_t hcId) { - // we have 2 HCHeaders defined Tracklet and Digit in Rawdata.h - int wordswritten = 0; - //from linkid we can get supermodule, stack, layer, side - int detector = linkid / 2; - + // The detector can in theory send up to 8 HCHeaders, but it will always send at least 2. + // Here, we always only send those two headers + int detector = hcId / 2; DigitHCHeader digitheader; DigitHCHeader1 digitheader1; digitheader.res = 1; - digitheader.side = (linkid % 2) ? 1 : 0; - digitheader.stack = (detector % (o2::trd::constants::NLAYER * o2::trd::constants::NSTACK)) / o2::trd::constants::NLAYER; - digitheader.layer = (detector % o2::trd::constants::NLAYER); - digitheader.supermodule = linkid / 60; + digitheader.side = (hcId % 2) ? 1 : 0; + digitheader.stack = HelperMethods::getStack(detector); + digitheader.layer = HelperMethods::getLayer(detector); + digitheader.supermodule = HelperMethods::getSector(detector); digitheader.numberHCW = 1; // number of additional words in th header, we are using 2 header words so 1 here. digitheader.minor = 42; // my (shtm) version, not used digitheader.major = 0x21; // zero suppressed and 0x1 to comply with what we see in the raw data @@ -638,42 +508,46 @@ int Trap2CRU::writeDigitHCHeader(const int eventcount, const uint32_t linkid) digitheader1.ptrigcount = 1; digitheader1.ptrigphase = 1; digitheader1.bunchcrossing = eventcount; //NB this is not the same as the bunchcrossing the rdh. See RawData.h for explanation - digitheader1.numtimebins = 30; + digitheader1.numtimebins = constants::TIMEBINS; memcpy(mRawDataPtr, (char*)&digitheader, sizeof(DigitHCHeader)); // 8 because we are only using the first 2 32bit words of the header, the rest are optional. mRawDataPtr += sizeof(DigitHCHeader); memcpy(mRawDataPtr, (char*)&digitheader1, sizeof(DigitHCHeader1)); // 8 because we are only using the first 2 32bit words of the header, the rest are optional. mRawDataPtr += sizeof(DigitHCHeader1); - wordswritten += 2; - return wordswritten; } void Trap2CRU::convertTrapData(o2::trd::TriggerRecord const& triggerrecord, const int& triggercount) { - //build a HalfCRUHeader for this event/cru/endpoint - //loop over cru's - // loop over all half chambers, thankfully they data is sorted. - // check if current chamber has a link - // if not blank, else fill in data from link records - // dump data to rawwriter - //finished for event. this method is only called per event. - // char* traprawdataptr = (char*)&mTrapRawData[0]; - std::array localParsedDigitsindex; // store the index of the digits of an mcm + // Create the raw data for this trigger + // loop over half-CRUs and for each half-CRU we put + // 1. HalfCRUHeader + // 2. Tracklet data + // 3. Two tracklet endmarkers + // 4. Two digit HC headers + // 5. Digit data + // 6. Two end markers + int rawwords = 0; + int nLinksWithData = 0; char* rawdataptratstart; std::vector rawdatavector(1024 * 1024 * 2); // sum of link sizes + padding in units of bytes and some space for the header (512 bytes). if (mVerbosity) { LOG(info) << "BUNCH CROSSING : " << triggerrecord.getBCData().bc << " with orbit : " << triggerrecord.getBCData().orbit; } - //set startdigit and starttracklet relative to the trigger. - // - int starttrackletindex = triggerrecord.getFirstTracklet(); int endtrackletindex = triggerrecord.getFirstTracklet() + triggerrecord.getNumberOfTracklets(); - int64_t startdigitindex = triggerrecord.getFirstDigit(); int64_t enddigitindex = triggerrecord.getFirstDigit() + triggerrecord.getNumberOfDigits(); const auto& ctpOffsets = o2::ctp::TriggerOffsetsParam::Instance(); + auto ir = triggerrecord.getBCData(); + ir += ctpOffsets.LM_L0; + if (ctpOffsets.LM_L0 < 0 && ir.toLong() <= -ctpOffsets.LM_L0) { + // skip this trigger + LOG(info) << "Skip writing IR " << triggerrecord.getBCData() << " as after applying LM_L0 shift of " << ctpOffsets.LM_L0 << " bunches the orbit would become negative"; + mCurrentDigit = enddigitindex; + mCurrentTracklet = endtrackletindex; + return; + } - for (int halfcru = 0; halfcru < o2::trd::constants::NHALFCRU; halfcru++) { + for (int halfcru = 0; halfcru < constants::NHALFCRU; halfcru++) { int halfcruwordswritten = 0; int supermodule = halfcru / 4; // 2 cru per supermodule. 72/4, as of writing mEndPointID = halfcru % 2; // 2 pci end points per cru, 15 links each @@ -682,15 +556,11 @@ void Trap2CRU::convertTrapData(o2::trd::TriggerRecord const& triggerrecord, cons int side = cru % 2; // first cru is A second is B, 3rd is A etc mFeeID = constructTRDFeeID(supermodule, side, mEndPointID); mCruID = halfcru / 2; - mLinkID = o2::trd::constants::TRDLINKID; mEndPointID = halfcru % 2; // just the upper or lower half of the cru, hence %2 of the the halfcru number. - std::string sside; - (side) ? sside = "C" : sside = "A"; - //15 links per half cru or cru end point. - memset(&mRawData[0], 0, sizeof(mRawData[0]) * mRawData.size()); // zero the rawdata storage + // 15 links per half cru or cru end point. HalfCRUHeader halfcruheader; //now write the cruheader at the head of all the data for this halfcru. - buildHalfCRUHeader(halfcruheader, triggerrecord.getBCData().bc, halfcru); + buildHalfCRUHeader(halfcruheader, ir.bc, halfcru); halfcruheader.EndPoint = mEndPointID; mRawDataPtr = rawdatavector.data(); HalfCRUHeader* halfcruheaderptr = (HalfCRUHeader*)mRawDataPtr; // store the ptr to the halfcruheader for later adding the link lengths and possibly simulated errors. @@ -698,133 +568,90 @@ void Trap2CRU::convertTrapData(o2::trd::TriggerRecord const& triggerrecord, cons halfcruwordswritten += sizeof(halfcruheader) / 4; int totallinklengths = 0; rawdataptratstart = mRawDataPtr; // keep track of where we started. - for (int halfcrulink = 0; halfcrulink < o2::trd::constants::NLINKSPERHALFCRU; halfcrulink++) { + for (int halfcrulink = 0; halfcrulink < constants::NLINKSPERHALFCRU; halfcrulink++) { //links run from 0 to 14, so linkid offset is halfcru*15; - int linkid = halfcrulink + halfcru * o2::trd::constants::NLINKSPERHALFCRU; - if (mVerbosity) { - LOG(info) << " linkid : " << linkid << " with link " << halfcrulink << " of halfcru " << halfcru << " tracklet is on link for linkid : " << linkid << " and tracklet index of : " << mCurrentTracklet << " with current digit index : " << mCurrentDigit; - } - int linkwordswritten = 0; + int linkid = halfcrulink + halfcru * constants::NLINKSPERHALFCRU; + int hcid = HelperMethods::getHCIDFromLinkID(linkid); + int linkwordswritten = 0; // number of 32 bit words for this link int errors = 0; // put no errors in for now. - int size = 0; // in 32 bit words - uint32_t paddingsize = 0; // in 32 bit words uint32_t crudatasize = 0; // in 256 bit words. - //loop over tracklets for mcm's that match - int tracklets = 0; - int trackletendmarker = 0; - int adccounter = 0; - int rawwordsbefore = 0; - bool isFirstDigit = true; - int trackletcounter = 0; + // loop over tracklets for mcms that match + int nTrackletsOnLink = 0; + int nDigitsOnLink = 0; + bool haveDigitOnLink = false; + bool haveTrackletOnLink = false; + if (mCurrentTracklet < mTracklets.size() && mTracklets[mCurrentTracklet].getHCID() == hcid) { + haveTrackletOnLink = true; + } + if (mCurrentDigit < mDigits.size() && mDigits[mDigitsIndex[mCurrentDigit]].getHCId() == hcid) { + haveDigitOnLink = true; + } if (mVerbosity) { - LOG(info) << "tracklet on link : " << linkid << " mcurrenttracklet:" << mCurrentTracklet << " endtrackletindex:" << endtrackletindex << " is on link: " << isTrackletOnLink(linkid, mCurrentTracklet) << " and digits current digit:" << mCurrentDigit << " enddigitindex:" << enddigitindex << "is digit on link:" << isDigitOnLink(linkid, mCurrentDigit); + LOGF(info, "Link ID(%i), HCID(%i). Tracklets? %i, Digits? %i. Tracklet HCID(%i), mCurrentTracklet(%i), mCurrentDigit(%i)", + linkid, hcid, haveTrackletOnLink, haveDigitOnLink, mTracklets[mCurrentTracklet].getHCID(), mCurrentTracklet, mCurrentDigit); } - if (isTrackletOnLink(linkid, mCurrentTracklet) || isDigitOnLink(linkid, mCurrentDigit)) { + if (haveTrackletOnLink || haveDigitOnLink) { + nLinksWithData++; // we have some data somewhere for this link - //write tracklet half chamber header irrespective of there being tracklet data - if (mUseTrackletHCHeader != 0) { - if (isTrackletOnLink(linkid, mCurrentTracklet) || mUseTrackletHCHeader == 2) { - //write tracklethcheader if there is tracklet data or if we always have tracklethcheader - //first part of the if statement handles the mUseTrackletHCHeader==1 option - int hcheaderwords = writeTrackletHCHeader(triggercount); - linkwordswritten += hcheaderwords; - rawwords += hcheaderwords; + if (mUseTrackletHCHeader > 0) { + if (haveTrackletOnLink || mUseTrackletHCHeader == 2) { + // write tracklethcheader if there is tracklet data or if we always want to have tracklethcheader + // first part of the if statement handles the mUseTrackletHCHeader==1 option + writeTrackletHCHeader(hcid, triggercount); + linkwordswritten += 1; } //else do nothing as we dont want/have tracklethcheader } - while (isTrackletOnLink(linkid, mCurrentTracklet) && mCurrentTracklet < endtrackletindex) { + while (mCurrentTracklet < endtrackletindex && mTracklets[mCurrentTracklet].getHCID() == hcid) { // still on an mcm on this link - tracklets = buildTrackletRawData(mCurrentTracklet, linkid); //returns # of 32 bits, header plus trackletdata words that would have come from the mcm. + int tracklets = buildTrackletRawData(mCurrentTracklet); // returns # of tracklets for single MCM mCurrentTracklet += tracklets; - trackletcounter += tracklets; - linkwordswritten += tracklets + 1; - rawwords += tracklets + 1; //1 to include the header + nTrackletsOnLink += tracklets; + mTotalTrackletsWritten += tracklets; + linkwordswritten += tracklets + 1; // +1 to include the header } - if (mCurrentTracklet >= mTracklets.size()) { - LOG(debug) << " finished with tracklets"; - } - //write tracklet end marker irrespective of their being tracklet data. - trackletendmarker = writeTrackletEndMarker(); - linkwordswritten += trackletendmarker; - rawwords += trackletendmarker; - adccounter = 0; - rawwordsbefore = rawwords; - //always write the digit hc header - int hcheaderwords = 0; - if (mCurrentDigit >= mDigits.size()) { - // take care of the case where the digit hc header is written but we have no more digits to write, we then need to get the half chamber header from the tracklet. - hcheaderwords = writeDigitHCHeader(triggercount, mTracklets[mCurrentTracklet].getHCID()); - } else { - hcheaderwords = writeDigitHCHeader(triggercount, mDigits[mDigitsIndex[mCurrentDigit]].getHCId()); - } - - linkwordswritten += hcheaderwords; - rawwords += hcheaderwords; - //although if there are trackelts there better be some digits unless the digits are switched off. - if (mCurrentDigit < mDigits.size()) { - while (isDigitOnLink(linkid, mCurrentDigit) && mCurrentDigit < enddigitindex && mEventDigitCount % mDigitRate == 0) { - if (mVerbosity) { - LOG(info) << "at top of digit while loop calc linkid :" << linkid << " : hcid=" << mDigits[mDigitsIndex[mCurrentDigit]].getHCId() << " actual link=" << linkid; - LOG(info) << "mCurrentDigit :" << mCurrentDigit; + // write 2 tracklet end markers irrespective of there being tracklet data. + writeTrackletEndMarkers(); + linkwordswritten += 2; + // always write 2 digit hc headers, irrespective of whether there are digits or not + writeDigitHCHeaders(triggercount, hcid); + linkwordswritten += 2; + while (mCurrentDigit < enddigitindex && mDigits[mDigitsIndex[mCurrentDigit]].getHCId() == hcid) { + // while we are on a single mcm, copy the digits timebins to the array. + int digitcounter = 0; + int currentROB = mDigits[mDigitsIndex[mCurrentDigit]].getROB(); + int currentMCM = mDigits[mDigitsIndex[mCurrentDigit]].getMCM(); + int firstDigitMCM = mCurrentDigit; + while (mDigits[mDigitsIndex[mCurrentDigit]].getMCM() == currentMCM && + mDigits[mDigitsIndex[mCurrentDigit]].getROB() == currentROB && + mDigits[mDigitsIndex[mCurrentDigit]].getHCId() == hcid) { + mCurrentDigit++; + digitcounter++; + if (mCurrentDigit == enddigitindex) { + break; } - //while we are on a single mcm, copy the digits timebins to the array. - int digitcounter = 0; - int currentROB = mDigits[mDigitsIndex[mCurrentDigit]].getROB(); - int currentMCM = mDigits[mDigitsIndex[mCurrentDigit]].getMCM(); - int currentDetector = mDigits[mDigitsIndex[mCurrentDigit]].getDetector(); - int startmCurrentDigit = mCurrentDigit; - while (mDigits[mDigitsIndex[mCurrentDigit]].getMCM() == currentMCM && - mDigits[mDigitsIndex[mCurrentDigit]].getROB() == currentROB && - mDigits[mDigitsIndex[mCurrentDigit]].getDetector() == currentDetector) { - LOG(debug) << " on index of : " << mDigitsIndex[mCurrentDigit] << " wuf channel=" << mDigits[mDigitsIndex[mCurrentDigit]].getChannel(); - mCurrentDigit++; - digitcounter++; - adccounter++; - if (digitcounter > 22) { - LOG(error) << " we are on the 22nd digit of an mcm ?? This is not possible"; - } - if (mCurrentDigit == mDigits.size()) { - break; - } - } - // mcm digits are full, now write it out. - char* preptr; - preptr = mRawDataPtr; - int digitwordswritten = 0; - digitwordswritten = buildDigitRawData(startmCurrentDigit, mCurrentDigit, currentMCM, currentROB, triggercount); - linkwordswritten += digitwordswritten; } + // mcm digits are full, now write it out. + linkwordswritten += buildDigitRawData(firstDigitMCM, mCurrentDigit, currentMCM, currentROB, triggercount); + nDigitsOnLink += (mCurrentDigit - firstDigitMCM); } - } - if (mVerbosity) { - LOG(info) << "link:" << linkid << " trackletcounter: " << trackletcounter << " currenttracklet: " << mCurrentTracklet << " adccounter :" << adccounter << " current digit : " << mCurrentDigit; - } - int counter = 0; - if (adccounter > 0 || trackletcounter > 0) { - //write the tracklet end marker so long as we have any data (digits or tracklets). - int digitendmarkerwritten = writeDigitEndMarker(); - linkwordswritten += digitendmarkerwritten; - rawwords += digitendmarkerwritten; - } - //pad up to a whole 256 bit word size - if (linkwordswritten != 0) { - crudatasize = linkwordswritten / 8; - linkSizePadding(linkwordswritten, crudatasize, paddingsize); - - // now pad the data if needed .... - char* olddataptr = mRawDataPtr; // store the old pointer so we can do some sanity checks for how far we advance. - //now for padding - uint16_t padbytes = paddingsize * sizeof(uint32_t); - uint32_t padword = 0xeeeeeeee; + + // write the digit end marker so long as we have any data (digits or tracklets). + writeDigitEndMarkers(); + linkwordswritten += 2; + + // pad up to a whole 256 bit word size (paddingsize is number of 32 bit words to pad) + int paddingsize = (linkwordswritten % 8 == 0) ? 0 : 8 - (linkwordswritten % 8); + int padword = constants::PADDINGWORD; for (int i = 0; i < paddingsize; ++i) { - memcpy(mRawDataPtr, (char*)&padword, 4); + memcpy(mRawDataPtr, &padword, 4); mRawDataPtr += 4; linkwordswritten++; - rawwords++; } + rawwords += linkwordswritten; crudatasize = linkwordswritten / 8; //convert to 256 bit alignment. if ((linkwordswritten % 8) != 0) { - LOG(error) << "linkwordswritten is not 256 bit aligned " << linkwordswritten << " %8 = " << linkwordswritten % 8 << " and a padding size of : " << paddingsize << " or padbytes of : " << padbytes; + LOG(error) << "linkwordswritten is not 256 bit aligned: " << linkwordswritten << ". Padding size of= " << paddingsize; } //set the halfcruheader for the length of this link. //but first a sanity check. @@ -837,64 +664,36 @@ void Trap2CRU::convertTrapData(o2::trd::TriggerRecord const& triggerrecord, cons totallinklengths += crudatasize; if ((mRawDataPtr - rawdataptratstart) != (totallinklengths * 32)) { bytescopied = mRawDataPtr - rawdataptratstart; - if (mVerbosity) { - LOG(info) << "something wrong with data size in cruheader writing" - << "linkwordswriten:" - << linkwordswritten << " rawwords:" << rawwords << "bytestocopy : " - << bytescopied << " crudatasize:" << crudatasize << " sum of links up to now : " - << totallinklengths << " mRawDataPtr:0x" << std::hex << (void*)mRawDataPtr - << " start ptr:" << std::hex << (void*)rawdataptratstart; - } - } else { - if (mVerbosity) { - LOG(debug) << "all fine with data size writing padbytes:" << paddingsize - << " linkwordswriten:" << linkwordswritten << " bytestocopy : " << bytescopied - << " crudatasize:" << crudatasize << " mRawDataPtr:0x" << std::hex - << (void*)mRawDataPtr << " start ptr:" << std::hex << (void*)rawdataptratstart; - } + LOGF(error, "Data size missmatch. Written words (%i), bytesCopied(%i), crudatasize(%i)", linkwordswritten, bytescopied, crudatasize); } - //sanity check for now: - if (crudatasize != o2::trd::getHalfCRULinkDataSize(halfcruheader, halfcrulink)) { - // we have written the wrong amount of data .... - LOG(warn) << "crudata is ! = get link data size " << crudatasize << "!=" << o2::trd::getHalfCRULinkDataSize(halfcruheader, halfcrulink); - } - } // if we have data on link - else { + LOGF(debug, "Found %i tracklets and %i digits on link %i (HCID=%i)", nTrackletsOnLink, nDigitsOnLink, linkid, hcid); + } else { + // no data on this link setHalfCRUHeaderLinkSizeAndFlags(halfcruheader, halfcrulink, 0, 0); if (mVerbosity) { LOG(info) << "linkwordswritten is zero : " << linkwordswritten; } - if (crudatasize != 0) { - LOG(warn) << " we should not be here with a crudatasize of " << crudatasize << " as the linkwordswritten is " << linkwordswritten << " with a halfcrulink of : " << halfcrulink; - LOG(debug) << " ### setting halfcrulink " << halfcrulink << " linksize to : " << crudatasize << " with a linkwordswrittern=" << linkwordswritten; - } - // setHalfCRUHeaderLinkData(halfcruheader, halfcrulink, 0,0); } halfcruwordswritten += linkwordswritten; - } // if tracklets.size >0 - //write the cruhalfheader now that we know the lengths. + } // end loop over all links for one half CRU + // write the cruhalfheader now that we know the lengths. memcpy((char*)halfcruheaderptr, (char*)&halfcruheader, sizeof(halfcruheader)); //write halfcru data here. std::vector feeidpayload(halfcruwordswritten * 4); memcpy(feeidpayload.data(), &rawdatavector[0], halfcruwordswritten * 4); assert(halfcruwordswritten % 8 == 0); - auto ir = triggerrecord.getBCData(); - ir += ctpOffsets.LM_L0; - if (ctpOffsets.LM_L0 >= 0 || ir.toLong() > -ctpOffsets.LM_L0) { - mWriter.addData(mFeeID, mCruID, mLinkID, mEndPointID, ir, feeidpayload, false, triggercount); - if (mVerbosity) { - LOG(info) << "written file for trigger : " << triggercount << " feeid of 0x" << std::hex << mFeeID << " cruid : " << mCruID << " and linkid: " << mLinkID << " and EndPoint: " << mEndPointID << " orbit :0x" << std::hex << triggerrecord.getBCData().orbit << " bc:0x" << std::hex << triggerrecord.getBCData().bc << " and payload size of : " << halfcruwordswritten << " with a half cru of: "; - printHalfCRUHeader(halfcruheader); - HalfCRUHeader* h; - h = (HalfCRUHeader*)feeidpayload.data(); - HalfCRUHeader h1 = *h; - printHalfCRUHeader(h1); - LOG(info) << "+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+ ====== end of writing"; - } - } else { - LOG(info) << "Skip writing IR " << triggerrecord.getBCData() << " as after applying LM_L0 shift of " << ctpOffsets.LM_L0 << " bunches the orbit would become negative"; + mWriter.addData(mFeeID, mCruID, mLinkID, mEndPointID, ir, feeidpayload, false, triggercount); + if (mVerbosity) { + LOGF(info, "Written file for trigger %i, FeeID(%x), CruID(%i), LindID(%i), end point (%i), orbit(%i), bc(%i), payload size (%i)", + triggercount, mFeeID, mCruID, mLinkID, mEndPointID, ir.orbit, ir.bc, halfcruwordswritten); + printHalfCRUHeader(halfcruheader); + LOG(info) << "+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+ ====== end of writing"; } } + if (mVerbosity) { + LOG(info) << "Raw data written for all CRUs of this trigger: " << rawwords; + LOG(info) << "Number of links with data for this trigger: " << nLinksWithData; + } } } // end namespace trd diff --git a/Detectors/TRD/simulation/src/trap2raw.cxx b/Detectors/TRD/simulation/src/trap2raw.cxx index 9639da3e1ddd4..dc3959bc2642b 100644 --- a/Detectors/TRD/simulation/src/trap2raw.cxx +++ b/Detectors/TRD/simulation/src/trap2raw.cxx @@ -50,7 +50,7 @@ namespace bpo = boost::program_options; void trap2raw(const std::string& inpDigitsName, const std::string& inpTrackletsName, - const std::string& outDir, int digitrate, bool verbose, std::string filePerLink, + const std::string& outDir, int verbosity, std::string filePerLink, uint32_t rdhV = 6, bool noEmptyHBF = false, int tracklethcheader = 0, int superPageSizeInB = 1024 * 1024); int main(int argc, char** argv) @@ -66,7 +66,6 @@ int main(int argc, char** argv) auto add_option = opt_general.add_options(); add_option("help,h", "Print this help message"); add_option("verbosity,v", bpo::value()->default_value(0), "verbosity level"); - // add_option("input-file,i", bpo::value()->default_value("trdtrapraw.root"), "input Trapsim raw file"); add_option("input-file-digits,d", bpo::value()->default_value("trddigits.root"), "input Trapsim digits file"); add_option("input-file-tracklets,t", bpo::value()->default_value("trdtracklets.root"), "input Trapsim tracklets file"); add_option("file-per,l", bpo::value()->default_value("halfcru"), "all : raw file(false), halfcru : cru end point, cru : one file per cru, sm: one file per supermodule"); @@ -76,8 +75,6 @@ int main(int argc, char** argv) add_option("rdh-version,r", bpo::value()->default_value(6), "rdh version in use default"); add_option("configKeyValues", bpo::value()->default_value(""), "comma-separated configKeyValues"); add_option("hbfutils-config,u", bpo::value()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); - add_option("digitrate", bpo::value()->default_value(1), "only include digits at 1 per this number"); - add_option("verbose,w", bpo::value()->default_value(false), "verbose"); opt_all.add(opt_general).add(opt_hidden); bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); @@ -103,13 +100,12 @@ int main(int argc, char** argv) } o2::conf::ConfigurableParam::updateFromString(vm["configKeyValues"].as()); - std::cout << "yay it ran" << std::endl; - trap2raw(vm["input-file-digits"].as(), vm["input-file-tracklets"].as(), vm["output-dir"].as(), vm["digitrate"].as(), vm["verbosity"].as(), vm["file-per"].as(), vm["rdh-version"].as(), vm["no-empty-hbf"].as(), vm["tracklethcheader"].as()); + trap2raw(vm["input-file-digits"].as(), vm["input-file-tracklets"].as(), vm["output-dir"].as(), vm["verbosity"].as(), vm["file-per"].as(), vm["rdh-version"].as(), vm["no-empty-hbf"].as(), vm["tracklethcheader"].as()); return 0; } -void trap2raw(const std::string& inpDigitsName, const std::string& inpTrackletsName, const std::string& outDir, int digitrate, bool verbose, std::string filePer, uint32_t rdhV, bool noEmptyHBF, int trackletHCHeader, int superPageSizeInB) +void trap2raw(const std::string& inpDigitsName, const std::string& inpTrackletsName, const std::string& outDir, int verbosity, std::string filePer, uint32_t rdhV, bool noEmptyHBF, int trackletHCHeader, int superPageSizeInB) { TStopwatch swTot; swTot.Start(); @@ -117,9 +113,8 @@ void trap2raw(const std::string& inpDigitsName, const std::string& inpTrackletsN o2::trd::Trap2CRU mc2raw(outDir, inpDigitsName, inpTrackletsName); //,superPageSizeInB); LOG(info) << "class instantiated"; mc2raw.setFilePer(filePer); - mc2raw.setVerbosity(verbose); + mc2raw.setVerbosity(verbosity); mc2raw.setTrackletHCHeader(trackletHCHeader); // run3 or run2 - mc2raw.setDigitRate(digitrate); // run3 or run2 auto& wr = mc2raw.getWriter(); std::string inputGRP = o2::base::NameConf::getGRPFileName(); const auto grp = o2::parameters::GRPObject::loadFrom(inputGRP); diff --git a/Detectors/TRD/workflow/src/TRDDigitizerSpec.cxx b/Detectors/TRD/workflow/src/TRDDigitizerSpec.cxx index e4af5998435c8..cf76ffa6535f0 100644 --- a/Detectors/TRD/workflow/src/TRDDigitizerSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDDigitizerSpec.cxx @@ -105,6 +105,7 @@ class TRDDPLDigitizerTask : public o2::base::BaseDPLDigitizer double dT = currentTime.getTimeNS() - triggerTime.getTimeNS(); if (dT < o2::trd::constants::BUSY_TIME) { // BUSY_TIME = READOUT_TIME + DEAD_TIME, if less than that, pile up the signals and update the last time + LOGF(info, "Not creating new trigger at time %.2f since dT=%.2f < busy time of %.2f", currentTime.getTimeNS(), dT, o2::trd::constants::BUSY_TIME); isNewTrigger = false; mDigitizer.pileup(); } else { From 49fb811b3d578bfc0aaccebdaba198aaf6510bc7 Mon Sep 17 00:00:00 2001 From: Ole Schmidt Date: Tue, 12 Jul 2022 10:02:56 +0200 Subject: [PATCH 5/5] Add macro to compare two digits and tracklets files --- .../macros/CompareDigitsAndTracklets.C | 179 ++++++++++++++++++ cmake/O2RootMacroExclusionList.cmake | 1 + 2 files changed, 180 insertions(+) create mode 100644 Detectors/TRD/reconstruction/macros/CompareDigitsAndTracklets.C diff --git a/Detectors/TRD/reconstruction/macros/CompareDigitsAndTracklets.C b/Detectors/TRD/reconstruction/macros/CompareDigitsAndTracklets.C new file mode 100644 index 0000000000000..9439eae08a2f0 --- /dev/null +++ b/Detectors/TRD/reconstruction/macros/CompareDigitsAndTracklets.C @@ -0,0 +1,179 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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 CompareDigitsAndTracklets.C +/// \brief Simple macro to compare TRD digits and tracklets e.g. before and after conversion to RAW + +// see the Detectors/TRD/reconstruction/README.md for the steps required to convert a simulation to RAW and read it back +// +// WARNING: This should be used only for rather small data sets (e.g. the 20 PbPb events as suggested above). +// Otherwise, due to the quadratic dependency on the number of digits/tracklets this takes very long. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include + +#include "FairLogger.h" +#include "DataFormatsTRD/Digit.h" +#include "DataFormatsTRD/Tracklet64.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "DataFormatsTRD/Constants.h" +#include "DataFormatsTRD/HelperMethods.h" +#endif + +using namespace o2::trd; + +void CompareDigitsAndTracklets(bool ignoreTrkltPid = false, + std::string digitfile = "trddigitsOrig.root", + std::string trackletfile = "trdtrackletsOrig.root", + std::string recodigitfile = "trddigits.root", + std::string recotrackletfile = "trdtracklets.root") +{ + TFile* dfin = TFile::Open(digitfile.c_str()); + TTree* digitTree = (TTree*)dfin->Get("o2sim"); + std::vector* digits = nullptr; + digitTree->SetBranchAddress("TRDDigit", &digits); + int ndigitev = digitTree->GetEntries(); + + TFile* tfin = TFile::Open(trackletfile.c_str()); + TTree* trackletTree = (TTree*)tfin->Get("o2sim"); + std::vector* tracklets = nullptr; + trackletTree->SetBranchAddress("Tracklet", &tracklets); + std::vector* trigRecs = nullptr; + trackletTree->SetBranchAddress("TrackTrg", &trigRecs); + int ntrackletev = trackletTree->GetEntries(); + + TFile* dfinreco = TFile::Open(recodigitfile.c_str()); + TTree* digitTreereco = (TTree*)dfinreco->Get("o2sim"); + std::vector* digitsreco = nullptr; + digitTreereco->SetBranchAddress("TRDDigit", &digitsreco); + int ndigitevreco = digitTreereco->GetEntries(); + + TFile* tfinreco = TFile::Open(recotrackletfile.c_str()); + TTree* trackletTreereco = (TTree*)tfinreco->Get("o2sim"); + std::vector* trackletsreco = nullptr; + trackletTreereco->SetBranchAddress("Tracklet", &trackletsreco); + std::vector* trigRecsReco = nullptr; + trackletTreereco->SetBranchAddress("TrackTrg", &trigRecsReco); + int ntrackletevreco = trackletTreereco->GetEntries(); + + if ((ndigitev != ntrackletev) || (ndigitevreco != ntrackletevreco) || (ndigitev != ndigitevreco)) { + // make sure the number of entries is the same in all trees + LOG(error) << "The trees have a different number of entries"; + return; + } + + for (int iev = 0; iev < ntrackletev; ++iev) { + digitTree->GetEvent(iev); + trackletTree->GetEvent(iev); + digitTreereco->GetEvent(iev); + trackletTreereco->GetEvent(iev); + + // compare trigger records + if (trigRecs->size() != trigRecsReco->size()) { + LOG(warn) << "Number of trigger records does not match for entry " << iev; + continue; + } + for (size_t iTrig = 0; iTrig < trigRecs->size(); ++iTrig) { + const auto& trig = trigRecs->at(iTrig); + const auto& trigReco = trigRecsReco->at(iTrig); + if (!(trig == trigReco)) { + LOGF(error, "Trigger records don't match at trigger %ul. Reference orbit/bc (%u/%u), orbit/bc (%u/%u)", + iTrig, trig.getBCData().orbit, trig.getBCData().bc, trigReco.getBCData().orbit, trigReco.getBCData().bc); + break; + } + } + + // compare tracklets + if (tracklets->size() != trackletsreco->size()) { + LOG(warn) << "Number of tracklets does not match for entry " << iev; + continue; + } + std::vector flags(trackletsreco->size()); + for (size_t iTrklt = 0; iTrklt < tracklets->size(); ++iTrklt) { + const auto& trklt = tracklets->at(iTrklt); + auto tw = trklt.getTrackletWord(); + tw |= (0xfUL << 60); // set all format bits + if (ignoreTrkltPid) { + tw |= 0xffffffUL; // set all PID bits + } + bool hasMatch = false; + for (size_t iTrkltReco = 0; iTrkltReco < trackletsreco->size(); ++iTrkltReco) { + if (flags[iTrkltReco]) { + // tracklet has already been matched, skip it + continue; + } + const auto& trkltReco = trackletsreco->at(iTrkltReco); + auto twReco = trkltReco.getTrackletWord(); + twReco |= (0xfUL << 60); // set all format bits + if (ignoreTrkltPid) { + twReco |= 0xffffffUL; // set all PID bits + } + if (tw == twReco) { + // matching tracklet found + flags[iTrkltReco] = true; + hasMatch = true; + break; + } + } + if (!hasMatch) { + LOGF(error, "No match for reference tracklet at index %lu\n", iTrklt); + break; + } + } + + // compare digits + if (digits->size() != digitsreco->size()) { + LOG(warn) << "Number of digits does not match for entry " << iev; + continue; + } + std::vector flagsDigit(digitsreco->size()); + for (size_t iDigit = 0; iDigit < digits->size(); ++iDigit) { + bool hasMatch = false; + const auto& digit = digits->at(iDigit); + for (size_t iDigitReco = 0; iDigitReco < digitsreco->size(); ++iDigitReco) { + if (flagsDigit[iDigitReco]) { + continue; + } + const auto& digitReco = digitsreco->at(iDigitReco); + if (digitReco == digit) { + flagsDigit[iDigitReco] = true; + hasMatch = true; + break; + } + } + if (!hasMatch) { + LOGF(error, "No match for reference digit at index %lu\n", iDigit); + break; + } + } + + // summary for this TF + int matchedTracklets = 0; + for (auto f : flags) { + if (f) { + matchedTracklets++; + } + } + int matchedDigits = 0; + for (auto f : flagsDigit) { + if (f) { + matchedDigits++; + } + } + LOGF(info, "Number of tracklets in simulation: %lu. In reco: %lu. Number of tracklets from simulation for which a match in reco was found: %i", tracklets->size(), trackletsreco->size(), matchedTracklets); + LOGF(info, "Number of digits in simulation: %lu. In reco: %lu. Number of digits from simulation for which a match in reco was found: %i", digits->size(), digitsreco->size(), matchedDigits); + } + + if (ignoreTrkltPid) { + LOG(warn) << "The PID values stored inside the tracklets have been ignored for this comparison"; + } +} diff --git a/cmake/O2RootMacroExclusionList.cmake b/cmake/O2RootMacroExclusionList.cmake index 155e6fd5a11c6..d3d06fe1e5347 100644 --- a/cmake/O2RootMacroExclusionList.cmake +++ b/cmake/O2RootMacroExclusionList.cmake @@ -32,6 +32,7 @@ list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST Detectors/TRD/macros/convertRun2ToRun3Digits.C Detectors/TRD/simulation/macros/CheckTRDFST.C Detectors/TRD/reconstruction/macros/checkTrackletCharges.C + Detectors/TRD/reconstruction/macros/CompareDigitsAndTracklets.C Detectors/gconfig/g4Config.C Detectors/TRD/macros/ParseTrapRawOutput.C Detectors/EMCAL/calib/macros/ReadTestBadChannelMap_CCDBApi.C