From 37d117ae9d475ed80848095ad31ac3bb800be41f Mon Sep 17 00:00:00 2001 From: iravasen Date: Tue, 21 Oct 2025 13:35:26 +0200 Subject: [PATCH 1/4] fix parallel processing for highly disordered cases (local data replay) --- .../ITSWorkflow/ThresholdCalibratorSpec.h | 8 +- .../workflow/src/ThresholdCalibratorSpec.cxx | 178 ++++++++++-------- 2 files changed, 109 insertions(+), 77 deletions(-) diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h index 2a139f7997dfb..45ae5269750b9 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h @@ -232,7 +232,9 @@ class ITSThresholdCalibrator : public Task short int mRunTypeUp = -1; short int mRunTypeRU[N_RU] = {0}; short int mRunTypeRUCopy[N_RU] = {0}; - short int mCdwCntRU[N_RU][N_ROW] = {{0}}; + bool mFlagsRU[N_RU] = {0}; + //short int mCdwCntRU[N_RU][N_ROW] = {{0}}; + std::map, 500>>> mCdwCntRU; // RU --> row --> 2D hit map short int mLoopVal[N_RU][N_ROW] = {{0}}; bool mActiveLinks[N_RU][3] = {{false}}; std::set mRuSet; @@ -241,6 +243,7 @@ class ITSThresholdCalibrator : public Task short int mMin = -1, mMax = -1, mMin2 = 0, mMax2 = 0; short int mStep = 1, mStep2 = 1; short int mStrobeWindow = 5; // 5 means 5*25ns = 125 ns + short int mRowScan = 512; // number of scanned rows, used only to normalize % of success // Get threshold method (fit == 1, derivative == 0, or hitcounting == 2) char mFitType = -1; @@ -293,6 +296,7 @@ class ITSThresholdCalibrator : public Task short int manualStep = 1, manualStep2 = 1; std::string manualScanType; short int manualStrobeWindow = 5; + short int manualRowScan = 512; // used only to normalize % of success in thr/ithr/vcasn scans // for CRU_ITS data processing bool isCRUITS = false; @@ -306,7 +310,7 @@ class ITSThresholdCalibrator : public Task int maxDumpS = -1; // maximum number of s-curves to be dumped, default -1 = dump all std::string chipDumpS = ""; // list of comma-separated O2 chipIDs to be dumped, default is empty = dump all int dumpCounterS[24120] = {0}; // count dumps for every chip - int countCdw[24120] = {0}; // count how many CDWs have been processed with the maximum charge injected: usefull for s-curve dump when hits do not arrive in order + bool isChipDB[24120] = {0}; // check whether a chip has been already added to DB entry TFile* fileDumpS; // file where to store the s-curves on disk std::vector chipDumpList; // vector of chips to dump diff --git a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx index e1d7dc725e9e3..f70db2147ecf2 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx @@ -149,6 +149,12 @@ void ITSThresholdCalibrator::init(InitContext& ic) // Parameters to operate in manual mode (when run type is not recognized automatically) isManualMode = ic.options().get("manual-mode"); if (isManualMode) { + try { + manualRowScan = ic.options().get("manual-rowscan"); + } catch (std::exception const& e) { + throw std::runtime_error("Number of scanned rows not found, mandatory in manual mode"); + } + try { manualMin = ic.options().get("manual-min"); } catch (std::exception const& e) { @@ -746,39 +752,40 @@ void ITSThresholdCalibrator::extractThresholdRow(const short int& chipID, const } else { // threshold, vcasn, ithr, vresetd_2d - short int iRU = getRUID(chipID); + for (int scan_i = 0; scan_i < ((mScanType == 'r') ? N_RANGE : N_RANGE2); scan_i++) { #ifdef WITH_OPENMP omp_set_num_threads(mNThreads); #pragma omp parallel for schedule(dynamic) #endif - // Loop over all columns (pixels) in the row - for (short int col_i = 0; col_i < this->N_COL; col_i++) { - // Do the threshold fit - float thresh = 0., noise = 0.; - bool success = false; - int spoints = 0; - int scan_i = mScanType == 'r' ? (mLoopVal[iRU][row] - mMin) / mStep : 0; - if (isDumpS) { // already protected for multi-thread in the init - mFitHist->SetName(Form("scurve_chip%d_row%d_col%d_scani%d", chipID, row, col_i, scan_i)); - } + // Loop over all columns (pixels) in the row + for (short int col_i = 0; col_i < this->N_COL; col_i++) { + // Do the threshold fit + float thresh = 0., noise = 0.; + bool success = false; + int spoints = 0; - success = this->findThreshold(chipID, mPixelHits[chipID][row][col_i], - this->mX, mScanType == 'r' ? N_RANGE2 : N_RANGE, thresh, noise, spoints, scan_i); + if (isDumpS) { // already protected for multi-thread in the init + mFitHist->SetName(Form("scurve_chip%d_row%d_col%d_scani%d", chipID, row, col_i, scan_i)); + } - vChipid[col_i] = chipID; - vRow[col_i] = row; - vThreshold[col_i] = (mScanType == 'T' || mScanType == 'r') ? (short int)(thresh * 10.) : (short int)(thresh); - vNoise[col_i] = (float)(noise * 10.); // always factor 10 also for ITHR/VCASN to not have all zeros - vSuccess[col_i] = success; - vPoints[col_i] = spoints > 0 ? (unsigned char)(spoints) : 0; + success = this->findThreshold(chipID, mPixelHits[chipID][row][col_i], + this->mX, mScanType == 'r' ? N_RANGE2 : N_RANGE, thresh, noise, spoints, scan_i); + vChipid[col_i] = chipID; + vRow[col_i] = row; + vThreshold[col_i] = (mScanType == 'T' || mScanType == 'r') ? (short int)(thresh * 10.) : (short int)(thresh); + vNoise[col_i] = (float)(noise * 10.); // always factor 10 also for ITHR/VCASN to not have all zeros + vSuccess[col_i] = success; + vPoints[col_i] = spoints > 0 ? (unsigned char)(spoints) : 0; + + if (mScanType == 'r') { + vMixData[col_i] = (scan_i * mStep) + mMin; + } + } if (mScanType == 'r') { - vMixData[col_i] = mLoopVal[iRU][row]; + this->saveThreshold(); // save before moving to the next vresetd } } - if (mScanType == 'r') { - this->saveThreshold(); // save before moving to the next vresetd - } // Fill the ScTree tree if (mScanType == 'T' || mScanType == 'V' || mScanType == 'I') { // TODO: store also for other scans? @@ -794,6 +801,9 @@ void ITSThresholdCalibrator::extractThresholdRow(const short int& chipID, const // Saves threshold information to internal memory if (mScanType != 'P' && mScanType != 'p' && mScanType != 't' && mScanType != 'R' && mScanType != 'r') { + if(mVerboseOutput) { + LOG(info)<<"Saving data of ChipID: "<saveThreshold(); } } @@ -934,6 +944,7 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) this->mMax = 50; this->N_RANGE = 51; this->mCheckExactRow = true; + mRowScan = 512; } else if (runtype == THR_SCAN_SHORT || runtype == THR_SCAN_SHORT_100HZ || runtype == THR_SCAN_SHORT_200HZ || runtype == THR_SCAN_SHORT_33 || runtype == THR_SCAN_SHORT_2_10HZ || runtype == THR_SCAN_SHORT_150INJ) { @@ -951,6 +962,12 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) nInjScaled = nInj / 3; } } + mRowScan = 11; + if (runtype == THR_SCAN_SHORT_33) { + mRowScan = 33; + } else if(runtype == THR_SCAN_SHORT_2_10HZ){ + mRowScan = 2; + } } else if (runtype == VCASN150 || runtype == VCASN100 || runtype == VCASN100_100HZ || runtype == VCASN130 || runtype == VCASNBB) { // VCASN tuning for different target thresholds // Store average VCASN for each chip into CCDB @@ -962,6 +979,7 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) this->mMax = inMaxVcasn; // 80 is the default this->N_RANGE = mMax - mMin + 1; this->mCheckExactRow = true; + mRowScan = 4; } else if (runtype == ITHR150 || runtype == ITHR100 || runtype == ITHR100_100HZ || runtype == ITHR130) { // ITHR tuning -- average ITHR per chip @@ -973,6 +991,7 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) this->mMax = inMaxIthr; // 100 is the default this->N_RANGE = mMax - mMin + 1; this->mCheckExactRow = true; + mRowScan = 4; } else if (runtype == DIGITAL_SCAN || runtype == DIGITAL_SCAN_100HZ || runtype == DIGITAL_SCAN_NOMASK) { // Digital scan -- only storing one value per chip, no fit needed @@ -1078,6 +1097,7 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) if (scaleNinj) { nInjScaled = nInj / 3; } + mRowScan = manualRowScan; } else { throw runtype; } @@ -1367,15 +1387,14 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) row = !mCdwVersion ? (short int)(calib.calibUserField & 0xffff) : (short int)(calib.calibUserField & 0x1ff); // cw counter cwcnt = (short int)(calib.calibCounter); - // count the last N injections - short int checkVal = (mScanType == 'I') ? mMin : mMax; - if ((mScanType != 'r' && mScanType != 'p' && mScanType != 't' && loopval == checkVal) || - (mScanType == 'r' && realcharge == mMax2) || - (mScanType == 'p' && realcharge == mMin2) || - (mScanType == 't' && loopval == checkVal && realcharge == mMax2)) { - mCdwCntRU[iRU][row]++; - mLoopVal[iRU][row] = loopval; // keep loop val (relevant for VRESET2D and TOT_1ROW scan only) - } + + // count injections + short int loopPoint = (loopval - this->mMin) / mStep; + short int chgPoint = (realcharge - this->mMin2) / mStep2; + auto &arr = mCdwCntRU[iRU][row]; + arr[chgPoint][loopPoint]++; + + if (this->mVerboseOutput) { LOG(info) << "RU: " << iRU << " CDWcounter: " << cwcnt << " row: " << row << " Loopval: " << loopval << " realcharge: " << realcharge << " confDBv: " << mCdwVersion; LOG(info) << "NDIGITS: " << digits.size(); @@ -1470,12 +1489,7 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) if (ruIndex < 0) { continue; } - short int nL = 0; - for (int iL = 0; iL < 3; iL++) { - if (mActiveLinks[ruIndex][iL]) { - nL++; // count active links - } - } + short int nL = ruIndex > 47 ? 2 : 3; // total number of links per RU std::vector chipEnabled = getChipListFromRu(ruIndex, mActiveLinks[ruIndex]); // chip boundaries // Fill the chipDone info string if (mRunTypeRUCopy[ruIndex] == nInjScaled * nL) { @@ -1488,14 +1502,27 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) mRunTypeRUCopy[ruIndex] = 0; // reset here is safer (the other counter is reset in finalize) } // Check if scan of a row is finished: only for specific scans! - bool passCondition = (mCdwCntRU[ruIndex][row] >= nInjScaled * nL); - if (mScanType == 'p' || mScanType == 't') { - passCondition = passCondition && (mLoopVal[ruIndex][row] == mMax); - if (mVerboseOutput) { - LOG(info) << "PassCondition: " << passCondition << " - (mCdwCntRU,mLoopVal) of RU" << ruIndex << " row " << row << " = (" << mCdwCntRU[ruIndex][row] << ", " << mLoopVal[ruIndex][row] << ")"; + bool passCondition = true; + for(int j1=0; j1 < N_RANGE2; j1++) { + for(int j2=0; j2 < N_RANGE; j2++) { + if(mScanType == 't') { // ToT scan is done in specific ranges depending on charge (see ITSComm) + if ((j1 == 0 && j2<((600-mMin)/mStep)) || (j2>=((600-mMin)/mStep) && j2<=((800-mMin)/mStep)) || (j1==1 && j2>((800-mMin)/mStep))) { + if(mCdwCntRU[ruIndex][row][j1][j2] < nInjScaled * nL) { + passCondition = false; + break; + } + } + } else if(mCdwCntRU[ruIndex][row][j1][j2] < nInjScaled * nL) { + passCondition = false; + break; + } } - } else if (mVerboseOutput) { - LOG(info) << "PassCondition: " << passCondition << " - mCdwCntRU of RU" << ruIndex << " row " << row << " = " << mCdwCntRU[ruIndex][row]; + if(!passCondition){ + break; + } + } + if (mVerboseOutput) { + LOG(info) << "PassCondition: " << passCondition << " - mCdwCntRU of RU" << ruIndex << " row " << row << " = " << mCdwCntRU[ruIndex][row][0][0] << "(Links: "<= nInjScaled * nL && passCondition) { + mFlagsRU[ruIndex] = true; + finalize(); + LOG(info) << "Shipping all outputs to aggregator (before endOfStream arrival!)"; + pc.outputs().snapshot(Output{"ITS", "TSTR", (unsigned int)mChipModSel}, this->mTuning); + pc.outputs().snapshot(Output{"ITS", "PIXTYP", (unsigned int)mChipModSel}, this->mPixStat); + pc.outputs().snapshot(Output{"ITS", "RUNT", (unsigned int)mChipModSel}, this->mRunType); + pc.outputs().snapshot(Output{"ITS", "SCANT", (unsigned int)mChipModSel}, this->mScanType); + pc.outputs().snapshot(Output{"ITS", "FITT", (unsigned int)mChipModSel}, this->mFitType); + pc.outputs().snapshot(Output{"ITS", "CONFDBV", (unsigned int)mChipModSel}, this->mConfDBv); + pc.outputs().snapshot(Output{"ITS", "QCSTR", (unsigned int)mChipModSel}, this->mChipDoneQc); + // reset the DCSconfigObject_t before next ship out + mTuning.clear(); + mPixStat.clear(); + mChipDoneQc.clear(); } } // for (ROFs) - if (!(this->mRunTypeUp)) { - finalize(); - LOG(info) << "Shipping all outputs to aggregator (before endOfStream arrival!)"; - pc.outputs().snapshot(Output{"ITS", "TSTR", (unsigned int)mChipModSel}, this->mTuning); - pc.outputs().snapshot(Output{"ITS", "PIXTYP", (unsigned int)mChipModSel}, this->mPixStat); - pc.outputs().snapshot(Output{"ITS", "RUNT", (unsigned int)mChipModSel}, this->mRunType); - pc.outputs().snapshot(Output{"ITS", "SCANT", (unsigned int)mChipModSel}, this->mScanType); - pc.outputs().snapshot(Output{"ITS", "FITT", (unsigned int)mChipModSel}, this->mFitType); - pc.outputs().snapshot(Output{"ITS", "CONFDBV", (unsigned int)mChipModSel}, this->mConfDBv); - pc.outputs().snapshot(Output{"ITS", "QCSTR", (unsigned int)mChipModSel}, this->mChipDoneQc); - // reset the DCSconfigObject_t before next ship out - mTuning.clear(); - mPixStat.clear(); - mChipDoneQc.clear(); - } else if (pc.transitionState() == TransitionHandlingState::Requested) { + if (pc.transitionState() == TransitionHandlingState::Requested) { LOG(info) << "Run stop requested during the scan, sending output to aggregator and then stopping to process new data"; mRunStopRequested = true; finalize(); // calculating average thresholds based on what's collected up to this moment @@ -1769,13 +1799,13 @@ void ITSThresholdCalibrator::finalize() if (mScanType == 'I') { // Only ITHR scan: assign default ITHR = 50 if chip has no avg ITHR for (auto& iRU : mRuSet) { - if (mRunTypeRU[iRU] >= nInjScaled * getNumberOfActiveLinks(mActiveLinks[iRU]) || mRunStopRequested) { + if (mFlagsRU[iRU] || mRunStopRequested) { std::vector chipList = getChipListFromRu(iRU, mActiveLinks[iRU]); for (size_t i = 0; i < chipList.size(); i++) { if ((chipList[i] % mChipModBase) != mChipModSel) { continue; } - if (!mThresholds.count(chipList[i])) { + if (!mThresholds.count(chipList[i]) && !isChipDB[chipList[i]]) { if (mVerboseOutput) { LOG(info) << "Setting ITHR = 50 for chip " << chipList[i]; } @@ -1790,7 +1820,7 @@ void ITSThresholdCalibrator::finalize() auto it = this->mThresholds.cbegin(); while (it != this->mThresholds.cend()) { short int iRU = getRUID(it->first); - if (!isCRUITS && (mRunTypeRU[iRU] < nInjScaled * getNumberOfActiveLinks(mActiveLinks[iRU]) && !mRunStopRequested)) { + if (!isCRUITS && (!mFlagsRU[iRU]) && !mRunStopRequested) { ++it; continue; } @@ -1804,8 +1834,8 @@ void ITSThresholdCalibrator::finalize() } if (mVerboseOutput) { LOG(info) << "Average or mpv " << name << " of chip " << it->first << " = " << outVal << " e-"; - } - float status = ((float)it->second[4] / (float)(it->second[4] + it->second[5])) * 100.; // percentage of successful threshold extractions + } + float status = ((float)it->second[4] / (float)(mRowScan * N_COL)) * 100.; // percentage of successful threshold extractions if (status < mPercentageCut && (mScanType == 'I' || mScanType == 'V')) { if (mScanType == 'I') { // default ITHR if percentage of success < mPercentageCut outVal = 50.; @@ -1822,6 +1852,7 @@ void ITSThresholdCalibrator::finalize() } std::vector data = {outVal, rmsT, avgN, rmsN, status}; this->addDatabaseEntry(it->first, name, data, false); + isChipDB[it->first] = true; it = this->mThresholds.erase(it); } } else if (this->mScanType == 'D' || this->mScanType == 'A') { @@ -1831,7 +1862,7 @@ void ITSThresholdCalibrator::finalize() auto itchip = this->mPixelHits.cbegin(); while (itchip != this->mPixelHits.cend()) { // loop over chips collected short int iRU = getRUID(itchip->first); - if (!isCRUITS && (mRunTypeRU[iRU] < nInjScaled * getNumberOfActiveLinks(mActiveLinks[iRU]) && !mRunStopRequested)) { + if (!isCRUITS && !mFlagsRU[iRU] && !mRunStopRequested) { ++itchip; continue; } @@ -1845,7 +1876,7 @@ void ITSThresholdCalibrator::finalize() if (this->mVerboseOutput) { LOG(info) << "Chip " << itchip->first << " hits extracted"; } - ++itchip; + itchip = mPixelHits.erase(itchip); } auto it = this->mNoisyPixID.cbegin(); @@ -1886,7 +1917,7 @@ void ITSThresholdCalibrator::finalize() auto itchip = this->mPixelHits.cbegin(); while (itchip != mPixelHits.cend()) { int iRU = getRUID(itchip->first); - if (!mRunStopRequested && mRunTypeRU[iRU] < nInjScaled * getNumberOfActiveLinks(mActiveLinks[iRU])) { + if (!mRunStopRequested && !mFlagsRU[iRU]) { ++itchip; continue; } @@ -1909,15 +1940,11 @@ void ITSThresholdCalibrator::finalize() if (this->mVerboseOutput) { LOG(info) << "Chip " << itchip->first << " hits extracted"; } - ++itchip; + itchip = mPixelHits.erase(itchip); } // reset RU counters so that the chips which are done will not appear again in the DCSConfigObject } - for (auto& ru : thisRUs) { - mRunTypeRU[ru] = 0; // reset - } - return; } @@ -1996,6 +2023,7 @@ DataProcessorSpec getITSThresholdCalibratorSpec(const ITSCalibInpConf& inpConf) {"manual-step2", VariantType::Int, 1, {"Step2 value: defines the steps between manual-min2 and manual-max2. Default is 1. Use only in manual mode"}}, {"manual-scantype", VariantType::String, "T", {"scan type, can be D, T, I, V, P, p: use only in manual mode"}}, {"manual-strobewindow", VariantType::Int, 5, {"strobe duration in clock cycles, default is 5 = 125 ns: use only in manual mode"}}, + {"manual-rowscan", VariantType::Int, 512, {"Number of ALPIDE rows scanned in the run: use only in manual mode"}}, {"save-tree", VariantType::Bool, false, {"Flag to save ROOT tree on disk: use only in manual mode"}}, {"scale-ninj", VariantType::Bool, false, {"Flag to activate the scale of the number of injects to be used to count hits from specific MEBs: use only in manual mode and in combination with --meb-select"}}, {"enable-mpv", VariantType::Bool, false, {"Flag to enable calculation of most-probable value in vcasn/ithr scans"}}, From 96a75da2b406e1e64bb5cc5cbe04eef871697662 Mon Sep 17 00:00:00 2001 From: iravasen Date: Tue, 21 Oct 2025 13:44:46 +0200 Subject: [PATCH 2/4] clang format applied --- .../ITSWorkflow/ThresholdCalibratorSpec.h | 6 +- .../workflow/src/ThresholdCalibratorSpec.cxx | 63 +++++++++---------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h index 45ae5269750b9..8913bfa9c4912 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h @@ -233,8 +233,8 @@ class ITSThresholdCalibrator : public Task short int mRunTypeRU[N_RU] = {0}; short int mRunTypeRUCopy[N_RU] = {0}; bool mFlagsRU[N_RU] = {0}; - //short int mCdwCntRU[N_RU][N_ROW] = {{0}}; - std::map, 500>>> mCdwCntRU; // RU --> row --> 2D hit map + // short int mCdwCntRU[N_RU][N_ROW] = {{0}}; + std::map, 500>>> mCdwCntRU; // RU --> row --> 2D hit map short int mLoopVal[N_RU][N_ROW] = {{0}}; bool mActiveLinks[N_RU][3] = {{false}}; std::set mRuSet; @@ -243,7 +243,7 @@ class ITSThresholdCalibrator : public Task short int mMin = -1, mMax = -1, mMin2 = 0, mMax2 = 0; short int mStep = 1, mStep2 = 1; short int mStrobeWindow = 5; // 5 means 5*25ns = 125 ns - short int mRowScan = 512; // number of scanned rows, used only to normalize % of success + short int mRowScan = 512; // number of scanned rows, used only to normalize % of success // Get threshold method (fit == 1, derivative == 0, or hitcounting == 2) char mFitType = -1; diff --git a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx index f70db2147ecf2..573fe9bd0f514 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx @@ -154,7 +154,7 @@ void ITSThresholdCalibrator::init(InitContext& ic) } catch (std::exception const& e) { throw std::runtime_error("Number of scanned rows not found, mandatory in manual mode"); } - + try { manualMin = ic.options().get("manual-min"); } catch (std::exception const& e) { @@ -754,7 +754,7 @@ void ITSThresholdCalibrator::extractThresholdRow(const short int& chipID, const for (int scan_i = 0; scan_i < ((mScanType == 'r') ? N_RANGE : N_RANGE2); scan_i++) { #ifdef WITH_OPENMP - omp_set_num_threads(mNThreads); + omp_set_num_threads(mNThreads); #pragma omp parallel for schedule(dynamic) #endif // Loop over all columns (pixels) in the row @@ -801,8 +801,8 @@ void ITSThresholdCalibrator::extractThresholdRow(const short int& chipID, const // Saves threshold information to internal memory if (mScanType != 'P' && mScanType != 'p' && mScanType != 't' && mScanType != 'R' && mScanType != 'r') { - if(mVerboseOutput) { - LOG(info)<<"Saving data of ChipID: "<saveThreshold(); } @@ -965,9 +965,9 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) mRowScan = 11; if (runtype == THR_SCAN_SHORT_33) { mRowScan = 33; - } else if(runtype == THR_SCAN_SHORT_2_10HZ){ + } else if (runtype == THR_SCAN_SHORT_2_10HZ) { mRowScan = 2; - } + } } else if (runtype == VCASN150 || runtype == VCASN100 || runtype == VCASN100_100HZ || runtype == VCASN130 || runtype == VCASNBB) { // VCASN tuning for different target thresholds // Store average VCASN for each chip into CCDB @@ -979,7 +979,7 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) this->mMax = inMaxVcasn; // 80 is the default this->N_RANGE = mMax - mMin + 1; this->mCheckExactRow = true; - mRowScan = 4; + mRowScan = 4; } else if (runtype == ITHR150 || runtype == ITHR100 || runtype == ITHR100_100HZ || runtype == ITHR130) { // ITHR tuning -- average ITHR per chip @@ -991,7 +991,7 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) this->mMax = inMaxIthr; // 100 is the default this->N_RANGE = mMax - mMin + 1; this->mCheckExactRow = true; - mRowScan = 4; + mRowScan = 4; } else if (runtype == DIGITAL_SCAN || runtype == DIGITAL_SCAN_100HZ || runtype == DIGITAL_SCAN_NOMASK) { // Digital scan -- only storing one value per chip, no fit needed @@ -1389,11 +1389,10 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) cwcnt = (short int)(calib.calibCounter); // count injections - short int loopPoint = (loopval - this->mMin) / mStep; - short int chgPoint = (realcharge - this->mMin2) / mStep2; - auto &arr = mCdwCntRU[iRU][row]; - arr[chgPoint][loopPoint]++; - + short int loopPoint = (loopval - this->mMin) / mStep; + short int chgPoint = (realcharge - this->mMin2) / mStep2; + auto& arr = mCdwCntRU[iRU][row]; + arr[chgPoint][loopPoint]++; if (this->mVerboseOutput) { LOG(info) << "RU: " << iRU << " CDWcounter: " << cwcnt << " row: " << row << " Loopval: " << loopval << " realcharge: " << realcharge << " confDBv: " << mCdwVersion; @@ -1489,7 +1488,7 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) if (ruIndex < 0) { continue; } - short int nL = ruIndex > 47 ? 2 : 3; // total number of links per RU + short int nL = ruIndex > 47 ? 2 : 3; // total number of links per RU std::vector chipEnabled = getChipListFromRu(ruIndex, mActiveLinks[ruIndex]); // chip boundaries // Fill the chipDone info string if (mRunTypeRUCopy[ruIndex] == nInjScaled * nL) { @@ -1502,27 +1501,27 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) mRunTypeRUCopy[ruIndex] = 0; // reset here is safer (the other counter is reset in finalize) } // Check if scan of a row is finished: only for specific scans! - bool passCondition = true; - for(int j1=0; j1 < N_RANGE2; j1++) { - for(int j2=0; j2 < N_RANGE; j2++) { - if(mScanType == 't') { // ToT scan is done in specific ranges depending on charge (see ITSComm) - if ((j1 == 0 && j2<((600-mMin)/mStep)) || (j2>=((600-mMin)/mStep) && j2<=((800-mMin)/mStep)) || (j1==1 && j2>((800-mMin)/mStep))) { - if(mCdwCntRU[ruIndex][row][j1][j2] < nInjScaled * nL) { - passCondition = false; - break; - } - } - } else if(mCdwCntRU[ruIndex][row][j1][j2] < nInjScaled * nL) { + bool passCondition = true; + for (int j1 = 0; j1 < N_RANGE2; j1++) { + for (int j2 = 0; j2 < N_RANGE; j2++) { + if (mScanType == 't') { // ToT scan is done in specific ranges depending on charge (see ITSComm) + if ((j1 == 0 && j2 < ((600 - mMin) / mStep)) || (j2 >= ((600 - mMin) / mStep) && j2 <= ((800 - mMin) / mStep)) || (j1 == 1 && j2 > ((800 - mMin) / mStep))) { + if (mCdwCntRU[ruIndex][row][j1][j2] < nInjScaled * nL) { + passCondition = false; + break; + } + } + } else if (mCdwCntRU[ruIndex][row][j1][j2] < nInjScaled * nL) { passCondition = false; - break; - } + break; + } } - if(!passCondition){ + if (!passCondition) { break; } } if (mVerboseOutput) { - LOG(info) << "PassCondition: " << passCondition << " - mCdwCntRU of RU" << ruIndex << " row " << row << " = " << mCdwCntRU[ruIndex][row][0][0] << "(Links: "<= nInjScaled * nL && passCondition) { + if (mRunTypeRU[ruIndex] >= nInjScaled * nL && passCondition) { mFlagsRU[ruIndex] = true; finalize(); LOG(info) << "Shipping all outputs to aggregator (before endOfStream arrival!)"; @@ -1834,7 +1833,7 @@ void ITSThresholdCalibrator::finalize() } if (mVerboseOutput) { LOG(info) << "Average or mpv " << name << " of chip " << it->first << " = " << outVal << " e-"; - } + } float status = ((float)it->second[4] / (float)(mRowScan * N_COL)) * 100.; // percentage of successful threshold extractions if (status < mPercentageCut && (mScanType == 'I' || mScanType == 'V')) { if (mScanType == 'I') { // default ITHR if percentage of success < mPercentageCut @@ -2023,7 +2022,7 @@ DataProcessorSpec getITSThresholdCalibratorSpec(const ITSCalibInpConf& inpConf) {"manual-step2", VariantType::Int, 1, {"Step2 value: defines the steps between manual-min2 and manual-max2. Default is 1. Use only in manual mode"}}, {"manual-scantype", VariantType::String, "T", {"scan type, can be D, T, I, V, P, p: use only in manual mode"}}, {"manual-strobewindow", VariantType::Int, 5, {"strobe duration in clock cycles, default is 5 = 125 ns: use only in manual mode"}}, - {"manual-rowscan", VariantType::Int, 512, {"Number of ALPIDE rows scanned in the run: use only in manual mode"}}, + {"manual-rowscan", VariantType::Int, 512, {"Number of ALPIDE rows scanned in the run: use only in manual mode"}}, {"save-tree", VariantType::Bool, false, {"Flag to save ROOT tree on disk: use only in manual mode"}}, {"scale-ninj", VariantType::Bool, false, {"Flag to activate the scale of the number of injects to be used to count hits from specific MEBs: use only in manual mode and in combination with --meb-select"}}, {"enable-mpv", VariantType::Bool, false, {"Flag to enable calculation of most-probable value in vcasn/ithr scans"}}, From caf7cc428cfb83d4259c50538caab35c11e3af0d Mon Sep 17 00:00:00 2001 From: iravasen Date: Thu, 23 Oct 2025 18:31:51 +0200 Subject: [PATCH 3/4] added compatibility with P2 operations where links/EPN are fixed --- .../ITSWorkflow/ThresholdCalibratorSpec.h | 5 +- .../workflow/src/ThresholdCalibratorSpec.cxx | 49 ++++++++++++++++--- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h index 8913bfa9c4912..a768b848c7095 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h @@ -175,6 +175,7 @@ class ITSThresholdCalibrator : public Task unsigned char vCharge[N_COL]; unsigned char vHits[N_COL]; short int mColStep = 8; // save s-curves to tree every mColStep pixels on 1 row + short int mRowStep = 1; // Initialize pointers for doing error function fits TH1F* mFitHist = nullptr; @@ -233,7 +234,6 @@ class ITSThresholdCalibrator : public Task short int mRunTypeRU[N_RU] = {0}; short int mRunTypeRUCopy[N_RU] = {0}; bool mFlagsRU[N_RU] = {0}; - // short int mCdwCntRU[N_RU][N_ROW] = {{0}}; std::map, 500>>> mCdwCntRU; // RU --> row --> 2D hit map short int mLoopVal[N_RU][N_ROW] = {{0}}; bool mActiveLinks[N_RU][3] = {{false}}; @@ -328,6 +328,9 @@ class ITSThresholdCalibrator : public Task // Percentage cut for VCASN/ITHR scans short int mPercentageCut = 25; // default, at least 1 good row equivalent + + // For data replay only + short int isLocal = false; }; // Create a processor spec diff --git a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx index 573fe9bd0f514..f2cd946dd8843 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx @@ -74,6 +74,8 @@ void ITSThresholdCalibrator::init(InitContext& ic) LOG(warning) << "mColStep = " << mColStep << ": saving s-curves of only 1 pixel (pix 0) per row"; } + isLocal = ic.options().get("local"); + std::string fittype = ic.options().get("fittype"); if (fittype == "derivative") { this->mFitType = DERIVATIVE; @@ -1002,6 +1004,7 @@ void ITSThresholdCalibrator::setRunType(const short int& runtype) this->mMax = 0; this->N_RANGE = mMax - mMin + 1; this->mCheckExactRow = false; + mRowStep = 1; } else if (runtype == ANALOGUE_SCAN) { // Analogue scan -- only storing one value per chip, no fit needed @@ -1488,10 +1491,13 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) if (ruIndex < 0) { continue; } - short int nL = ruIndex > 47 ? 2 : 3; // total number of links per RU + short int nL = getNumberOfActiveLinks(mActiveLinks[ruIndex]); + if (isLocal) { + nL = ruIndex > 47 ? 2 : 3; + } std::vector chipEnabled = getChipListFromRu(ruIndex, mActiveLinks[ruIndex]); // chip boundaries // Fill the chipDone info string - if (mRunTypeRUCopy[ruIndex] == nInjScaled * nL) { + if (mRunTypeRUCopy[ruIndex] == nInjScaled * nL && nL > 0) { for (short int iChip = 0; iChip < chipEnabled.size(); iChip++) { if ((chipEnabled[iChip] % mChipModBase) != mChipModSel) { continue; @@ -1501,10 +1507,20 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) mRunTypeRUCopy[ruIndex] = 0; // reset here is safer (the other counter is reset in finalize) } // Check if scan of a row is finished: only for specific scans! - bool passCondition = true; + bool passCondition = nL > 0 ? true : false; for (int j1 = 0; j1 < N_RANGE2; j1++) { for (int j2 = 0; j2 < N_RANGE; j2++) { - if (mScanType == 't') { // ToT scan is done in specific ranges depending on charge (see ITSComm) + if (mScanType == 'D' || mScanType == 'A') { // D and A are processed in finalize and include >1 rows: row data can be mixed in time! + for (int ir = 0; ir < mRowScan; ir += mRowStep) { + if (!mCdwCntRU[ruIndex].count(ir)) { + passCondition = false; + break; + } else if (mCdwCntRU[ruIndex][ir][j1][j2] < nInjScaled * nL) { + passCondition = false; + break; + } + } + } else if (mScanType == 't') { // ToT scan is done in specific ranges depending on charge (see ITSComm) if ((j1 == 0 && j2 < ((600 - mMin) / mStep)) || (j2 >= ((600 - mMin) / mStep) && j2 <= ((800 - mMin) / mStep)) || (j1 == 1 && j2 > ((800 - mMin) / mStep))) { if (mCdwCntRU[ruIndex][row][j1][j2] < nInjScaled * nL) { passCondition = false; @@ -1548,6 +1564,19 @@ void ITSThresholdCalibrator::run(ProcessingContext& pc) if (mRunTypeRU[ruIndex] >= nInjScaled * nL && passCondition) { mFlagsRU[ruIndex] = true; finalize(); + // Reset Active Links, mRunTypeRU, mFlagsRU (needed only for local data replay!) + if (mVerboseOutput) { + LOG(info) << "Resetting links of RU " << ruIndex; + } + if (!isLocal) { + mActiveLinks[ruIndex][0] = 0; + mActiveLinks[ruIndex][1] = 0; + mActiveLinks[ruIndex][2] = 0; + mRunTypeRU[ruIndex] = 0; + mFlagsRU[ruIndex] = false; + mCdwCntRU.erase(ruIndex); // for D,A,P,R (not entering the if above) + } + LOG(info) << "Shipping all outputs to aggregator (before endOfStream arrival!)"; pc.outputs().snapshot(Output{"ITS", "TSTR", (unsigned int)mChipModSel}, this->mTuning); pc.outputs().snapshot(Output{"ITS", "PIXTYP", (unsigned int)mChipModSel}, this->mPixStat); @@ -1810,6 +1839,7 @@ void ITSThresholdCalibrator::finalize() } std::vector data = {50, 0, 0, 0, 0}; addDatabaseEntry(chipList[i], name, data, false); + isChipDB[chipList[i]] = true; } } } @@ -1954,9 +1984,9 @@ void ITSThresholdCalibrator::endOfStream(EndOfStreamContext& ec) { if (!isEnded && !mRunStopRequested) { LOGF(info, "endOfStream report:", mSelfName); - if (isCRUITS) { - finalize(); - } + LOG(info) << "Calling finalize(), doing nothing if scan has properly ended, otherwise save partial data in ROOT trees as backup"; + finalize(); + this->finalizeOutput(); isEnded = true; } @@ -1969,6 +1999,8 @@ void ITSThresholdCalibrator::stop() { if (!isEnded) { LOGF(info, "stop() report:", mSelfName); + LOG(info) << "Calling finalize(), doing nothing if scan has properly ended, otherwise save partial data in ROOT trees as backup"; + finalize(); this->finalizeOutput(); isEnded = true; } @@ -2036,7 +2068,8 @@ DataProcessorSpec getITSThresholdCalibratorSpec(const ITSCalibInpConf& inpConf) {"charge-b", VariantType::Int, 0, {"To use with --calculate-slope, it defines the charge (in DAC) for the 2nd point used for the slope calculation"}}, {"meb-select", VariantType::Int, -1, {"Select from which multi-event buffer consider the hits: 0,1 or 2"}}, {"s-curve-col-step", VariantType::Int, 8, {"save s-curves points to tree every s-curve-col-step pixels on 1 row"}}, - {"percentage-cut", VariantType::Int, 25, {"discard chip in ITHR/VCASN scan if the percentage of success is less than this cut"}}}}; + {"percentage-cut", VariantType::Int, 25, {"discard chip in ITHR/VCASN scan if the percentage of success is less than this cut"}}, + {"local", VariantType::Bool, false, {"Enable in case of data replay of scans processed row by row or in 1 go in finalize() but with partial data in the raw TF (e.g. data dump stopped before the real end of run)"}}}}; } } // namespace its } // namespace o2 From 3faed7d74d41d3fd7af3350282712283cdea8bee Mon Sep 17 00:00:00 2001 From: iravasen Date: Fri, 24 Oct 2025 17:37:12 +0200 Subject: [PATCH 4/4] dummy commit to retrigger tests --- Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx index f2cd946dd8843..0a08841059d63 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx @@ -1307,7 +1307,7 @@ void ITSThresholdCalibrator::extractAndUpdate(const short int& chipID, const sho return; } -////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// // Main running function // Get info from previous stf decoder workflow, then loop over readout frames // (ROFs) to count hits and extract thresholds