29double erf(
double* xx,
double* par)
37 return (
nInjScaled / 2) * (1 - TMath::Erf((xx[0] - par[0]) / (sqrt(2) * par[1])));
43 : mChipModSel(inpConf.chipModSel), mChipModBase(inpConf.chipModBase)
57 if (this->mFitType ==
FIT) {
58 delete this->mFitHist;
59 this->mFitHist =
nullptr;
60 delete this->mFitFunction;
61 this->mFitFunction =
nullptr;
68 LOGF(info,
"ITSThresholdCalibrator init...", mSelfName);
70 mPercentageCut = ic.
options().
get<
short int>(
"percentage-cut");
72 mColStep = ic.
options().
get<
short int>(
"s-curve-col-step");
73 if (mColStep >= N_COL) {
74 LOG(warning) <<
"mColStep = " << mColStep <<
": saving s-curves of only 1 pixel (pix 0) per row";
79 std::string fittype = ic.
options().
get<std::string>(
"fittype");
80 if (fittype ==
"derivative") {
83 }
else if (fittype ==
"fit") {
86 }
else if (fittype ==
"hitcounting") {
90 LOG(error) <<
"fittype " << fittype
91 <<
" not recognized, please use 'derivative', 'fit', or 'hitcounting'";
97 this->mMetafileDir = ic.
options().
get<std::string>(
"meta-output-dir");
98 }
catch (std::exception
const& e) {
99 LOG(warning) <<
"Input parameter meta-output-dir not found"
100 <<
"\n*** Setting metafile output directory to /dev/null";
102 if (this->mMetafileDir !=
"/dev/null") {
108 this->mOutputDir = ic.
options().
get<std::string>(
"output-dir");
109 }
catch (std::exception
const& e) {
110 LOG(warning) <<
"Input parameter output-dir not found"
111 <<
"\n*** Setting ROOT output directory to ./";
117 this->mMetaType = ic.
options().
get<std::string>(
"meta-type");
118 }
catch (std::exception
const& e) {
119 LOG(warning) <<
"Input parameter meta-type not found"
120 <<
"\n*** Disabling 'type' in metadata output files";
123 this->mVerboseOutput = ic.
options().
get<
bool>(
"verbose");
126 this->mNThreads = ic.
options().
get<
int>(
"nthreads");
129 if (mFitType ==
FIT && mNThreads > 1) {
130 throw std::runtime_error(
"Multiple threads are requested with fit method which is not thread safe");
134 this->mHostname = boost::asio::ip::host_name();
137 this->mTagSinglePix = ic.
options().
get<
bool>(
"enable-single-pix-tag");
140 inMinVcasn = ic.
options().
get<
short int>(
"min-vcasn");
141 inMaxVcasn = ic.
options().
get<
short int>(
"max-vcasn");
142 inMinIthr = ic.
options().
get<
short int>(
"min-ithr");
143 inMaxIthr = ic.
options().
get<
short int>(
"max-ithr");
144 if (inMinVcasn > inMaxVcasn || inMinIthr > inMaxIthr) {
145 throw std::runtime_error(
"Min VCASN/ITHR is larger than Max VCASN/ITHR: check the settings, analysis not possible");
152 isManualMode = ic.
options().
get<
bool>(
"manual-mode");
155 manualRowScan = ic.
options().
get<
short int>(
"manual-rowscan");
156 }
catch (std::exception
const& e) {
157 throw std::runtime_error(
"Number of scanned rows not found, mandatory in manual mode");
161 manualMin = ic.
options().
get<
short int>(
"manual-min");
162 }
catch (std::exception
const& e) {
163 throw std::runtime_error(
"Min value of the scan parameter not found, mandatory in manual mode");
167 manualMax = ic.
options().
get<
short int>(
"manual-max");
168 }
catch (std::exception
const& e) {
169 throw std::runtime_error(
"Max value of the scan parameter not found, mandatory in manual mode");
173 manualScanType = ic.
options().
get<std::string>(
"manual-scantype");
174 }
catch (std::exception
const& e) {
175 throw std::runtime_error(
"Scan type not found, mandatory in manual mode");
179 saveTree = ic.
options().
get<
bool>(
"save-tree");
180 }
catch (std::exception
const& e) {
181 throw std::runtime_error(
"Please specify if you want to save the ROOT trees, mandatory in manual mode");
185 manualStep = ic.
options().
get<
short int>(
"manual-step");
188 manualMin2 = ic.
options().
get<
short int>(
"manual-min2");
191 manualMax2 = ic.
options().
get<
short int>(
"manual-max2");
194 manualStep2 = ic.
options().
get<
short int>(
"manual-step2");
197 manualStrobeWindow = ic.
options().
get<
short int>(
"manual-strobewindow");
200 scaleNinj = ic.
options().
get<
bool>(
"scale-ninj");
204 isCRUITS = ic.
options().
get<
bool>(
"enable-cru-its");
211 this->mCcdbMgrUrl = ic.
options().
get<std::string>(
"ccdb-mgr-url");
214 LOG(info) <<
"Getting confDB map from ccdb - timestamp: " << ts;
216 mgr.setURL(mCcdbMgrUrl);
217 mgr.setTimestamp(ts);
218 mConfDBmap = mgr.get<std::vector<int>>(
"ITS/Calib/Confdbmap");
221 isDumpS = ic.
options().
get<
bool>(
"dump-scurves");
223 chipDumpS = ic.
options().
get<std::string>(
"chip-dump");
224 chipDumpList = getIntegerVect(chipDumpS);
225 if (isDumpS && mFitType !=
FIT) {
226 LOG(error) <<
"S-curve dump enabled but `fittype` is not fit. Please check";
229 fileDumpS = TFile::Open(Form(
"s-curves_%d.root", mChipModSel),
"RECREATE");
231 LOG(info) <<
"`max-dump` " << maxDumpS <<
". Dumping all s-curves";
233 LOG(info) <<
"`max-dump` " << maxDumpS <<
". Dumping " << maxDumpS <<
" s-curves";
235 if (!chipDumpList.size()) {
236 LOG(info) <<
"Dumping s-curves for all chips";
238 LOG(info) <<
"Dumping s-curves for chips: " << chipDumpS;
243 doSlopeCalculation = ic.
options().
get<
bool>(
"calculate-slope");
244 if (doSlopeCalculation) {
247 }
catch (std::exception
const& e) {
248 throw std::runtime_error(
"You want to do the slop calculation but you did not specify charge-a");
253 }
catch (std::exception
const& e) {
254 throw std::runtime_error(
"You want to do the slop calculation but you did not specify charge-b");
261 LOG(error) <<
"MEB cannot be greater than 2. Please check your command line.";
269short int ITSThresholdCalibrator::getNumberOfActiveLinks(
bool* links)
272 for (
int i = 0;
i < 3;
i++) {
282short int ITSThresholdCalibrator::getLinkID(
short int chipID,
short int ruID)
285 return (chipID - ruID * 9) / 3;
286 }
else if (chipID >= 432 && chipID < 6480) {
287 return (chipID - 48 * 9 - (ruID - 48) * 112) / 56;
289 return (chipID - 48 * 9 - 54 * 112 - (ruID - 102) * 196) / 98;
295std::vector<short int> ITSThresholdCalibrator::getChipListFromRu(
short int ruID,
bool* links)
297 std::vector<short int> cList;
302 }
else if (ruID >= 48 && ruID < 102) {
303 a = 48 * 9 + (ruID - 48) * 112;
306 a = 48 * 9 + 54 * 112 + (ruID - 102) * 196;
310 for (
int c =
a;
c <=
b;
c++) {
311 short int lid = getLinkID(
c, ruID);
322short int ITSThresholdCalibrator::getRUID(
short int chipID)
327 }
else if (chipID >= 432 && chipID < 6480) {
328 return (chipID - 48 * 9 + 112 * 48) / 112;
330 return (chipID - 48 * 9 - 54 * 112 + 102 * 196) / 196;
336std::vector<short int> ITSThresholdCalibrator::getIntegerVect(std::string& s)
338 std::stringstream ss(s);
339 std::vector<short int>
result;
351void ITSThresholdCalibrator::initThresholdTree(
bool recreate )
355 std::string dir = this->mOutputDir + fmt::format(
"{}_{}/", mDataTakingContext.
envId, mDataTakingContext.
runNumber);
357 LOG(info) <<
"Created " << dir <<
" directory for ROOT trees output";
365 LOG(warning) <<
"File " <<
filename <<
" already exists, recreating";
370 const char* option = recreate ?
"RECREATE" :
"UPDATE";
371 mRootOutfile =
new TFile(
filename.c_str(), option);
374 mScTree =
new TTree(
"s-curve-points",
"s-curve-points");
375 mScTree->Branch(
"chipid", &vChipid,
"vChipID[1024]/S");
376 mScTree->Branch(
"row", &vRow,
"vRow[1024]/S");
379 mThresholdTree =
new TTree(
"ITS_calib_tree",
"ITS_calib_tree");
380 mThresholdTree->Branch(
"chipid", &vChipid,
"vChipID[1024]/S");
381 mThresholdTree->Branch(
"row", &vRow,
"vRow[1024]/S");
382 if (mScanType ==
'T' || mScanType ==
'V' || mScanType ==
'I') {
383 std::string bName = mScanType ==
'T' ?
"thr" : mScanType ==
'V' ?
"vcasn"
385 mThresholdTree->Branch(bName.c_str(), &vThreshold,
"vThreshold[1024]/S");
386 mThresholdTree->Branch(
"noise", &vNoise,
"vNoise[1024]/F");
387 mThresholdTree->Branch(
"spoints", &vPoints,
"vPoints[1024]/b");
388 mThresholdTree->Branch(
"success", &vSuccess,
"vSuccess[1024]/O");
390 mScTree->Branch(
"chg", &vCharge,
"vCharge[1024]/b");
391 mScTree->Branch(
"hits", &vHits,
"vHits[1024]/b");
392 }
else if (mScanType ==
'D' || mScanType ==
'A') {
393 mThresholdTree->Branch(
"n_hits", &vThreshold,
"vThreshold[1024]/S");
394 }
else if (mScanType ==
'P') {
395 mThresholdTree->Branch(
"n_hits", &vThreshold,
"vThreshold[1024]/S");
396 mThresholdTree->Branch(
"strobedel", &vMixData,
"vMixData[1024]/S");
397 }
else if (mScanType ==
'p' || mScanType ==
't') {
398 mThresholdTree->Branch(
"n_hits", &vThreshold,
"vThreshold[1024]/S");
399 mThresholdTree->Branch(
"strobedel", &vMixData,
"vMixData[1024]/S");
400 mThresholdTree->Branch(
"charge", &vCharge,
"vCharge[1024]/b");
401 if (doSlopeCalculation) {
402 mSlopeTree =
new TTree(
"line_tree",
"line_tree");
403 mSlopeTree->Branch(
"chipid", &vChipid,
"vChipID[1024]/S");
404 mSlopeTree->Branch(
"row", &vRow,
"vRow[1024]/S");
405 mSlopeTree->Branch(
"slope", &vSlope,
"vSlope[1024]/F");
406 mSlopeTree->Branch(
"intercept", &vIntercept,
"vIntercept[1024]/F");
408 }
else if (mScanType ==
'R') {
409 mThresholdTree->Branch(
"n_hits", &vThreshold,
"vThreshold[1024]/S");
410 mThresholdTree->Branch(
"vresetd", &vMixData,
"vMixData[1024]/S");
411 }
else if (mScanType ==
'r') {
412 mThresholdTree->Branch(
"thr", &vThreshold,
"vThreshold[1024]/S");
413 mThresholdTree->Branch(
"noise", &vNoise,
"vNoise[1024]/F");
414 mThresholdTree->Branch(
"success", &vSuccess,
"vSuccess[1024]/O");
415 mThresholdTree->Branch(
"vresetd", &vMixData,
"vMixData[1024]/S");
426bool ITSThresholdCalibrator::findUpperLower(
427 std::vector<std::vector<unsigned short int>>
data,
const short int& NPoints,
428 short int& lower,
short int& upper,
bool flip,
int iloop2)
436 for (
int i = 0;
i < NPoints;
i++) {
437 int comp = mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2];
447 for (
int i = upper;
i > 0;
i--) {
448 int comp = mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2];
457 for (
int i = 0;
i < NPoints;
i++) {
458 int comp = mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2];
468 for (
int i = upper;
i > 0;
i--) {
469 int comp = mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2];
478 if ((lower == -1) || (upper < lower)) {
486bool ITSThresholdCalibrator::findThreshold(
487 const short int& chipID, std::vector<std::vector<unsigned short int>>
data,
const float*
x,
short int& NPoints,
488 float& thresh,
float& noise,
int& spoints,
int iloop2)
490 bool success =
false;
492 switch (this->mFitType) {
494 success = this->findThresholdDerivative(
data,
x, NPoints, thresh, noise, spoints, iloop2);
498 success = this->findThresholdFit(chipID,
data,
x, NPoints, thresh, noise, spoints, iloop2);
502 success = this->findThresholdHitcounting(
data,
x, NPoints, thresh, iloop2);
518bool ITSThresholdCalibrator::findThresholdFit(
519 const short int& chipID, std::vector<std::vector<unsigned short int>>
data,
const float*
x,
const short int& NPoints,
520 float& thresh,
float& noise,
int& spoints,
int iloop2)
523 short int lower, upper;
524 bool flip = (this->mScanType ==
'I');
525 auto fndVal = std::find(chipDumpList.begin(), chipDumpList.end(), chipID);
527 if (!this->findUpperLower(
data, NPoints, lower, upper, flip, iloop2) || lower == upper) {
528 if (this->mVerboseOutput) {
529 LOG(warning) <<
"Start-finding unsuccessful: (lower, upper) = ("
530 << lower <<
", " << upper <<
")";
533 if (isDumpS && (dumpCounterS[chipID] < maxDumpS || maxDumpS < 0) && (fndVal != chipDumpList.end() || !chipDumpList.size())) {
534 for (
int i = 0;
i < NPoints;
i++) {
535 this->mFitHist->SetBinContent(
i + 1, mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2]);
541 dumpCounterS[chipID]++;
546 float start = (this->mX[upper] + this->mX[lower]) / 2;
549 if (this->mVerboseOutput) {
550 LOG(warning) <<
"Start-finding unsuccessful: Start = " <<
start;
555 for (
int i = 0;
i < NPoints;
i++) {
556 this->mFitHist->SetBinContent(
i + 1, mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2]);
560 this->mFitFunction->SetParameter(0,
start);
561 this->mFitFunction->SetParameter(1, 8);
563 this->mFitHist->Fit(
"mFitFunction",
"RQL");
564 if (isDumpS && (dumpCounterS[chipID] < maxDumpS || maxDumpS < 0) && (fndVal != chipDumpList.end() || !chipDumpList.size())) {
569 dumpCounterS[chipID]++;
572 noise = this->mFitFunction->GetParameter(1);
573 thresh = this->mFitFunction->GetParameter(0);
574 float chi2 = this->mFitFunction->GetChisquare() / this->mFitFunction->GetNDF();
575 spoints = upper - lower - 1;
578 this->mFitHist->Reset();
590bool ITSThresholdCalibrator::findThresholdDerivative(std::vector<std::vector<unsigned short int>>
data,
const float*
x,
const short int& NPoints,
591 float& thresh,
float& noise,
int& spoints,
int iloop2)
594 short int lower, upper;
595 bool flip = (this->mScanType ==
'I');
596 if (!this->findUpperLower(
data, NPoints, lower, upper, flip, iloop2) || lower == upper) {
597 if (this->mVerboseOutput) {
598 LOG(warning) <<
"Start-finding unsuccessful: (lower, upper) = (" << lower <<
", " << upper <<
")";
603 int deriv_size = upper - lower;
604 float deriv[deriv_size];
605 float xfx = 0, fx = 0;
608 for (
int i = lower;
i < upper;
i++) {
609 deriv[
i - lower] = std::abs(mScanType !=
'r' ? (
data[iloop2][
i + 1] -
data[iloop2][
i]) : (
data[
i + 1][iloop2] -
data[
i][iloop2])) / (
this->mX[
i + 1] - mX[
i]);
610 xfx += this->mX[
i] * deriv[
i - lower];
611 fx += deriv[
i - lower];
618 for (
int i = lower;
i < upper;
i++) {
619 stddev += std::pow(this->mX[
i] - thresh, 2) * deriv[
i - lower];
623 noise = std::sqrt(stddev);
624 spoints = upper - lower - 1;
635bool ITSThresholdCalibrator::findThresholdHitcounting(
636 std::vector<std::vector<unsigned short int>>
data,
const float*
x,
const short int& NPoints,
float& thresh,
int iloop2)
638 unsigned short int numberOfHits = 0;
640 for (
unsigned short int i = 0;
i < NPoints;
i++) {
641 numberOfHits += (mScanType !=
'r') ?
data[iloop2][
i] :
data[
i][iloop2];
642 int comp = (mScanType !=
'r') ?
data[iloop2][
i] :
data[
i][iloop2];
650 if (this->mVerboseOutput) {
651 LOG(warning) <<
"Calculation unsuccessful: too few hits. Skipping this pixel";
656 if (this->mScanType ==
'T') {
657 thresh = this->mX[N_RANGE - 1] - numberOfHits / float(
nInjScaled);
658 }
else if (this->mScanType ==
'V') {
660 }
else if (this->mScanType ==
'I') {
663 LOG(error) <<
"Unexpected runtype encountered in findThresholdHitcounting()";
672void ITSThresholdCalibrator::extractThresholdRow(
const short int& chipID,
const short int&
row)
674 if (this->mScanType ==
'D' || this->mScanType ==
'A') {
676 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
677 vChipid[col_i] = chipID;
679 vThreshold[col_i] = this->mPixelHits[chipID][
row][col_i][0][0];
680 if (vThreshold[col_i] >
nInj) {
681 this->mNoisyPixID[chipID].push_back(col_i * 1000 +
row);
682 }
else if (vThreshold[col_i] > 0 && vThreshold[col_i] <
nInj) {
683 this->mIneffPixID[chipID].push_back(col_i * 1000 +
row);
684 }
else if (vThreshold[col_i] == 0) {
685 this->mDeadPixID[chipID].push_back(col_i * 1000 +
row);
688 }
else if (this->mScanType ==
'P' || this->mScanType ==
'p' || mScanType ==
'R' || mScanType ==
't') {
690 for (
short int var1_i = 0; var1_i < this->N_RANGE; var1_i++) {
691 for (
short int chg_i = 0; chg_i < this->N_RANGE2; chg_i++) {
692 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
693 vChipid[col_i] = chipID;
695 vThreshold[col_i] = this->mPixelHits[chipID][
row][col_i][chg_i][var1_i];
696 vMixData[col_i] = (var1_i * this->mStep) + mMin;
697 if (mScanType !=
'R') {
700 vCharge[col_i] = (
unsigned char)(chg_i * this->mStep2 + mMin2);
702 this->saveThreshold();
706 if (doSlopeCalculation) {
707 int delA = -1, delB = -1;
708 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
709 for (
short int chg_i = 0; chg_i < 2; chg_i++) {
710 bool isFound =
false;
711 int checkchg = !chg_i ? chargeA / mStep2 : chargeB / mStep2;
712 for (
short int sdel_i = N_RANGE - 1; sdel_i >= 0; sdel_i--) {
713 if (mPixelHits[chipID][
row][col_i][checkchg - 1][sdel_i] ==
nInj) {
715 delA = mMin + sdel_i * mStep + mStep / 2;
718 delB = mMin + sdel_i * mStep + mStep / 2;
726 for (
short int sdel_i = 0; sdel_i < N_RANGE; sdel_i++) {
727 if (mPixelHits[chipID][
row][col_i][checkchg - 1][sdel_i] > 0) {
729 delA = mMin + sdel_i * mStep + mStep / 2;
731 delB = mMin + sdel_i * mStep + mStep / 2;
739 if (delA > 0 && delB > 0 && delA != delB) {
740 vSlope[col_i] = ((float)(chargeA - chargeB) / (float)(delA - delB));
741 vIntercept[col_i] = (float)chargeA - (
float)(vSlope[col_i] * delA);
742 if (vSlope[col_i] < 0) {
744 vIntercept[col_i] = 0.;
748 vIntercept[col_i] = 0.;
757 for (
int scan_i = 0; scan_i < ((mScanType ==
'r') ? N_RANGE : N_RANGE2); scan_i++) {
759 omp_set_num_threads(mNThreads);
760#pragma omp parallel for schedule(dynamic)
763 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
765 float thresh = 0., noise = 0.;
766 bool success =
false;
770 mFitHist->SetName(Form(
"scurve_chip%d_row%d_col%d_scani%d", chipID,
row, col_i, scan_i));
773 success = this->findThreshold(chipID, mPixelHits[chipID][
row][col_i],
774 this->mX, mScanType ==
'r' ? N_RANGE2 : N_RANGE, thresh, noise, spoints, scan_i);
776 vChipid[col_i] = chipID;
778 vThreshold[col_i] = (mScanType ==
'T' || mScanType ==
'r') ? (
short int)(thresh * 10.) : (short
int)(thresh);
779 vNoise[col_i] = (float)(noise * 10.);
780 vSuccess[col_i] = success;
781 vPoints[col_i] = spoints > 0 ? (
unsigned char)(spoints) : 0;
783 if (mScanType ==
'r') {
784 vMixData[col_i] = (scan_i * mStep) + mMin;
787 if (mScanType ==
'r') {
788 this->saveThreshold();
793 if (mScanType ==
'T' || mScanType ==
'V' || mScanType ==
'I') {
794 for (
int ichg = mMin; ichg <= mMax; ichg += mStep) {
795 for (
short int col_i = 0; col_i < this->N_COL; col_i += mColStep) {
796 vCharge[col_i] = ichg;
797 vHits[col_i] = mPixelHits[chipID][
row][col_i][0][(ichg - mMin) / mStep];
805 if (mScanType !=
'P' && mScanType !=
'p' && mScanType !=
't' && mScanType !=
'R' && mScanType !=
'r') {
806 if (mVerboseOutput) {
807 LOG(info) <<
"Saving data of ChipID: " << chipID <<
" Row: " <<
row;
809 this->saveThreshold();
814void ITSThresholdCalibrator::saveThreshold()
817 this->mThresholdTree->Fill();
819 if (this->mScanType ==
'V' || this->mScanType ==
'I' || this->mScanType ==
'T') {
821 int sumT = 0, sumSqT = 0, sumN = 0, sumSqN = 0;
822 int countSuccess = 0, countUnsuccess = 0;
823 for (
int i = 0;
i < this->N_COL;
i++) {
825 sumT += vThreshold[
i];
826 sumN += (
int)vNoise[
i];
827 sumSqT += (vThreshold[
i]) * (vThreshold[
i]);
828 sumSqN += ((
int)vNoise[
i]) * ((
int)vNoise[
i]);
830 if (vThreshold[
i] >= mMin && vThreshold[
i] <= mMax && (mScanType ==
'I' || mScanType ==
'V')) {
831 mpvCounter[vChipid[0]][vThreshold[
i] - mMin]++;
837 short int chipID = vChipid[0];
838 std::array<long int, 6> dataSum{{sumT, sumSqT, sumN, sumSqN, countSuccess, countUnsuccess}};
839 if (!(this->mThresholds.count(chipID))) {
840 this->mThresholds[chipID] = dataSum;
842 std::array<long int, 6> dataAll{{this->mThresholds[chipID][0] + dataSum[0], this->mThresholds[chipID][1] + dataSum[1], this->mThresholds[chipID][2] + dataSum[2], this->mThresholds[chipID][3] + dataSum[3], this->mThresholds[chipID][4] + dataSum[4], this->mThresholds[chipID][5] + dataSum[5]}};
843 this->mThresholds[chipID] = dataAll;
853void ITSThresholdCalibrator::finalizeOutput()
856 if (!(mScTree) || !(this->mRootOutfile) || !(this->mThresholdTree) || (doSlopeCalculation && !(this->mSlopeTree))) {
861 this->mRootOutfile->cd();
862 this->mThresholdTree->Write(
nullptr, TObject::kOverwrite);
863 this->mScTree->Write(
nullptr, TObject::kOverwrite);
865 if (doSlopeCalculation) {
866 this->mSlopeTree->Write(
nullptr, TObject::kOverwrite);
870 delete this->mThresholdTree;
871 this->mThresholdTree =
nullptr;
874 if (doSlopeCalculation) {
875 delete this->mSlopeTree;
876 this->mSlopeTree =
nullptr;
879 this->mRootOutfile->Close();
880 delete this->mRootOutfile;
881 this->mRootOutfile =
nullptr;
884 std::string dir = this->mOutputDir + fmt::format(
"{}_{}/", mDataTakingContext.
envId, mDataTakingContext.
runNumber);
885 if (!std::filesystem::exists(dir)) {
886 LOG(error) <<
"Cannot find expected output directory " << dir;
893 std::string filenameFull = dir +
filename;
895 std::rename((filenameFull +
".root.part").c_str(),
896 (filenameFull +
".root").c_str());
897 }
catch (std::exception
const& e) {
898 LOG(error) <<
"Failed to rename ROOT file " << filenameFull
899 <<
".root.part, reason: " << e.what();
906 if (!(this->mMetaType.empty())) {
907 mdFile->
type = this->mMetaType;
910 mdFile->
lurl = filenameFull +
".root";
911 auto metaFileNameTmp = fmt::format(
"{}{}.tmp", this->mMetafileDir,
filename);
912 auto metaFileName = fmt::format(
"{}{}.done", this->mMetafileDir,
filename);
914 std::ofstream metaFileOut(metaFileNameTmp);
915 metaFileOut << mdFile->
asString() <<
'\n';
917 std::filesystem::rename(metaFileNameTmp, metaFileName);
918 }
catch (std::exception
const& e) {
919 LOG(error) <<
"Failed to create threshold metadata file "
920 << metaFileName <<
", reason: " << e.what();
934void ITSThresholdCalibrator::setRunType(
const short int& runtype)
938 this->mRunType = runtype;
943 this->mScanType =
'T';
944 this->initThresholdTree();
948 this->mCheckExactRow =
true;
955 this->mScanType =
'T';
956 this->initThresholdTree();
960 this->mCheckExactRow =
true;
978 this->mScanType =
'V';
979 this->initThresholdTree();
980 this->mMin = inMinVcasn;
981 this->mMax = inMaxVcasn;
982 this->N_RANGE = mMax - mMin + 1;
983 this->mCheckExactRow =
true;
990 this->mScanType =
'I';
991 this->initThresholdTree();
992 this->mMin = inMinIthr;
993 this->mMax = inMaxIthr;
994 this->N_RANGE = mMax - mMin + 1;
995 this->mCheckExactRow =
true;
1000 this->mScanType =
'D';
1001 this->initThresholdTree();
1005 this->N_RANGE = mMax - mMin + 1;
1006 this->mCheckExactRow =
false;
1011 this->mScanType =
'A';
1012 this->initThresholdTree();
1016 this->N_RANGE = mMax - mMin + 1;
1017 this->mCheckExactRow =
false;
1021 this->mScanType =
'P';
1022 this->initThresholdTree();
1027 this->mStrobeWindow = 1;
1028 this->N_RANGE = (mMax - mMin) / mStep + 1;
1029 this->mCheckExactRow =
true;
1032 this->mScanType =
'p';
1033 this->initThresholdTree();
1038 this->mStrobeWindow = 10;
1039 this->N_RANGE = (mMax - mMin) / mStep + 1;
1043 this->N_RANGE2 = (mMax2 - mMin2) / mStep2 + 1;
1044 this->mCheckExactRow =
true;
1047 this->mScanType =
't';
1048 this->initThresholdTree();
1053 this->mStrobeWindow = 10;
1054 this->N_RANGE = (mMax - mMin) / mStep + 1;
1058 this->mCalculate2DParams =
false;
1059 this->N_RANGE2 = (mMax2 - mMin2) / mStep2 + 1;
1060 this->mCheckExactRow =
true;
1063 this->mScanType =
'R';
1070 this->N_RANGE = (mMax - mMin) / mStep + 1;
1072 this->mScanType =
'r';
1076 this->N_RANGE2 = (mMax2 - mMin2) / mStep2 + 1;
1078 this->mCheckExactRow =
true;
1079 this->initThresholdTree();
1082 LOG(error) <<
"Runtype " << runtype <<
" not recognized by calibration workflow (ignore if you are in manual mode)";
1084 LOG(info) <<
"Entering manual mode: be sure to have set all parameters correctly";
1085 this->mScanType = manualScanType[0];
1086 this->mMin = manualMin;
1087 this->mMax = manualMax;
1088 this->mMin2 = manualMin2;
1089 this->mMax2 = manualMax2;
1090 this->mStep = manualStep;
1091 this->mStep2 = manualStep2;
1092 this->mStrobeWindow = manualStrobeWindow;
1093 this->N_RANGE = (mMax - mMin) / mStep + 1;
1094 this->N_RANGE2 = (mMax2 - mMin2) / mStep2 + 1;
1096 this->initThresholdTree();
1098 this->mFitType = (mScanType ==
'D' || mScanType ==
'A' || mScanType ==
'P' || mScanType ==
'p' || mScanType ==
't') ?
NO_FIT : mFitType;
1099 this->mCheckExactRow = (mScanType ==
'D' || mScanType ==
'A') ?
false : true;
1103 mRowScan = manualRowScan;
1109 this->mX =
new float[mScanType ==
'r' ? N_RANGE2 : N_RANGE];
1110 for (
short int i = ((mScanType ==
'r') ? mMin2 : mMin);
i <= ((mScanType ==
'r') ? mMax2 / mStep2 : mMax / mStep);
i++) {
1111 this->mX[
i - (mScanType ==
'r' ? mMin2 : mMin)] = (
float)
i + 0.5;
1115 if (this->mFitType ==
FIT) {
1118 this->mFitHist =
new TH1F(
1119 "mFitHist",
"mFitHist", mScanType ==
'r' ? N_RANGE2 : N_RANGE, mX[0] - 1., mX[(mScanType ==
'r' ? N_RANGE2 : N_RANGE) - 1]);
1122 this->mFitFunction = (this->mScanType ==
'I')
1123 ?
new TF1(
"mFitFunction",
erf_ithr, mMin, mMax, 2)
1124 :
new TF1(
"mFitFunction",
erf, (mScanType ==
'T' || mScanType ==
'r') ? 3 : mMin, mScanType ==
'r' ? mMax2 : mMax, 2);
1125 this->mFitFunction->SetParName(0,
"Threshold");
1126 this->mFitFunction->SetParName(1,
"Noise");
1134std::vector<float> ITSThresholdCalibrator::calculatePulseParams(
const short int& chipID)
1137 int tot_mindel = -1, tot_maxdel = -1;
1138 float sumToA = 0., sumSqToA = 0., countToA = 0., sumTot = 0., sumSqTot = 0., countTot = 0.;
1141 for (
auto itrow = mPixelHits[chipID].
begin(); itrow != mPixelHits[chipID].end(); itrow++) {
1142 short int row = itrow->first;
1143 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
1145 for (
short int sdel_i = 0; sdel_i < N_RANGE; sdel_i++) {
1146 if (mPixelHits[chipID][
row][col_i][0][sdel_i] >= 0.5 *
nInj) {
1147 tot_mindel = (sdel_i * mStep) + 1;
1148 toa = (sdel_i * mStep) + 1;
1153 for (
short int sdel_i = N_RANGE - 1; sdel_i >= 0; sdel_i--) {
1154 if (mPixelHits[chipID][
row][col_i][0][sdel_i] >= 0.5 *
nInj) {
1155 tot_maxdel = (sdel_i * mStep) + 1;
1160 if (tot_maxdel > tot_mindel && tot_mindel >= 0 && tot_maxdel >= 0) {
1161 sumTot += tot_maxdel - tot_mindel - mStrobeWindow;
1162 sumSqTot += (tot_maxdel - tot_mindel - mStrobeWindow) * (tot_maxdel - tot_mindel - mStrobeWindow);
1167 sumToA += toa + float(mStrobeWindow) / 2.;
1168 sumSqToA += (toa + float(mStrobeWindow) / 2.) * (toa +
float(mStrobeWindow) / 2.);
1178 std::vector<float>
output;
1180 output.push_back(!countToA ? 0. : (float)sumToA / (float)countToA);
1182 output.push_back(!countToA ? 0. : (
std::sqrt((float)sumSqToA / (float)countToA -
output[0] *
output[0])) * 25.);
1185 output.push_back(!countTot ? 0. : (float)sumTot / (float)countTot);
1187 output.push_back(!countTot ? 0. : (
std::sqrt((float)sumSqTot / (float)countTot -
output[2] *
output[2])) * 25.);
1195std::vector<float> ITSThresholdCalibrator::calculatePulseParams2D(
const short int& chipID)
1197 long int sumTot = 0, sumSqTot = 0, countTot = 0;
1198 long int sumMinThr = 0, sumSqMinThr = 0, countMinThr = 0;
1199 long int sumMinThrDel = 0, sumSqMinThrDel = 0;
1200 long int sumMaxPl = 0, sumSqMaxPl = 0, countMaxPl = 0;
1201 long int sumMaxPlChg = 0, sumSqMaxPlChg = 0;
1203 for (
auto itrow = mPixelHits[chipID].
begin(); itrow != mPixelHits[chipID].end(); itrow++) {
1204 short int row = itrow->first;
1205 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
1206 int minThr = 1e7, minThrDel = 1e7, maxPl = -1, maxPlChg = -1;
1207 int tot_mindel = 1e7;
1208 bool isFound =
false;
1209 for (
short int chg_i = 0; chg_i < this->N_RANGE2; chg_i++) {
1210 for (
short int sdel_i = 0; sdel_i < this->N_RANGE; sdel_i++) {
1211 if (mPixelHits[chipID][
row][col_i][chg_i][sdel_i] ==
nInj) {
1212 minThr = chg_i * mStep2;
1213 minThrDel = (sdel_i * mStep) + 1;
1223 for (
short int sdel_i = this->N_RANGE - 1; sdel_i >= 0; sdel_i--) {
1224 for (
short int chg_i = this->N_RANGE2 - 1; chg_i >= 0; chg_i--) {
1225 if (mPixelHits[chipID][
row][col_i][chg_i][sdel_i] ==
nInj) {
1226 maxPl = (sdel_i * mStep) + 1;
1227 maxPlChg = chg_i * mStep2;
1237 for (
short int sdel_i = 0; sdel_i < this->N_RANGE; sdel_i++) {
1238 for (
short int chg_i = 0; chg_i < this->N_RANGE2; chg_i++) {
1239 if (mPixelHits[chipID][
row][col_i][chg_i][sdel_i] ==
nInj) {
1240 tot_mindel = (sdel_i * mStep) + 1;
1250 if (maxPl > tot_mindel && tot_mindel < 1e7 && maxPl >= 0) {
1251 sumTot += maxPl - tot_mindel - mStrobeWindow;
1252 sumSqTot += (maxPl - tot_mindel - mStrobeWindow) * (maxPl - tot_mindel - mStrobeWindow);
1257 sumMinThr += minThr;
1258 sumSqMinThr += minThr * minThr;
1259 sumMinThrDel += minThrDel;
1260 sumSqMinThrDel += minThrDel * minThrDel;
1266 sumSqMaxPl += maxPl * maxPl;
1267 sumMaxPlChg += maxPlChg;
1268 sumSqMaxPlChg += maxPlChg * maxPlChg;
1275 std::vector<long int>
values = {sumTot, sumSqTot, countTot, sumMinThr, sumSqMinThr, countMinThr, sumMinThrDel, sumSqMinThrDel, countMinThr, sumMaxPl, sumSqMaxPl, countMaxPl, sumMaxPlChg, sumSqMaxPlChg, countMaxPl};
1276 std::vector<float>
output;
1278 for (
int i = 0;
i <
values.size();
i += 3) {
1283 if (
i == 0 ||
i == 6 ||
i == 9) {
1293void ITSThresholdCalibrator::extractAndUpdate(
const short int& chipID,
const short int&
row)
1296 if ((this->mRowCounter)++ == N_ROWS_PER_FILE) {
1298 this->finalizeOutput();
1299 this->initThresholdTree();
1301 this->mRowCounter = 1;
1305 this->extractThresholdRow(chipID,
row);
1316 if (mRunStopRequested) {
1320 updateTimeDependentParams(pc);
1323 const auto calibs = pc.
inputs().
get<gsl::span<o2::itsmft::GBTCalibData>>(
"calib");
1324 const auto digits = pc.
inputs().
get<gsl::span<o2::itsmft::Digit>>(
"digits");
1325 const auto ROFs = pc.
inputs().
get<gsl::span<o2::itsmft::ROFRecord>>(
"digitsROF");
1328 const unsigned int nROF = (
unsigned int)ROFs.size();
1331 for (
unsigned int iROF = 0; iROF < nROF; iROF++) {
1333 unsigned int rofIndex = ROFs[iROF].getFirstEntry();
1334 unsigned int rofNEntries = ROFs[iROF].getNEntries();
1337 short int loopval = -1, realcharge = 0;
1339 short int cwcnt = -1;
1340 bool isAllZero =
true;
1341 short int ruIndex = -1;
1342 for (
short int iRU = 0; iRU < this->N_RU; iRU++) {
1343 const auto& calib = calibs[iROF * this->N_RU + iRU];
1344 if (calib.calibUserField != 0) {
1350 LOG(warning) <<
"More than one charge detected!";
1353 if (this->mRunType == -1) {
1354 mCdwVersion = isCRUITS ? 0 : ((
short int)(calib.calibUserField >> 45)) & 0x7;
1355 LOG(info) <<
"CDW version: " << mCdwVersion;
1356 short int runtype = isCRUITS ? -2 : !mCdwVersion ? ((
short int)(calib.calibUserField >> 24)) & 0xff
1357 : ((
short int)(calib.calibUserField >> 9)) & 0x7f;
1358 mConfDBv = !mCdwVersion ? ((
short int)(calib.calibUserField >> 32)) & 0xffff : ((
short int)(calib.calibUserField >> 32)) & 0x1fff;
1359 this->setRunType(runtype);
1360 LOG(info) <<
"Calibrator will ship these run parameters to aggregator:";
1361 LOG(info) <<
"Run type : " << mRunType;
1362 LOG(info) <<
"Scan type : " << mScanType;
1364 LOG(info) <<
"DB version (ignore in TOT_CALIB & VRESET2D): " << mConfDBv;
1366 this->mRunTypeUp = isCRUITS ? -1 : !mCdwVersion ? ((
short int)(calib.calibUserField >> 24)) & 0xff
1367 : ((
short int)(calib.calibUserField >> 9)) & 0x7f;
1372 mRunTypeRUCopy[iRU]++;
1375 if (this->mScanType ==
'T') {
1377 loopval = isCRUITS ? (
short int)((calib.calibUserField >> 16) & 0xff) : !mCdwVersion ? (
short int)(170 - (calib.calibUserField >> 16) & 0xff)
1378 : (
short int)(170 - (calib.calibUserField >> 16) & 0xffff);
1379 }
else if (this->mScanType ==
'D' || this->mScanType ==
'A') {
1382 loopval = !mCdwVersion ? (
short int)((calib.calibUserField >> 16) & 0xff) : (
short int)((calib.calibUserField >> 16) & 0xffff);
1385 if (this->mScanType ==
'p' || this->mScanType ==
't' || this->mScanType ==
'r') {
1386 realcharge = 170 - ((
short int)(calib.calibUserField >> 32)) & 0x1fff;
1390 row = !mCdwVersion ? (
short int)(calib.calibUserField & 0xffff) : (
short int)(calib.calibUserField & 0x1ff);
1392 cwcnt = (
short int)(calib.calibCounter);
1395 short int loopPoint = (loopval - this->mMin) / mStep;
1396 short int chgPoint = (realcharge - this->mMin2) / mStep2;
1397 auto& arr = mCdwCntRU[iRU][
row];
1398 arr[chgPoint][loopPoint]++;
1400 if (this->mVerboseOutput) {
1401 LOG(info) <<
"RU: " << iRU <<
" CDWcounter: " << cwcnt <<
" row: " <<
row <<
" Loopval: " << loopval <<
" realcharge: " << realcharge <<
" confDBv: " << mCdwVersion;
1402 LOG(info) <<
"NDIGITS: " <<
digits.size();
1409 if (isCRUITS && isAllZero) {
1410 if (mRunType == -1) {
1411 short int runtype = -2;
1413 this->setRunType(runtype);
1414 LOG(info) <<
"Running with CRU_ITS data - Calibrator will ship these run parameters to aggregator:";
1415 LOG(info) <<
"Run type (non-sense) : " << mRunType;
1416 LOG(info) <<
"Scan type : " << mScanType;
1418 LOG(info) <<
"DB version (non-sense): " << mConfDBv;
1426 if (loopval > this->mMax || loopval < this->mMin || ((mScanType ==
'p' || mScanType ==
't' || mScanType ==
'r') && (realcharge > this->mMax2 || realcharge < this->mMin2))) {
1427 if (this->mVerboseOutput) {
1428 LOG(warning) <<
"CW issues - loopval value " << loopval <<
" out of range for min " << this->mMin
1429 <<
" and max " << this->mMax <<
" (range: " << N_RANGE <<
")";
1430 if (mScanType ==
'p' || mScanType ==
'r' || mScanType ==
't') {
1431 LOG(warning) <<
" and/or realcharge value " << realcharge <<
" out of range from min " << this->mMin2
1432 <<
" and max " << this->mMax2 <<
" (range: " << N_RANGE2 <<
")";
1436 std::vector<short int> mChips;
1438 for (
unsigned int idig = rofIndex; idig < rofIndex + rofNEntries; idig++) {
1440 short int chipID = (
short int)d.getChipIndex();
1441 if ((chipID % mChipModBase) != mChipModSel) {
1444 if (d.getRow() !=
row && mVerboseOutput) {
1445 LOG(info) <<
"iROF: " << iROF <<
" ChipID " << chipID <<
": current row is " << d.getRow() <<
" (col = " << d.getColumn() <<
") but the one in CW is " <<
row;
1447 if (std::find(mChips.begin(), mChips.end(), chipID) == mChips.end()) {
1448 mChips.push_back(chipID);
1452 for (
auto& chipID : mChips) {
1454 short int ru = getRUID(chipID);
1455 mActiveLinks[ru][getLinkID(chipID, ru)] =
true;
1457 if (!this->mPixelHits.count(chipID)) {
1458 if (mScanType ==
'D' || mScanType ==
'A') {
1459 for (
int irow = 0; irow < 512; irow++) {
1460 this->mPixelHits[chipID][irow] = std::vector<std::vector<std::vector<unsigned short int>>>(this->N_COL, std::vector<std::vector<unsigned short int>>(N_RANGE2, std::vector<unsigned short int>(N_RANGE, 0)));
1463 this->mPixelHits[chipID][
row] = std::vector<std::vector<std::vector<unsigned short int>>>(this->N_COL, std::vector<std::vector<unsigned short int>>(N_RANGE2, std::vector<unsigned short int>(N_RANGE, 0)));
1465 }
else if (!this->mPixelHits[chipID].
count(
row)) {
1466 this->mPixelHits[chipID][
row] = std::vector<std::vector<std::vector<unsigned short int>>>(this->N_COL, std::vector<std::vector<unsigned short int>>(N_RANGE2, std::vector<unsigned short int>(N_RANGE, 0)));
1471 short int loopPoint = (loopval - this->mMin) / mStep;
1472 short int chgPoint = (realcharge - this->mMin2) / mStep2;
1473 for (
unsigned int idig = rofIndex; idig < rofIndex + rofNEntries; idig++) {
1475 short int chipID = (
short int)d.getChipIndex();
1476 short int col = (
short int)d.getColumn();
1478 if ((chipID % mChipModBase) != mChipModSel) {
1482 if ((!mCheckExactRow || d.getRow() ==
row) && (mMeb < 0 || cwcnt % 3 == mMeb)) {
1484 this->mPixelHits[chipID][d.getRow()][
col][chgPoint][loopPoint]++;
1494 short int nL = getNumberOfActiveLinks(mActiveLinks[ruIndex]);
1496 nL = ruIndex > 47 ? 2 : 3;
1498 std::vector<short int> chipEnabled = getChipListFromRu(ruIndex, mActiveLinks[ruIndex]);
1500 if (mRunTypeRUCopy[ruIndex] ==
nInjScaled * nL && nL > 0) {
1501 for (
short int iChip = 0; iChip < chipEnabled.size(); iChip++) {
1502 if ((chipEnabled[iChip] % mChipModBase) != mChipModSel) {
1505 addDatabaseEntry(chipEnabled[iChip],
"", std::vector<float>(),
true);
1507 mRunTypeRUCopy[ruIndex] = 0;
1510 bool passCondition = nL > 0 ? true :
false;
1511 for (
int j1 = 0; j1 < N_RANGE2; j1++) {
1512 for (
int j2 = 0; j2 < N_RANGE; j2++) {
1513 if (mScanType ==
'D' || mScanType ==
'A') {
1514 for (
int ir = 0;
ir < mRowScan;
ir += mRowStep) {
1515 if (!mCdwCntRU[ruIndex].
count(
ir)) {
1516 passCondition =
false;
1518 }
else if (mCdwCntRU[ruIndex][
ir][j1][j2] <
nInjScaled * nL) {
1519 passCondition =
false;
1523 }
else if (mScanType ==
't') {
1524 if ((j1 == 0 && j2 < ((600 - mMin) / mStep)) || (j2 >= ((600 - mMin) / mStep) && j2 <= ((800 - mMin) / mStep)) || (j1 == 1 && j2 > ((800 - mMin) / mStep))) {
1526 passCondition =
false;
1530 }
else if (mCdwCntRU[ruIndex][
row][j1][j2] <
nInjScaled * nL) {
1531 passCondition =
false;
1535 if (!passCondition) {
1539 if (mVerboseOutput) {
1540 LOG(info) <<
"PassCondition: " << passCondition <<
" - mCdwCntRU of RU" << ruIndex <<
" row " <<
row <<
" = " << mCdwCntRU[ruIndex][
row][0][0] <<
"(Links: " << mActiveLinks[ruIndex][0] <<
", " << mActiveLinks[ruIndex][1] <<
"," << mActiveLinks[ruIndex][2] <<
")";
1543 if (mScanType !=
'D' && mScanType !=
'A' && mScanType !=
'P' && mScanType !=
'R' && passCondition) {
1545 for (
short int iChip = 0; iChip < chipEnabled.size(); iChip++) {
1546 short int chipID = chipEnabled[iChip];
1547 if ((chipID % mChipModBase) != mChipModSel) {
1550 if (!isDumpS || (std::find(chipDumpList.begin(), chipDumpList.end(), chipID) != chipDumpList.end() || !chipDumpList.size())) {
1551 if (mPixelHits.count(chipID)) {
1552 if (mPixelHits[chipID].
count(
row)) {
1553 extractAndUpdate(chipID,
row);
1554 if (mScanType !=
'p') {
1555 mPixelHits[chipID].erase(
row);
1561 mCdwCntRU[ruIndex].erase(
row);
1564 if (mRunTypeRU[ruIndex] >=
nInjScaled * nL && passCondition) {
1565 mFlagsRU[ruIndex] =
true;
1568 if (mVerboseOutput) {
1569 LOG(info) <<
"Resetting links of RU " << ruIndex;
1572 mActiveLinks[ruIndex][0] = 0;
1573 mActiveLinks[ruIndex][1] = 0;
1574 mActiveLinks[ruIndex][2] = 0;
1575 mRunTypeRU[ruIndex] = 0;
1576 mFlagsRU[ruIndex] =
false;
1577 mCdwCntRU.erase(ruIndex);
1580 LOG(info) <<
"Shipping all outputs to aggregator (before endOfStream arrival!)";
1591 mChipDoneQc.clear();
1596 LOG(info) <<
"Run stop requested during the scan, sending output to aggregator and then stopping to process new data";
1597 mRunStopRequested =
true;
1606 mChipDoneQc.clear();
1619 LOG(info) <<
"Conf DB map retrieved from CCDB";
1620 mConfDBmap = (std::vector<int>*)obj;
1626void ITSThresholdCalibrator::findAverage(
const std::array<long int, 6>&
data,
float& avgT,
float& rmsT,
float& avgN,
float& rmsN)
1628 avgT = (!
data[4]) ? 0. : (float)
data[0] / (float)
data[4];
1629 rmsT = (!
data[4]) ? 0. :
std::sqrt((float)
data[1] / (float)
data[4] - avgT * avgT);
1630 avgN = (!
data[4]) ? 0. : (float)
data[2] / (float)
data[4];
1631 rmsN = (!
data[4]) ? 0. :
std::sqrt((float)
data[3] / (float)
data[4] - avgN * avgN);
1636void ITSThresholdCalibrator::addDatabaseEntry(
1637 const short int& chipID,
const char*
name, std::vector<float>
data,
bool isQC)
1649 int lay, sta, ssta, mod, chipInMod;
1653 snprintf(stave, 6,
"L%d_%02d", lay, sta);
1661 int confDBid = (*mConfDBmap)[chipID];
1664 if (this->mScanType ==
'D' || this->mScanType ==
'A') {
1665 short int vPixDcolCounter[512] = {0};
1666 std::string dcolIDs =
"";
1667 std::string pixIDs_Noisy =
"";
1668 std::string pixIDs_Dead =
"";
1669 std::string pixIDs_Ineff =
"";
1670 std::vector<int>&
v = PixelType ==
"Noisy" ? mNoisyPixID[chipID] : PixelType ==
"Dead" ? mDeadPixID[chipID]
1671 : mIneffPixID[chipID];
1673 int n_pixel =
v.size(), nDcols = 0;
1674 std::string
ds =
"-1";
1676 if (PixelType ==
"Noisy") {
1677 for (
int i = 0;
i <
v.size();
i++) {
1678 short int dcol = ((
v[
i] -
v[
i] % 1000) / 1000) / 2;
1679 vPixDcolCounter[dcol]++;
1681 for (
int i = 0;
i < 512;
i++) {
1682 if (vPixDcolCounter[
i] > N_PIX_DCOL) {
1695 if (this->mTagSinglePix) {
1696 if (PixelType ==
"Noisy") {
1697 for (
int i = 0;
i <
v.size();
i++) {
1698 short int dcol = ((
v[
i] -
v[
i] % 1000) / 1000) / 2;
1699 if (vPixDcolCounter[dcol] > N_PIX_DCOL) {
1705 if (
i + 1 <
v.size()) {
1706 pixIDs_Noisy +=
'|';
1717 if (PixelType ==
"Dead") {
1718 for (
int i = 0;
i <
v.size();
i++) {
1720 if (
i + 1 <
v.size()) {
1726 if (PixelType ==
"Ineff") {
1727 for (
int i = 0;
i <
v.size();
i++) {
1729 if (
i + 1 <
v.size()) {
1730 pixIDs_Ineff +=
'|';
1736 if (!dcolIDs.empty()) {
1742 if (pixIDs_Noisy.empty()) {
1743 pixIDs_Noisy =
"-1";
1746 if (pixIDs_Dead.empty()) {
1750 if (pixIDs_Ineff.empty()) {
1751 pixIDs_Ineff =
"-1";
1755 if (PixelType ==
"Dead" || PixelType ==
"Ineff") {
1765 if (this->mScanType !=
'D' && this->mScanType !=
'A' && this->mScanType !=
'P' && this->mScanType !=
'p') {
1772 if (this->mScanType ==
'T') {
1777 if (this->mScanType ==
'P') {
1787 if (this->mScanType ==
'p') {
1808 static bool initOnceDone =
false;
1809 if (!initOnceDone) {
1810 initOnceDone =
true;
1820 const char*
name =
nullptr;
1821 std::set<int> thisRUs;
1823 if (mScanType ==
'V' || mScanType ==
'I' || mScanType ==
'T') {
1825 name = mScanType ==
'V' ?
"VCASN" : mScanType ==
'I' ?
"ITHR"
1827 if (mScanType ==
'I') {
1829 for (
auto& iRU : mRuSet) {
1830 if (mFlagsRU[iRU] || mRunStopRequested) {
1831 std::vector<short int> chipList = getChipListFromRu(iRU, mActiveLinks[iRU]);
1832 for (
size_t i = 0;
i < chipList.size();
i++) {
1833 if ((chipList[
i] % mChipModBase) != mChipModSel) {
1836 if (!mThresholds.count(chipList[
i]) && !isChipDB[chipList[
i]]) {
1837 if (mVerboseOutput) {
1838 LOG(info) <<
"Setting ITHR = 50 for chip " << chipList[
i];
1840 std::vector<float>
data = {50, 0, 0, 0, 0};
1841 addDatabaseEntry(chipList[
i],
name,
data,
false);
1842 isChipDB[chipList[
i]] =
true;
1849 auto it = this->mThresholds.cbegin();
1850 while (it != this->mThresholds.cend()) {
1851 short int iRU = getRUID(it->first);
1852 if (!isCRUITS && (!mFlagsRU[iRU]) && !mRunStopRequested) {
1856 thisRUs.insert(iRU);
1857 float avgT, rmsT, avgN, rmsN, mpvT, outVal;
1858 this->findAverage(it->second, avgT, rmsT, avgN, rmsN);
1861 mpvT = std::distance(mpvCounter[it->first].begin(), std::max_element(mpvCounter[it->first].begin(), mpvCounter[it->first].end())) + mMin;
1864 if (mVerboseOutput) {
1865 LOG(info) <<
"Average or mpv " <<
name <<
" of chip " << it->first <<
" = " << outVal <<
" e-";
1867 float status = ((float)it->second[4] / (
float)(mRowScan * N_COL)) * 100.;
1868 if (status < mPercentageCut && (mScanType ==
'I' || mScanType ==
'V')) {
1869 if (mScanType ==
'I') {
1871 if (mVerboseOutput) {
1872 LOG(info) <<
"Chip " << it->first <<
" status is " << status <<
". Setting ITHR = 50";
1875 it = this->mThresholds.erase(it);
1876 if (mVerboseOutput) {
1877 LOG(info) <<
"Chip " << it->first <<
" status is " << status <<
". Ignoring this chip.";
1882 std::vector<float>
data = {outVal, rmsT, avgN, rmsN, status};
1883 this->addDatabaseEntry(it->first,
name,
data,
false);
1884 isChipDB[it->first] =
true;
1885 it = this->mThresholds.erase(it);
1887 }
else if (this->mScanType ==
'D' || this->mScanType ==
'A') {
1891 auto itchip = this->mPixelHits.cbegin();
1892 while (itchip != this->mPixelHits.cend()) {
1893 short int iRU = getRUID(itchip->first);
1894 if (!isCRUITS && !mFlagsRU[iRU] && !mRunStopRequested) {
1898 thisRUs.insert(iRU);
1899 if (mVerboseOutput) {
1900 LOG(info) <<
"Extracting hits for the full matrix of chip " << itchip->first;
1902 for (
short int irow = 0; irow < 512; irow++) {
1903 this->extractAndUpdate(itchip->first, irow);
1905 if (this->mVerboseOutput) {
1906 LOG(info) <<
"Chip " << itchip->first <<
" hits extracted";
1908 itchip = mPixelHits.erase(itchip);
1911 auto it = this->mNoisyPixID.cbegin();
1912 while (it != this->mNoisyPixID.cend()) {
1913 PixelType =
"Noisy";
1914 if (mVerboseOutput) {
1915 LOG(info) <<
"Extracting noisy pixels in the full matrix of chip " << it->first;
1917 this->addDatabaseEntry(it->first,
name, std::vector<float>(),
false);
1918 if (this->mVerboseOutput) {
1919 LOG(info) <<
"Chip " << it->first <<
" done";
1921 it = this->mNoisyPixID.erase(it);
1924 auto it_d = this->mDeadPixID.cbegin();
1925 while (it_d != this->mDeadPixID.cend()) {
1926 if (mVerboseOutput) {
1927 LOG(info) <<
"Extracting dead pixels in the full matrix of chip " << it_d->first;
1930 this->addDatabaseEntry(it_d->first,
name, std::vector<float>(),
false);
1931 it_d = this->mDeadPixID.erase(it_d);
1934 auto it_ineff = this->mIneffPixID.cbegin();
1935 while (it_ineff != this->mIneffPixID.cend()) {
1936 if (mVerboseOutput) {
1937 LOG(info) <<
"Extracting inefficient pixels in the full matrix of chip " << it_ineff->first;
1939 PixelType =
"Ineff";
1940 this->addDatabaseEntry(it_ineff->first,
name, std::vector<float>(),
false);
1941 it_ineff = this->mIneffPixID.erase(it_ineff);
1943 }
else if (this->mScanType ==
'P' || this->mScanType ==
'p' || mScanType ==
'R') {
1946 auto itchip = this->mPixelHits.cbegin();
1947 while (itchip != mPixelHits.cend()) {
1948 int iRU = getRUID(itchip->first);
1949 if (!mRunStopRequested && !mFlagsRU[iRU]) {
1953 thisRUs.insert(iRU);
1954 if (mVerboseOutput) {
1955 LOG(info) <<
"Extracting hits from pulse shape scan or vresetd scan, chip " << itchip->first;
1958 if (mScanType !=
'p') {
1959 auto itrow = this->mPixelHits[itchip->first].cbegin();
1960 while (itrow != mPixelHits[itchip->first].cend()) {
1961 this->extractAndUpdate(itchip->first, itrow->first);
1966 if (mCalculate2DParams && (mScanType ==
'P' || mScanType ==
'p')) {
1967 this->addDatabaseEntry(itchip->first,
name, mScanType ==
'P' ? calculatePulseParams(itchip->first) : calculatePulseParams2D(itchip->first),
false);
1969 if (this->mVerboseOutput) {
1970 LOG(info) <<
"Chip " << itchip->first <<
" hits extracted";
1972 itchip = mPixelHits.erase(itchip);
1985 if (!isEnded && !mRunStopRequested) {
1986 LOGF(info,
"endOfStream report:", mSelfName);
1987 LOG(info) <<
"Calling finalize(), doing nothing if scan has properly ended, otherwise save partial data in ROOT trees as backup";
1990 this->finalizeOutput();
2001 LOGF(info,
"stop() report:", mSelfName);
2002 LOG(info) <<
"Calling finalize(), doing nothing if scan has properly ended, otherwise save partial data in ROOT trees as backup";
2004 this->finalizeOutput();
2014 std::vector<InputSpec> inputs;
2015 inputs.emplace_back(
"digits", detOrig,
"DIGITS", 0, Lifetime::Timeframe);
2016 inputs.emplace_back(
"digitsROF", detOrig,
"DIGITSROF", 0, Lifetime::Timeframe);
2017 inputs.emplace_back(
"calib", detOrig,
"GBTCALIB", 0, Lifetime::Timeframe);
2021 std::vector<OutputSpec> outputs;
2022 outputs.emplace_back(
"ITS",
"TSTR", inpConf.
chipModSel);
2023 outputs.emplace_back(
"ITS",
"PIXTYP", inpConf.
chipModSel);
2024 outputs.emplace_back(
"ITS",
"RUNT", inpConf.
chipModSel);
2025 outputs.emplace_back(
"ITS",
"SCANT", inpConf.
chipModSel);
2026 outputs.emplace_back(
"ITS",
"FITT", inpConf.
chipModSel);
2027 outputs.emplace_back(
"ITS",
"CONFDBV", inpConf.
chipModSel);
2028 outputs.emplace_back(
"ITS",
"QCSTR", inpConf.
chipModSel);
2034 AlgorithmSpec{adaptFromTask<ITSThresholdCalibrator>(inpConf)},
2035 Options{{
"fittype", VariantType::String,
"derivative", {
"Fit type to extract thresholds, with options: fit, derivative (default), hitcounting"}},
2036 {
"verbose", VariantType::Bool,
false, {
"Use verbose output mode"}},
2037 {
"output-dir", VariantType::String,
"./", {
"ROOT trees output directory"}},
2038 {
"meta-output-dir", VariantType::String,
"/dev/null", {
"Metadata output directory"}},
2039 {
"meta-type", VariantType::String,
"", {
"metadata type"}},
2040 {
"nthreads", VariantType::Int, 1, {
"Number of threads, default is 1"}},
2041 {
"enable-cw-cnt-check", VariantType::Bool,
false, {
"Use to enable the check of the calib word counter row by row in addition to the hits"}},
2042 {
"enable-single-pix-tag", VariantType::Bool,
false, {
"Use to enable tagging of single noisy pix in digital and analogue scan"}},
2043 {
"ccdb-mgr-url", VariantType::String,
"", {
"CCDB url to download confDBmap"}},
2044 {
"min-vcasn", VariantType::Int, 30, {
"Min value of VCASN in vcasn scan, default is 30"}},
2045 {
"max-vcasn", VariantType::Int, 70, {
"Max value of VCASN in vcasn scan, default is 70"}},
2046 {
"min-ithr", VariantType::Int, 25, {
"Min value of ITHR in ithr scan, default is 25"}},
2047 {
"max-ithr", VariantType::Int, 100, {
"Max value of ITHR in ithr scan, default is 100"}},
2048 {
"manual-mode", VariantType::Bool,
false, {
"Flag to activate the manual mode in case run type is not recognized"}},
2049 {
"manual-min", VariantType::Int, 0, {
"Min value of the variable used for the scan: use only in manual mode"}},
2050 {
"manual-max", VariantType::Int, 50, {
"Max value of the variable used for the scan: use only in manual mode"}},
2051 {
"manual-min2", VariantType::Int, 0, {
"Min2 value of the 2nd variable (if any) used for the scan (ex: charge in tot_calib): use only in manual mode"}},
2052 {
"manual-max2", VariantType::Int, 50, {
"Max2 value of the 2nd variable (if any) used for the scan (ex: charge in tot_calib): use only in manual mode"}},
2053 {
"manual-step", VariantType::Int, 1, {
"Step value: defines the steps between manual-min and manual-max. Default is 1. Use only in manual mode"}},
2054 {
"manual-step2", VariantType::Int, 1, {
"Step2 value: defines the steps between manual-min2 and manual-max2. Default is 1. Use only in manual mode"}},
2055 {
"manual-scantype", VariantType::String,
"T", {
"scan type, can be D, T, I, V, P, p: use only in manual mode"}},
2056 {
"manual-strobewindow", VariantType::Int, 5, {
"strobe duration in clock cycles, default is 5 = 125 ns: use only in manual mode"}},
2057 {
"manual-rowscan", VariantType::Int, 512, {
"Number of ALPIDE rows scanned in the run: use only in manual mode"}},
2058 {
"save-tree", VariantType::Bool,
false, {
"Flag to save ROOT tree on disk: use only in manual mode"}},
2059 {
"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"}},
2060 {
"enable-mpv", VariantType::Bool,
false, {
"Flag to enable calculation of most-probable value in vcasn/ithr scans"}},
2061 {
"enable-cru-its", VariantType::Bool,
false, {
"Flag to enable the analysis of raw data on disk produced by CRU_ITS IB commissioning tools"}},
2062 {
"ninj", VariantType::Int, 50, {
"Number of injections per change, default is 50"}},
2063 {
"dump-scurves", VariantType::Bool,
false, {
"Dump any s-curve to disk in ROOT file. Works only with fit option."}},
2064 {
"max-dump", VariantType::Int, -1, {
"Maximum number of s-curves to dump in ROOT file per chip. Works with fit option and dump-scurves flag enabled. Default: dump all"}},
2065 {
"chip-dump", VariantType::String,
"", {
"Dump s-curves only for these Chip IDs (0 to 24119). If multiple IDs, write them separated by comma. Default is empty string: dump all"}},
2066 {
"calculate-slope", VariantType::Bool,
false, {
"For Pulse Shape 2D: if enabled it calculate the slope of the charge vs strobe delay trend for each pixel and fill it in the output tree"}},
2067 {
"charge-a", VariantType::Int, 0, {
"To use with --calculate-slope, it defines the charge (in DAC) for the 1st point used for the slope calculation"}},
2068 {
"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"}},
2069 {
"meb-select", VariantType::Int, -1, {
"Select from which multi-event buffer consider the hits: 0,1 or 2"}},
2070 {
"s-curve-col-step", VariantType::Int, 8, {
"save s-curves points to tree every s-curve-col-step pixels on 1 row"}},
2071 {
"percentage-cut", VariantType::Int, 25, {
"discard chip in ITHR/VCASN scan if the percentage of success is less than this cut"}},
2072 {
"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)"}}}};
static BasicCCDBManager & instance()
T get(const char *key) const
void snapshot(const Output &spec, T const &object)
ConfigParamRegistry const & options()
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
TransitionHandlingState transitionState() const
void run(ProcessingContext &pc) final
void stop() final
This is invoked on stop.
void init(InitContext &ic) final
void endOfStream(EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
o2::itsmft::ChipMappingITS mp
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj) final
ITSThresholdCalibrator(const ITSCalibInpConf &inpConf)
~ITSThresholdCalibrator() override
void expandChipInfoHW(int idSW, int &lay, int &sta, int &ssta, int &mod, int &chipInMod) const
convert global SW chip ID to name in HW conventions
static constexpr std::string_view getName()
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
GLenum GLsizei GLsizei GLint * values
GLboolean GLboolean GLboolean GLboolean a
constexpr o2::header::DataOrigin gDataOriginITS
long getCurrentTimestamp()
returns the timestamp in long corresponding to "now"
void addConfigItem(DCSconfigObject_t &configVector, std::string key, const T value)
std::vector< ConfigParamSpec > Options
double erf_ithr(double *xx, double *par)
double erf(double *xx, double *par)
o2::framework::DataProcessorSpec getITSThresholdCalibratorSpec(const ITSCalibInpConf &inpConf)
Enum< T >::Iterator begin(Enum< T >)
void createDirectoriesIfAbsent(std::string const &path)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
std::string to_string(gsl::span< T, Size > span)
std::string envId
The environment ID for the deployment.
std::string runNumber
The current run number.
static std::string rectifyDirectory(const std::string_view p)
static std::string concat_string(Ts const &... ts)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
std::vector< Digit > digits