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";
77 std::string fittype = ic.
options().
get<std::string>(
"fittype");
78 if (fittype ==
"derivative") {
81 }
else if (fittype ==
"fit") {
84 }
else if (fittype ==
"hitcounting") {
88 LOG(error) <<
"fittype " << fittype
89 <<
" not recognized, please use 'derivative', 'fit', or 'hitcounting'";
95 this->mMetafileDir = ic.
options().
get<std::string>(
"meta-output-dir");
96 }
catch (std::exception
const& e) {
97 LOG(warning) <<
"Input parameter meta-output-dir not found"
98 <<
"\n*** Setting metafile output directory to /dev/null";
100 if (this->mMetafileDir !=
"/dev/null") {
106 this->mOutputDir = ic.
options().
get<std::string>(
"output-dir");
107 }
catch (std::exception
const& e) {
108 LOG(warning) <<
"Input parameter output-dir not found"
109 <<
"\n*** Setting ROOT output directory to ./";
115 this->mMetaType = ic.
options().
get<std::string>(
"meta-type");
116 }
catch (std::exception
const& e) {
117 LOG(warning) <<
"Input parameter meta-type not found"
118 <<
"\n*** Disabling 'type' in metadata output files";
121 this->mVerboseOutput = ic.
options().
get<
bool>(
"verbose");
124 this->mNThreads = ic.
options().
get<
int>(
"nthreads");
127 if (mFitType ==
FIT && mNThreads > 1) {
128 throw std::runtime_error(
"Multiple threads are requested with fit method which is not thread safe");
132 this->mHostname = boost::asio::ip::host_name();
135 this->mTagSinglePix = ic.
options().
get<
bool>(
"enable-single-pix-tag");
138 inMinVcasn = ic.
options().
get<
short int>(
"min-vcasn");
139 inMaxVcasn = ic.
options().
get<
short int>(
"max-vcasn");
140 inMinIthr = ic.
options().
get<
short int>(
"min-ithr");
141 inMaxIthr = ic.
options().
get<
short int>(
"max-ithr");
142 if (inMinVcasn > inMaxVcasn || inMinIthr > inMaxIthr) {
143 throw std::runtime_error(
"Min VCASN/ITHR is larger than Max VCASN/ITHR: check the settings, analysis not possible");
150 isManualMode = ic.
options().
get<
bool>(
"manual-mode");
153 manualMin = ic.
options().
get<
short int>(
"manual-min");
154 }
catch (std::exception
const& e) {
155 throw std::runtime_error(
"Min value of the scan parameter not found, mandatory in manual mode");
159 manualMax = ic.
options().
get<
short int>(
"manual-max");
160 }
catch (std::exception
const& e) {
161 throw std::runtime_error(
"Max value of the scan parameter not found, mandatory in manual mode");
165 manualScanType = ic.
options().
get<std::string>(
"manual-scantype");
166 }
catch (std::exception
const& e) {
167 throw std::runtime_error(
"Scan type not found, mandatory in manual mode");
171 saveTree = ic.
options().
get<
bool>(
"save-tree");
172 }
catch (std::exception
const& e) {
173 throw std::runtime_error(
"Please specify if you want to save the ROOT trees, mandatory in manual mode");
177 manualStep = ic.
options().
get<
short int>(
"manual-step");
180 manualMin2 = ic.
options().
get<
short int>(
"manual-min2");
183 manualMax2 = ic.
options().
get<
short int>(
"manual-max2");
186 manualStep2 = ic.
options().
get<
short int>(
"manual-step2");
189 manualStrobeWindow = ic.
options().
get<
short int>(
"manual-strobewindow");
192 scaleNinj = ic.
options().
get<
bool>(
"scale-ninj");
196 isCRUITS = ic.
options().
get<
bool>(
"enable-cru-its");
203 this->mCcdbMgrUrl = ic.
options().
get<std::string>(
"ccdb-mgr-url");
206 LOG(info) <<
"Getting confDB map from ccdb - timestamp: " << ts;
208 mgr.setURL(mCcdbMgrUrl);
209 mgr.setTimestamp(ts);
210 mConfDBmap = mgr.get<std::vector<int>>(
"ITS/Calib/Confdbmap");
213 isDumpS = ic.
options().
get<
bool>(
"dump-scurves");
215 chipDumpS = ic.
options().
get<std::string>(
"chip-dump");
216 chipDumpList = getIntegerVect(chipDumpS);
217 if (isDumpS && mFitType !=
FIT) {
218 LOG(error) <<
"S-curve dump enabled but `fittype` is not fit. Please check";
221 fileDumpS = TFile::Open(Form(
"s-curves_%d.root", mChipModSel),
"RECREATE");
223 LOG(info) <<
"`max-dump` " << maxDumpS <<
". Dumping all s-curves";
225 LOG(info) <<
"`max-dump` " << maxDumpS <<
". Dumping " << maxDumpS <<
" s-curves";
227 if (!chipDumpList.size()) {
228 LOG(info) <<
"Dumping s-curves for all chips";
230 LOG(info) <<
"Dumping s-curves for chips: " << chipDumpS;
235 doSlopeCalculation = ic.
options().
get<
bool>(
"calculate-slope");
236 if (doSlopeCalculation) {
239 }
catch (std::exception
const& e) {
240 throw std::runtime_error(
"You want to do the slop calculation but you did not specify charge-a");
245 }
catch (std::exception
const& e) {
246 throw std::runtime_error(
"You want to do the slop calculation but you did not specify charge-b");
253 LOG(error) <<
"MEB cannot be greater than 2. Please check your command line.";
261short int ITSThresholdCalibrator::getNumberOfActiveLinks(
bool* links)
264 for (
int i = 0;
i < 3;
i++) {
274short int ITSThresholdCalibrator::getLinkID(
short int chipID,
short int ruID)
277 return (chipID - ruID * 9) / 3;
278 }
else if (chipID >= 432 && chipID < 6480) {
279 return (chipID - 48 * 9 - (ruID - 48) * 112) / 56;
281 return (chipID - 48 * 9 - 54 * 112 - (ruID - 102) * 196) / 98;
287std::vector<short int> ITSThresholdCalibrator::getChipListFromRu(
short int ruID,
bool* links)
289 std::vector<short int> cList;
294 }
else if (ruID >= 48 && ruID < 102) {
295 a = 48 * 9 + (ruID - 48) * 112;
298 a = 48 * 9 + 54 * 112 + (ruID - 102) * 196;
302 for (
int c =
a;
c <=
b;
c++) {
303 short int lid = getLinkID(
c, ruID);
314short int ITSThresholdCalibrator::getRUID(
short int chipID)
319 }
else if (chipID >= 432 && chipID < 6480) {
320 return (chipID - 48 * 9 + 112 * 48) / 112;
322 return (chipID - 48 * 9 - 54 * 112 + 102 * 196) / 196;
328std::vector<short int> ITSThresholdCalibrator::getIntegerVect(std::string& s)
330 std::stringstream ss(s);
331 std::vector<short int>
result;
343void ITSThresholdCalibrator::initThresholdTree(
bool recreate )
347 std::string dir = this->mOutputDir + fmt::format(
"{}_{}/", mDataTakingContext.
envId, mDataTakingContext.
runNumber);
349 LOG(info) <<
"Created " << dir <<
" directory for ROOT trees output";
357 LOG(warning) <<
"File " <<
filename <<
" already exists, recreating";
362 const char* option = recreate ?
"RECREATE" :
"UPDATE";
363 mRootOutfile =
new TFile(
filename.c_str(), option);
366 mScTree =
new TTree(
"s-curve-points",
"s-curve-points");
367 mScTree->Branch(
"chipid", &vChipid,
"vChipID[1024]/S");
368 mScTree->Branch(
"row", &vRow,
"vRow[1024]/S");
371 mThresholdTree =
new TTree(
"ITS_calib_tree",
"ITS_calib_tree");
372 mThresholdTree->Branch(
"chipid", &vChipid,
"vChipID[1024]/S");
373 mThresholdTree->Branch(
"row", &vRow,
"vRow[1024]/S");
374 if (mScanType ==
'T') {
375 mThresholdTree->Branch(
"thr", &vThreshold,
"vThreshold[1024]/S");
376 mThresholdTree->Branch(
"noise", &vNoise,
"vNoise[1024]/F");
377 mThresholdTree->Branch(
"spoints", &vPoints,
"vPoints[1024]/b");
378 mThresholdTree->Branch(
"success", &vSuccess,
"vSuccess[1024]/O");
380 mScTree->Branch(
"chg", &vCharge,
"vCharge[1024]/b");
381 mScTree->Branch(
"hits", &vHits,
"vHits[1024]/b");
382 }
else if (mScanType ==
'D' || mScanType ==
'A') {
383 mThresholdTree->Branch(
"n_hits", &vThreshold,
"vThreshold[1024]/S");
384 }
else if (mScanType ==
'P') {
385 mThresholdTree->Branch(
"n_hits", &vThreshold,
"vThreshold[1024]/S");
386 mThresholdTree->Branch(
"strobedel", &vMixData,
"vMixData[1024]/S");
387 }
else if (mScanType ==
'p') {
388 mThresholdTree->Branch(
"n_hits", &vThreshold,
"vThreshold[1024]/S");
389 mThresholdTree->Branch(
"strobedel", &vMixData,
"vMixData[1024]/S");
390 mThresholdTree->Branch(
"charge", &vCharge,
"vCharge[1024]/b");
391 if (doSlopeCalculation) {
392 mSlopeTree =
new TTree(
"line_tree",
"line_tree");
393 mSlopeTree->Branch(
"chipid", &vChipid,
"vChipID[1024]/S");
394 mSlopeTree->Branch(
"row", &vRow,
"vRow[1024]/S");
395 mSlopeTree->Branch(
"slope", &vSlope,
"vSlope[1024]/F");
396 mSlopeTree->Branch(
"intercept", &vIntercept,
"vIntercept[1024]/F");
398 }
else if (mScanType ==
'R') {
399 mThresholdTree->Branch(
"n_hits", &vThreshold,
"vThreshold[1024]/S");
400 mThresholdTree->Branch(
"vresetd", &vMixData,
"vMixData[1024]/S");
401 }
else if (mScanType ==
'r') {
402 mThresholdTree->Branch(
"thr", &vThreshold,
"vThreshold[1024]/S");
403 mThresholdTree->Branch(
"noise", &vNoise,
"vNoise[1024]/F");
404 mThresholdTree->Branch(
"success", &vSuccess,
"vSuccess[1024]/O");
405 mThresholdTree->Branch(
"vresetd", &vMixData,
"vMixData[1024]/S");
416bool ITSThresholdCalibrator::findUpperLower(
417 std::vector<std::vector<unsigned short int>>
data,
const short int& NPoints,
418 short int& lower,
short int& upper,
bool flip,
int iloop2)
426 for (
int i = 0;
i < NPoints;
i++) {
427 int comp = mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2];
437 for (
int i = upper;
i > 0;
i--) {
438 int comp = mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2];
447 for (
int i = 0;
i < NPoints;
i++) {
448 int comp = mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2];
458 for (
int i = upper;
i > 0;
i--) {
459 int comp = mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2];
468 if ((lower == -1) || (upper < lower)) {
476bool ITSThresholdCalibrator::findThreshold(
477 const short int& chipID, std::vector<std::vector<unsigned short int>>
data,
const float*
x,
short int& NPoints,
478 float& thresh,
float& noise,
int& spoints,
int iloop2)
480 bool success =
false;
482 switch (this->mFitType) {
484 success = this->findThresholdDerivative(
data,
x, NPoints, thresh, noise, spoints, iloop2);
488 success = this->findThresholdFit(chipID,
data,
x, NPoints, thresh, noise, spoints, iloop2);
492 success = this->findThresholdHitcounting(
data,
x, NPoints, thresh, iloop2);
508bool ITSThresholdCalibrator::findThresholdFit(
509 const short int& chipID, std::vector<std::vector<unsigned short int>>
data,
const float*
x,
const short int& NPoints,
510 float& thresh,
float& noise,
int& spoints,
int iloop2)
513 short int lower, upper;
514 bool flip = (this->mScanType ==
'I');
515 auto fndVal = std::find(chipDumpList.begin(), chipDumpList.end(), chipID);
517 if (!this->findUpperLower(
data, NPoints, lower, upper, flip, iloop2) || lower == upper) {
518 if (this->mVerboseOutput) {
519 LOG(warning) <<
"Start-finding unsuccessful: (lower, upper) = ("
520 << lower <<
", " << upper <<
")";
523 if (isDumpS && (dumpCounterS[chipID] < maxDumpS || maxDumpS < 0) && (fndVal != chipDumpList.end() || !chipDumpList.size())) {
524 for (
int i = 0;
i < NPoints;
i++) {
525 this->mFitHist->SetBinContent(
i + 1, mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2]);
531 dumpCounterS[chipID]++;
536 float start = (this->mX[upper] + this->mX[lower]) / 2;
539 if (this->mVerboseOutput) {
540 LOG(warning) <<
"Start-finding unsuccessful: Start = " <<
start;
545 for (
int i = 0;
i < NPoints;
i++) {
546 this->mFitHist->SetBinContent(
i + 1, mScanType !=
'r' ?
data[iloop2][
i] :
data[
i][iloop2]);
550 this->mFitFunction->SetParameter(0,
start);
551 this->mFitFunction->SetParameter(1, 8);
553 this->mFitHist->Fit(
"mFitFunction",
"RQL");
554 if (isDumpS && (dumpCounterS[chipID] < maxDumpS || maxDumpS < 0) && (fndVal != chipDumpList.end() || !chipDumpList.size())) {
559 dumpCounterS[chipID]++;
562 noise = this->mFitFunction->GetParameter(1);
563 thresh = this->mFitFunction->GetParameter(0);
564 float chi2 = this->mFitFunction->GetChisquare() / this->mFitFunction->GetNDF();
565 spoints = upper - lower - 1;
568 this->mFitHist->Reset();
580bool ITSThresholdCalibrator::findThresholdDerivative(std::vector<std::vector<unsigned short int>>
data,
const float*
x,
const short int& NPoints,
581 float& thresh,
float& noise,
int& spoints,
int iloop2)
584 short int lower, upper;
585 bool flip = (this->mScanType ==
'I');
586 if (!this->findUpperLower(
data, NPoints, lower, upper, flip, iloop2) || lower == upper) {
587 if (this->mVerboseOutput) {
588 LOG(warning) <<
"Start-finding unsuccessful: (lower, upper) = (" << lower <<
", " << upper <<
")";
593 int deriv_size = upper - lower;
594 float deriv[deriv_size];
595 float xfx = 0, fx = 0;
598 for (
int i = lower;
i < upper;
i++) {
599 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]);
600 xfx += this->mX[
i] * deriv[
i - lower];
601 fx += deriv[
i - lower];
608 for (
int i = lower;
i < upper;
i++) {
609 stddev += std::pow(this->mX[
i] - thresh, 2) * deriv[
i - lower];
613 noise = std::sqrt(stddev);
614 spoints = upper - lower - 1;
625bool ITSThresholdCalibrator::findThresholdHitcounting(
626 std::vector<std::vector<unsigned short int>>
data,
const float*
x,
const short int& NPoints,
float& thresh,
int iloop2)
628 unsigned short int numberOfHits = 0;
630 for (
unsigned short int i = 0;
i < NPoints;
i++) {
631 numberOfHits += (mScanType !=
'r') ?
data[iloop2][
i] :
data[
i][iloop2];
632 int comp = (mScanType !=
'r') ?
data[iloop2][
i] :
data[
i][iloop2];
640 if (this->mVerboseOutput) {
641 LOG(warning) <<
"Calculation unsuccessful: too few hits. Skipping this pixel";
646 if (this->mScanType ==
'T') {
648 }
else if (this->mScanType ==
'V') {
650 }
else if (this->mScanType ==
'I') {
653 LOG(error) <<
"Unexpected runtype encountered in findThresholdHitcounting()";
662void ITSThresholdCalibrator::extractThresholdRow(
const short int& chipID,
const short int&
row)
664 if (this->mScanType ==
'D' || this->mScanType ==
'A') {
666 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
667 vChipid[col_i] = chipID;
669 vThreshold[col_i] = this->mPixelHits[chipID][
row][col_i][0][0];
670 if (vThreshold[col_i] >
nInj) {
671 this->mNoisyPixID[chipID].push_back(col_i * 1000 +
row);
672 }
else if (vThreshold[col_i] > 0 && vThreshold[col_i] <
nInj) {
673 this->mIneffPixID[chipID].push_back(col_i * 1000 +
row);
674 }
else if (vThreshold[col_i] == 0) {
675 this->mDeadPixID[chipID].push_back(col_i * 1000 +
row);
678 }
else if (this->mScanType ==
'P' || this->mScanType ==
'p' || mScanType ==
'R') {
680 for (
short int var1_i = 0; var1_i < this->N_RANGE; var1_i++) {
681 for (
short int chg_i = 0; chg_i < this->N_RANGE2; chg_i++) {
682 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
683 vChipid[col_i] = chipID;
685 vThreshold[col_i] = this->mPixelHits[chipID][
row][col_i][chg_i][var1_i];
686 vMixData[col_i] = (var1_i * this->mStep) + mMin;
687 if (mScanType !=
'R') {
690 vCharge[col_i] = (
unsigned char)(chg_i * this->mStep2 + mMin2);
692 this->saveThreshold();
696 if (doSlopeCalculation) {
697 int delA = -1, delB = -1;
698 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
699 for (
short int chg_i = 0; chg_i < 2; chg_i++) {
700 bool isFound =
false;
701 int checkchg = !chg_i ? chargeA / mStep2 : chargeB / mStep2;
702 for (
short int sdel_i = N_RANGE - 1; sdel_i >= 0; sdel_i--) {
703 if (mPixelHits[chipID][
row][col_i][checkchg - 1][sdel_i] ==
nInj) {
705 delA = mMin + sdel_i * mStep + mStep / 2;
708 delB = mMin + sdel_i * mStep + mStep / 2;
716 for (
short int sdel_i = 0; sdel_i < N_RANGE; sdel_i++) {
717 if (mPixelHits[chipID][
row][col_i][checkchg - 1][sdel_i] > 0) {
719 delA = mMin + sdel_i * mStep + mStep / 2;
721 delB = mMin + sdel_i * mStep + mStep / 2;
729 if (delA > 0 && delB > 0 && delA != delB) {
730 vSlope[col_i] = ((
float)(chargeA - chargeB) / (
float)(delA - delB));
731 vIntercept[col_i] = (
float)chargeA - (
float)(vSlope[col_i] * delA);
732 if (vSlope[col_i] < 0) {
734 vIntercept[col_i] = 0.;
738 vIntercept[col_i] = 0.;
747 short int iRU = getRUID(chipID);
749 omp_set_num_threads(mNThreads);
750#pragma omp parallel for schedule(dynamic)
753 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
755 float thresh = 0., noise = 0.;
756 bool success =
false;
758 int scan_i = mScanType ==
'r' ? (mLoopVal[iRU][
row] - mMin) / mStep : 0;
760 mFitHist->SetName(Form(
"scurve_chip%d_row%d_col%d_scani%d", chipID,
row, col_i, scan_i));
763 success = this->findThreshold(chipID, mPixelHits[chipID][
row][col_i],
764 this->mX, mScanType ==
'r' ? N_RANGE2 : N_RANGE, thresh, noise, spoints, scan_i);
766 vChipid[col_i] = chipID;
768 vThreshold[col_i] = (mScanType ==
'T' || mScanType ==
'r') ? (
short int)(thresh * 10.) : (
short int)(thresh);
769 vNoise[col_i] = (
float)(noise * 10.);
770 vSuccess[col_i] = success;
771 vPoints[col_i] = spoints > 0 ? (
unsigned char)(spoints) : 0;
773 if (mScanType ==
'r') {
774 vMixData[col_i] = mLoopVal[iRU][
row];
777 if (mScanType ==
'r') {
778 this->saveThreshold();
782 if (mScanType ==
'T') {
783 for (
int ichg = mMin; ichg <= mMax; ichg++) {
784 for (
short int col_i = 0; col_i < this->N_COL; col_i += mColStep) {
785 vCharge[col_i] = ichg;
786 vHits[col_i] = mPixelHits[chipID][
row][col_i][0][ichg - mMin];
794 if (mScanType !=
'P' && mScanType !=
'p' && mScanType !=
'R' && mScanType !=
'r') {
795 this->saveThreshold();
800void ITSThresholdCalibrator::saveThreshold()
803 if (this->mScanType ==
'T' || this->mScanType ==
'D' || this->mScanType ==
'A' || this->mScanType ==
'P' || this->mScanType ==
'p' || this->mScanType ==
'R' || this->mScanType ==
'r') {
804 this->mThresholdTree->Fill();
807 if (this->mScanType !=
'D' && this->mScanType !=
'A' && this->mScanType !=
'P' && this->mScanType !=
'p' && this->mScanType !=
'R' && this->mScanType !=
'r') {
809 int sumT = 0, sumSqT = 0, sumN = 0, sumSqN = 0;
810 int countSuccess = 0, countUnsuccess = 0;
811 for (
int i = 0;
i < this->N_COL;
i++) {
813 sumT += vThreshold[
i];
814 sumN += (
int)vNoise[
i];
815 sumSqT += (vThreshold[
i]) * (vThreshold[
i]);
816 sumSqN += ((
int)vNoise[
i]) * ((
int)vNoise[
i]);
818 if (vThreshold[
i] >= mMin && vThreshold[
i] <= mMax && (mScanType ==
'I' || mScanType ==
'V')) {
819 mpvCounter[vChipid[0]][vThreshold[
i] - mMin]++;
825 short int chipID = vChipid[0];
826 std::array<long int, 6> dataSum{{sumT, sumSqT, sumN, sumSqN, countSuccess, countUnsuccess}};
827 if (!(this->mThresholds.count(chipID))) {
828 this->mThresholds[chipID] = dataSum;
830 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]}};
831 this->mThresholds[chipID] = dataAll;
841void ITSThresholdCalibrator::finalizeOutput()
844 if (!(mScTree) || !(this->mRootOutfile) || !(this->mThresholdTree) || (doSlopeCalculation && !(this->mSlopeTree))) {
849 this->mRootOutfile->cd();
850 this->mThresholdTree->Write(
nullptr, TObject::kOverwrite);
851 this->mScTree->Write(
nullptr, TObject::kOverwrite);
853 if (doSlopeCalculation) {
854 this->mSlopeTree->Write(
nullptr, TObject::kOverwrite);
858 delete this->mThresholdTree;
859 this->mThresholdTree =
nullptr;
862 if (doSlopeCalculation) {
863 delete this->mSlopeTree;
864 this->mSlopeTree =
nullptr;
867 this->mRootOutfile->Close();
868 delete this->mRootOutfile;
869 this->mRootOutfile =
nullptr;
872 std::string dir = this->mOutputDir + fmt::format(
"{}_{}/", mDataTakingContext.
envId, mDataTakingContext.
runNumber);
873 if (!std::filesystem::exists(dir)) {
874 LOG(error) <<
"Cannot find expected output directory " << dir;
881 std::string filenameFull = dir +
filename;
883 std::rename((filenameFull +
".root.part").c_str(),
884 (filenameFull +
".root").c_str());
885 }
catch (std::exception
const& e) {
886 LOG(error) <<
"Failed to rename ROOT file " << filenameFull
887 <<
".root.part, reason: " << e.what();
894 if (!(this->mMetaType.empty())) {
895 mdFile->
type = this->mMetaType;
898 mdFile->
lurl = filenameFull +
".root";
899 auto metaFileNameTmp = fmt::format(
"{}{}.tmp", this->mMetafileDir,
filename);
900 auto metaFileName = fmt::format(
"{}{}.done", this->mMetafileDir,
filename);
902 std::ofstream metaFileOut(metaFileNameTmp);
903 metaFileOut << mdFile->
asString() <<
'\n';
905 std::filesystem::rename(metaFileNameTmp, metaFileName);
906 }
catch (std::exception
const& e) {
907 LOG(error) <<
"Failed to create threshold metadata file "
908 << metaFileName <<
", reason: " << e.what();
922void ITSThresholdCalibrator::setRunType(
const short int& runtype)
926 this->mRunType = runtype;
931 this->mScanType =
'T';
932 this->initThresholdTree();
936 this->mCheckExactRow =
true;
942 this->mScanType =
'T';
943 this->initThresholdTree();
947 this->mCheckExactRow =
true;
959 this->mScanType =
'V';
960 this->mMin = inMinVcasn;
961 this->mMax = inMaxVcasn;
962 this->N_RANGE = mMax - mMin + 1;
963 this->mCheckExactRow =
true;
969 this->mScanType =
'I';
970 this->mMin = inMinIthr;
971 this->mMax = inMaxIthr;
972 this->N_RANGE = mMax - mMin + 1;
973 this->mCheckExactRow =
true;
977 this->mScanType =
'D';
978 this->initThresholdTree();
982 this->N_RANGE = mMax - mMin + 1;
983 this->mCheckExactRow =
false;
987 this->mScanType =
'A';
988 this->initThresholdTree();
992 this->N_RANGE = mMax - mMin + 1;
993 this->mCheckExactRow =
false;
997 this->mScanType =
'P';
998 this->initThresholdTree();
1003 this->mStrobeWindow = 5;
1004 this->N_RANGE = (mMax - mMin) / mStep + 1;
1005 this->mCheckExactRow =
true;
1008 this->mScanType =
'p';
1009 this->initThresholdTree();
1014 this->mStrobeWindow = 2;
1015 this->N_RANGE = (mMax - mMin) / mStep + 1;
1019 this->mCalculate2DParams =
false;
1025 this->N_RANGE2 = (mMax2 - mMin2) / mStep2 + 1;
1026 this->mCheckExactRow =
true;
1028 this->mScanType =
'R';
1035 this->N_RANGE = (mMax - mMin) / mStep + 1;
1037 this->mScanType =
'r';
1041 this->N_RANGE2 = (mMax2 - mMin2) / mStep2 + 1;
1043 this->mCheckExactRow =
true;
1044 this->initThresholdTree();
1047 LOG(error) <<
"Runtype " << runtype <<
" not recognized by calibration workflow (ignore if you are in manual mode)";
1049 LOG(info) <<
"Entering manual mode: be sure to have set all parameters correctly";
1050 this->mScanType = manualScanType[0];
1051 this->mMin = manualMin;
1052 this->mMax = manualMax;
1053 this->mMin2 = manualMin2;
1054 this->mMax2 = manualMax2;
1055 this->mStep = manualStep;
1056 this->mStep2 = manualStep2;
1057 this->mStrobeWindow = manualStrobeWindow;
1058 this->N_RANGE = (mMax - mMin) / mStep + 1;
1059 this->N_RANGE2 = (mMax2 - mMin2) / mStep2 + 1;
1061 this->initThresholdTree();
1063 this->mFitType = (mScanType ==
'D' || mScanType ==
'A' || mScanType ==
'P' || mScanType ==
'p') ?
NO_FIT : mFitType;
1064 this->mCheckExactRow = (mScanType ==
'D' || mScanType ==
'A') ?
false : true;
1073 this->mX =
new float[mScanType ==
'r' ? N_RANGE2 : N_RANGE];
1074 for (
short int i = ((mScanType ==
'r') ? mMin2 : mMin);
i <= ((mScanType ==
'r') ? mMax2 / mStep2 : mMax / mStep);
i++) {
1075 this->mX[
i - (mScanType ==
'r' ? mMin2 : mMin)] = (
float)
i + 0.5;
1079 if (this->mFitType ==
FIT) {
1082 this->mFitHist =
new TH1F(
1083 "mFitHist",
"mFitHist", mScanType ==
'r' ? N_RANGE2 : N_RANGE, mX[0] - 1., mX[(mScanType ==
'r' ? N_RANGE2 : N_RANGE) - 1]);
1086 this->mFitFunction = (this->mScanType ==
'I')
1087 ?
new TF1(
"mFitFunction",
erf_ithr, mMin, mMax, 2)
1088 :
new TF1(
"mFitFunction",
erf, (mScanType ==
'T' || mScanType ==
'r') ? 3 : mMin, mScanType ==
'r' ? mMax2 : mMax, 2);
1089 this->mFitFunction->SetParName(0,
"Threshold");
1090 this->mFitFunction->SetParName(1,
"Noise");
1098std::vector<float> ITSThresholdCalibrator::calculatePulseParams(
const short int& chipID)
1101 int rt_mindel = -1, rt_maxdel = -1, tot_mindel = -1, tot_maxdel = -1;
1102 int sumRt = 0, sumSqRt = 0, countRt = 0, sumTot = 0, sumSqTot = 0, countTot = 0;
1104 for (
auto itrow = mPixelHits[chipID].
begin(); itrow != mPixelHits[chipID].end(); itrow++) {
1105 short int row = itrow->first;
1106 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
1107 for (
short int sdel_i = 0; sdel_i < this->N_RANGE; sdel_i++) {
1108 if (mPixelHits[chipID][
row][col_i][0][sdel_i] > 0 && mPixelHits[chipID][
row][col_i][0][sdel_i] <
nInj && rt_mindel < 0) {
1109 rt_mindel = sdel_i > 0 ? ((sdel_i - 1) * mStep) + 1 : (sdel_i * mStep) + 1;
1111 if (mPixelHits[chipID][
row][col_i][0][sdel_i] ==
nInj) {
1112 rt_maxdel = (sdel_i * mStep) + 1;
1113 tot_mindel = (sdel_i * mStep) + 1;
1118 for (
short int sdel_i = N_RANGE - 1; sdel_i >= 0; sdel_i--) {
1119 if (mPixelHits[chipID][
row][col_i][0][sdel_i] ==
nInj) {
1120 tot_maxdel = (sdel_i * mStep) + 1;
1125 if (tot_maxdel > tot_mindel && tot_mindel >= 0 && tot_maxdel >= 0) {
1126 sumTot += tot_maxdel - tot_mindel - (
int)(mStrobeWindow / 2);
1127 sumSqTot += (tot_maxdel - tot_mindel - (
int)(mStrobeWindow / 2)) * (tot_maxdel - tot_mindel - (
int)(mStrobeWindow / 2));
1131 if (rt_maxdel > rt_mindel && rt_maxdel > 0) {
1132 if (rt_mindel < 0) {
1133 sumRt += mStep + (
int)(mStrobeWindow / 2);
1134 sumSqRt += (mStep + (
int)(mStrobeWindow / 2)) * (mStep + (
int)(mStrobeWindow / 2));
1136 sumRt += rt_maxdel - rt_mindel + (
int)(mStrobeWindow / 2);
1137 sumSqRt += (rt_maxdel - rt_mindel + (
int)(mStrobeWindow / 2)) * (rt_maxdel - rt_mindel + (
int)(mStrobeWindow / 2));
1149 std::vector<float>
output;
1166std::vector<float> ITSThresholdCalibrator::calculatePulseParams2D(
const short int& chipID)
1168 long int sumTot = 0, sumSqTot = 0, countTot = 0;
1169 long int sumMinThr = 0, sumSqMinThr = 0, countMinThr = 0;
1170 long int sumMinThrDel = 0, sumSqMinThrDel = 0;
1171 long int sumMaxPl = 0, sumSqMaxPl = 0, countMaxPl = 0;
1172 long int sumMaxPlChg = 0, sumSqMaxPlChg = 0;
1174 for (
auto itrow = mPixelHits[chipID].
begin(); itrow != mPixelHits[chipID].end(); itrow++) {
1175 short int row = itrow->first;
1176 for (
short int col_i = 0; col_i < this->N_COL; col_i++) {
1177 int minThr = 1e7, minThrDel = 1e7, maxPl = -1, maxPlChg = -1;
1178 int tot_mindel = 1e7;
1179 bool isFound =
false;
1180 for (
short int chg_i = 0; chg_i < this->N_RANGE2; chg_i++) {
1181 for (
short int sdel_i = 0; sdel_i < this->N_RANGE; sdel_i++) {
1182 if (mPixelHits[chipID][
row][col_i][chg_i][sdel_i] ==
nInj) {
1183 minThr = chg_i * mStep2;
1184 minThrDel = (sdel_i * mStep) + 1;
1194 for (
short int sdel_i = this->N_RANGE - 1; sdel_i >= 0; sdel_i--) {
1195 for (
short int chg_i = this->N_RANGE2 - 1; chg_i >= 0; chg_i--) {
1196 if (mPixelHits[chipID][
row][col_i][chg_i][sdel_i] ==
nInj) {
1197 maxPl = (sdel_i * mStep) + 1;
1198 maxPlChg = chg_i * mStep2;
1208 for (
short int sdel_i = 0; sdel_i < this->N_RANGE; sdel_i++) {
1209 for (
short int chg_i = 0; chg_i < this->N_RANGE2; chg_i++) {
1210 if (mPixelHits[chipID][
row][col_i][chg_i][sdel_i] ==
nInj) {
1211 tot_mindel = (sdel_i * mStep) + 1;
1221 if (maxPl > tot_mindel && tot_mindel < 1e7 && maxPl >= 0) {
1222 sumTot += maxPl - tot_mindel - (
int)(mStrobeWindow / 2);
1223 sumSqTot += (maxPl - tot_mindel - (
int)(mStrobeWindow / 2)) * (maxPl - tot_mindel - (
int)(mStrobeWindow / 2));
1228 sumMinThr += minThr;
1229 sumSqMinThr += minThr * minThr;
1230 sumMinThrDel += minThrDel;
1231 sumSqMinThrDel += minThrDel * minThrDel;
1237 sumSqMaxPl += maxPl * maxPl;
1238 sumMaxPlChg += maxPlChg;
1239 sumSqMaxPlChg += maxPlChg * maxPlChg;
1246 std::vector<long int>
values = {sumTot, sumSqTot, countTot, sumMinThr, sumSqMinThr, countMinThr, sumMinThrDel, sumSqMinThrDel, countMinThr, sumMaxPl, sumSqMaxPl, countMaxPl, sumMaxPlChg, sumSqMaxPlChg, countMaxPl};
1247 std::vector<float>
output;
1249 for (
int i = 0;
i <
values.size();
i += 3) {
1254 if (
i == 0 ||
i == 6 ||
i == 9) {
1264void ITSThresholdCalibrator::extractAndUpdate(
const short int& chipID,
const short int&
row)
1267 if ((this->mScanType ==
'T' || this->mScanType ==
'D' || this->mScanType ==
'A' || this->mScanType ==
'P' || this->mScanType ==
'p' || mScanType ==
'R' || mScanType ==
'r') && ((this->mRowCounter)++ == N_ROWS_PER_FILE)) {
1269 this->finalizeOutput();
1270 this->initThresholdTree();
1272 this->mRowCounter = 1;
1276 this->extractThresholdRow(chipID,
row);
1287 if (mRunStopRequested) {
1291 updateTimeDependentParams(pc);
1294 const auto calibs = pc.
inputs().
get<gsl::span<o2::itsmft::GBTCalibData>>(
"calib");
1295 const auto digits = pc.
inputs().
get<gsl::span<o2::itsmft::Digit>>(
"digits");
1296 const auto ROFs = pc.
inputs().
get<gsl::span<o2::itsmft::ROFRecord>>(
"digitsROF");
1299 const unsigned int nROF = (
unsigned int)ROFs.size();
1302 for (
unsigned int iROF = 0; iROF < nROF; iROF++) {
1304 unsigned int rofIndex = ROFs[iROF].getFirstEntry();
1305 unsigned int rofNEntries = ROFs[iROF].getNEntries();
1308 short int loopval = -1, realcharge = 0;
1310 short int cwcnt = -1;
1311 bool isAllZero =
true;
1312 short int ruIndex = -1;
1313 for (
short int iRU = 0; iRU < this->N_RU; iRU++) {
1314 const auto& calib = calibs[iROF * this->N_RU + iRU];
1315 if (calib.calibUserField != 0) {
1321 LOG(warning) <<
"More than one charge detected!";
1324 if (this->mRunType == -1) {
1325 mCdwVersion = isCRUITS ? 0 : ((
short int)(calib.calibUserField >> 45)) & 0x7;
1326 LOG(info) <<
"CDW version: " << mCdwVersion;
1327 short int runtype = isCRUITS ? -2 : !mCdwVersion ? ((
short int)(calib.calibUserField >> 24)) & 0xff
1328 : ((
short int)(calib.calibUserField >> 9)) & 0x7f;
1329 mConfDBv = !mCdwVersion ? ((
short int)(calib.calibUserField >> 32)) & 0xffff : ((
short int)(calib.calibUserField >> 32)) & 0x1fff;
1330 this->setRunType(runtype);
1331 LOG(info) <<
"Calibrator will ship these run parameters to aggregator:";
1332 LOG(info) <<
"Run type : " << mRunType;
1333 LOG(info) <<
"Scan type : " << mScanType;
1335 LOG(info) <<
"DB version (ignore in TOT_CALIB & VRESET2D): " << mConfDBv;
1337 this->mRunTypeUp = isCRUITS ? -1 : !mCdwVersion ? ((
short int)(calib.calibUserField >> 24)) & 0xff
1338 : ((
short int)(calib.calibUserField >> 9)) & 0x7f;
1343 mRunTypeRUCopy[iRU]++;
1346 if (this->mScanType ==
'T') {
1348 loopval = isCRUITS ? (
short int)((calib.calibUserField >> 16) & 0xff) : !mCdwVersion ? (
short int)(170 - (calib.calibUserField >> 16) & 0xff)
1349 : (
short int)(170 - (calib.calibUserField >> 16) & 0xffff);
1350 }
else if (this->mScanType ==
'D' || this->mScanType ==
'A') {
1353 loopval = !mCdwVersion ? (
short int)((calib.calibUserField >> 16) & 0xff) : (
short int)((calib.calibUserField >> 16) & 0xffff);
1356 if (this->mScanType ==
'p' || this->mScanType ==
'r') {
1357 realcharge = 170 - ((
short int)(calib.calibUserField >> 32)) & 0x1fff;
1361 row = !mCdwVersion ? (
short int)(calib.calibUserField & 0xffff) : (
short int)(calib.calibUserField & 0x1ff);
1363 cwcnt = (
short int)(calib.calibCounter);
1365 short int checkVal = (mScanType ==
'I') ? mMin : mMax;
1366 if ((mScanType !=
'r' && loopval == checkVal) || (mScanType ==
'r' && realcharge == mMax2)) {
1367 mCdwCntRU[iRU][
row]++;
1368 mLoopVal[iRU][
row] = loopval;
1370 if (this->mVerboseOutput) {
1371 LOG(info) <<
"RU: " << iRU <<
" CDWcounter: " << cwcnt <<
" row: " <<
row <<
" Loopval: " << loopval <<
" realcharge: " << realcharge <<
" confDBv: " << mCdwVersion;
1372 LOG(info) <<
"NDIGITS: " <<
digits.size();
1379 if (isCRUITS && isAllZero) {
1380 if (mRunType == -1) {
1381 short int runtype = -2;
1383 this->setRunType(runtype);
1384 LOG(info) <<
"Running with CRU_ITS data - Calibrator will ship these run parameters to aggregator:";
1385 LOG(info) <<
"Run type (non-sense) : " << mRunType;
1386 LOG(info) <<
"Scan type : " << mScanType;
1388 LOG(info) <<
"DB version (non-sense): " << mConfDBv;
1396 if (loopval > this->mMax || loopval < this->mMin || ((mScanType ==
'p' || mScanType ==
'r') && (realcharge > this->mMax2 || realcharge < this->mMin2))) {
1397 if (this->mVerboseOutput) {
1398 LOG(warning) <<
"CW issues - loopval value " << loopval <<
" out of range for min " << this->mMin
1399 <<
" and max " << this->mMax <<
" (range: " << N_RANGE <<
")";
1400 if (mScanType ==
'p' || mScanType ==
'r') {
1401 LOG(warning) <<
" and/or realcharge value " << realcharge <<
" out of range from min " << this->mMin2
1402 <<
" and max " << this->mMax2 <<
" (range: " << N_RANGE2 <<
")";
1406 std::vector<short int> mChips;
1407 std::map<short int, bool> mChipsForbRows;
1409 for (
unsigned int idig = rofIndex; idig < rofIndex + rofNEntries; idig++) {
1411 short int chipID = (
short int)d.getChipIndex();
1412 if ((chipID % mChipModBase) != mChipModSel) {
1415 if (d.getRow() !=
row && mVerboseOutput) {
1416 LOG(info) <<
"iROF: " << iROF <<
" ChipID " << chipID <<
": current row is " << d.getRow() <<
" (col = " << d.getColumn() <<
") but the one in CW is " <<
row;
1418 if (std::find(mChips.begin(), mChips.end(), chipID) == mChips.end()) {
1419 mChips.push_back(chipID);
1423 for (
auto& chipID : mChips) {
1425 short int ru = getRUID(chipID);
1426 mActiveLinks[ru][getLinkID(chipID, ru)] =
true;
1428 if (mScanType !=
'r' && mForbiddenRows.count(chipID)) {
1429 for (
int iforb = mForbiddenRows[chipID].
size() - 1; iforb >= 0; iforb--) {
1430 if (mForbiddenRows[chipID][iforb] ==
row) {
1431 mChipsForbRows[chipID] =
true;
1436 if (mChipsForbRows[chipID]) {
1439 if (!this->mPixelHits.count(chipID)) {
1440 if (mScanType ==
'D' || mScanType ==
'A') {
1441 for (
int irow = 0; irow < 512; irow++) {
1442 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)));
1445 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)));
1447 }
else if (!this->mPixelHits[chipID].
count(
row)) {
1448 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)));
1453 short int loopPoint = (loopval - this->mMin) / mStep;
1454 short int chgPoint = (realcharge - this->mMin2) / mStep2;
1455 for (
unsigned int idig = rofIndex; idig < rofIndex + rofNEntries; idig++) {
1457 short int chipID = (
short int)d.getChipIndex();
1458 short int col = (
short int)d.getColumn();
1460 if ((chipID % mChipModBase) != mChipModSel) {
1464 if (!mChipsForbRows[chipID] && (!mCheckExactRow || d.getRow() ==
row) && (mMeb < 0 || cwcnt % 3 == mMeb)) {
1466 this->mPixelHits[chipID][d.getRow()][
col][chgPoint][loopPoint]++;
1477 for (
int iL = 0; iL < 3; iL++) {
1478 if (mActiveLinks[ruIndex][iL]) {
1482 std::vector<short int> chipEnabled = getChipListFromRu(ruIndex, mActiveLinks[ruIndex]);
1484 if (mRunTypeRUCopy[ruIndex] ==
nInjScaled * nL) {
1485 for (
short int iChip = 0; iChip < chipEnabled.size(); iChip++) {
1486 if ((chipEnabled[iChip] % mChipModBase) != mChipModSel) {
1489 addDatabaseEntry(chipEnabled[iChip],
"", std::vector<float>(),
true);
1491 mRunTypeRUCopy[ruIndex] = 0;
1494 bool passCondition = (mCdwCntRU[ruIndex][
row] >=
nInjScaled * nL);
1495 if (mScanType !=
'D' && mScanType !=
'A' && mScanType !=
'P' && mScanType !=
'p' && mScanType !=
'R' && passCondition) {
1497 for (
short int iChip = 0; iChip < chipEnabled.size(); iChip++) {
1498 short int chipID = chipEnabled[iChip];
1499 if ((chipID % mChipModBase) != mChipModSel) {
1502 if (!isDumpS || (std::find(chipDumpList.begin(), chipDumpList.end(), chipID) != chipDumpList.end() || !chipDumpList.size())) {
1503 if (mPixelHits.count(chipID)) {
1504 if (mPixelHits[chipID].
count(
row)) {
1505 extractAndUpdate(chipID,
row);
1506 if (mScanType !=
'r' || (mScanType ==
'r' && mLoopVal[ruIndex][
row] == mMax)) {
1507 mPixelHits[chipID].erase(
row);
1509 mForbiddenRows[chipID].push_back(
row);
1514 mCdwCntRU[ruIndex][
row] = 0;
1518 if (!(this->mRunTypeUp)) {
1520 LOG(info) <<
"Shipping all outputs to aggregator (before endOfStream arrival!)";
1531 mChipDoneQc.clear();
1532 }
else if (pc.
transitionState() == TransitionHandlingState::Requested) {
1533 LOG(info) <<
"Run stop requested during the scan, sending output to aggregator and then stopping to process new data";
1534 mRunStopRequested =
true;
1543 mChipDoneQc.clear();
1556 LOG(info) <<
"Conf DB map retrieved from CCDB";
1557 mConfDBmap = (std::vector<int>*)obj;
1563void ITSThresholdCalibrator::findAverage(
const std::array<long int, 6>&
data,
float& avgT,
float& rmsT,
float& avgN,
float& rmsN)
1565 avgT = (!
data[4]) ? 0. : (float)
data[0] / (float)
data[4];
1566 rmsT = (!
data[4]) ? 0. :
std::sqrt((float)
data[1] / (float)
data[4] - avgT * avgT);
1567 avgN = (!
data[4]) ? 0. : (float)
data[2] / (float)
data[4];
1568 rmsN = (!
data[4]) ? 0. :
std::sqrt((float)
data[3] / (float)
data[4] - avgN * avgN);
1573void ITSThresholdCalibrator::addDatabaseEntry(
1574 const short int& chipID,
const char*
name, std::vector<float>
data,
bool isQC)
1586 int lay, sta, ssta, mod, chipInMod;
1590 snprintf(stave, 6,
"L%d_%02d", lay, sta);
1598 int confDBid = (*mConfDBmap)[chipID];
1601 if (this->mScanType ==
'D' || this->mScanType ==
'A') {
1602 short int vPixDcolCounter[512] = {0};
1603 std::string dcolIDs =
"";
1604 std::string pixIDs_Noisy =
"";
1605 std::string pixIDs_Dead =
"";
1606 std::string pixIDs_Ineff =
"";
1607 std::vector<int>&
v = PixelType ==
"Noisy" ? mNoisyPixID[chipID] : PixelType ==
"Dead" ? mDeadPixID[chipID]
1608 : mIneffPixID[chipID];
1610 int n_pixel =
v.size(), nDcols = 0;
1611 std::string
ds =
"-1";
1613 if (PixelType ==
"Noisy") {
1614 for (
int i = 0;
i <
v.size();
i++) {
1615 short int dcol = ((
v[
i] -
v[
i] % 1000) / 1000) / 2;
1616 vPixDcolCounter[dcol]++;
1618 for (
int i = 0;
i < 512;
i++) {
1619 if (vPixDcolCounter[
i] > N_PIX_DCOL) {
1632 if (this->mTagSinglePix) {
1633 if (PixelType ==
"Noisy") {
1634 for (
int i = 0;
i <
v.size();
i++) {
1635 short int dcol = ((
v[
i] -
v[
i] % 1000) / 1000) / 2;
1636 if (vPixDcolCounter[dcol] > N_PIX_DCOL) {
1642 if (
i + 1 <
v.size()) {
1643 pixIDs_Noisy +=
'|';
1654 if (PixelType ==
"Dead") {
1655 for (
int i = 0;
i <
v.size();
i++) {
1657 if (
i + 1 <
v.size()) {
1663 if (PixelType ==
"Ineff") {
1664 for (
int i = 0;
i <
v.size();
i++) {
1666 if (
i + 1 <
v.size()) {
1667 pixIDs_Ineff +=
'|';
1673 if (!dcolIDs.empty()) {
1679 if (pixIDs_Noisy.empty()) {
1680 pixIDs_Noisy =
"-1";
1683 if (pixIDs_Dead.empty()) {
1687 if (pixIDs_Ineff.empty()) {
1688 pixIDs_Ineff =
"-1";
1692 if (PixelType ==
"Dead" || PixelType ==
"Ineff") {
1702 if (this->mScanType !=
'D' && this->mScanType !=
'A' && this->mScanType !=
'P' && this->mScanType !=
'p') {
1709 if (this->mScanType ==
'T') {
1714 if (this->mScanType ==
'P') {
1724 if (this->mScanType ==
'p') {
1745 static bool initOnceDone =
false;
1746 if (!initOnceDone) {
1747 initOnceDone =
true;
1757 const char*
name =
nullptr;
1758 std::set<int> thisRUs;
1760 if (mScanType ==
'V' || mScanType ==
'I' || mScanType ==
'T') {
1762 name = mScanType ==
'V' ?
"VCASN" : mScanType ==
'I' ?
"ITHR"
1764 if (mScanType ==
'I') {
1766 for (
auto& iRU : mRuSet) {
1767 if (mRunTypeRU[iRU] >=
nInjScaled * getNumberOfActiveLinks(mActiveLinks[iRU]) || mRunStopRequested) {
1768 std::vector<short int> chipList = getChipListFromRu(iRU, mActiveLinks[iRU]);
1769 for (
size_t i = 0;
i < chipList.size();
i++) {
1770 if ((chipList[
i] % mChipModBase) != mChipModSel) {
1773 if (!mThresholds.count(chipList[
i])) {
1774 if (mVerboseOutput) {
1775 LOG(info) <<
"Setting ITHR = 50 for chip " << chipList[
i];
1777 std::vector<float>
data = {50, 0, 0, 0, 0};
1778 addDatabaseEntry(chipList[
i],
name,
data,
false);
1785 auto it = this->mThresholds.cbegin();
1786 while (it != this->mThresholds.cend()) {
1787 short int iRU = getRUID(it->first);
1788 if (!isCRUITS && (mRunTypeRU[iRU] <
nInjScaled * getNumberOfActiveLinks(mActiveLinks[iRU]) && !mRunStopRequested)) {
1792 thisRUs.insert(iRU);
1793 float avgT, rmsT, avgN, rmsN, mpvT, outVal;
1794 this->findAverage(it->second, avgT, rmsT, avgN, rmsN);
1797 mpvT = std::distance(mpvCounter[it->first].begin(), std::max_element(mpvCounter[it->first].begin(), mpvCounter[it->first].end())) + mMin;
1800 if (mVerboseOutput) {
1801 LOG(info) <<
"Average or mpv " <<
name <<
" of chip " << it->first <<
" = " << outVal <<
" e-";
1803 float status = ((float)it->second[4] / (
float)(it->second[4] + it->second[5])) * 100.;
1804 if (status < mPercentageCut && (mScanType ==
'I' || mScanType ==
'V')) {
1805 if (mScanType ==
'I') {
1807 if (mVerboseOutput) {
1808 LOG(info) <<
"Chip " << it->first <<
" status is " << status <<
". Setting ITHR = 50";
1811 it = this->mThresholds.erase(it);
1812 if (mVerboseOutput) {
1813 LOG(info) <<
"Chip " << it->first <<
" status is " << status <<
". Ignoring this chip.";
1818 std::vector<float>
data = {outVal, rmsT, avgN, rmsN, status};
1819 this->addDatabaseEntry(it->first,
name,
data,
false);
1820 it = this->mThresholds.erase(it);
1822 }
else if (this->mScanType ==
'D' || this->mScanType ==
'A') {
1826 auto itchip = this->mPixelHits.cbegin();
1827 while (itchip != this->mPixelHits.cend()) {
1828 short int iRU = getRUID(itchip->first);
1829 if (!isCRUITS && (mRunTypeRU[iRU] <
nInjScaled * getNumberOfActiveLinks(mActiveLinks[iRU]) && !mRunStopRequested)) {
1833 thisRUs.insert(iRU);
1834 if (mVerboseOutput) {
1835 LOG(info) <<
"Extracting hits for the full matrix of chip " << itchip->first;
1837 for (
short int irow = 0; irow < 512; irow++) {
1838 this->extractAndUpdate(itchip->first, irow);
1840 if (this->mVerboseOutput) {
1841 LOG(info) <<
"Chip " << itchip->first <<
" hits extracted";
1846 auto it = this->mNoisyPixID.cbegin();
1847 while (it != this->mNoisyPixID.cend()) {
1848 PixelType =
"Noisy";
1849 if (mVerboseOutput) {
1850 LOG(info) <<
"Extracting noisy pixels in the full matrix of chip " << it->first;
1852 this->addDatabaseEntry(it->first,
name, std::vector<float>(),
false);
1853 if (this->mVerboseOutput) {
1854 LOG(info) <<
"Chip " << it->first <<
" done";
1856 it = this->mNoisyPixID.erase(it);
1859 auto it_d = this->mDeadPixID.cbegin();
1860 while (it_d != this->mDeadPixID.cend()) {
1861 if (mVerboseOutput) {
1862 LOG(info) <<
"Extracting dead pixels in the full matrix of chip " << it_d->first;
1865 this->addDatabaseEntry(it_d->first,
name, std::vector<float>(),
false);
1866 it_d = this->mDeadPixID.erase(it_d);
1869 auto it_ineff = this->mIneffPixID.cbegin();
1870 while (it_ineff != this->mIneffPixID.cend()) {
1871 if (mVerboseOutput) {
1872 LOG(info) <<
"Extracting inefficient pixels in the full matrix of chip " << it_ineff->first;
1874 PixelType =
"Ineff";
1875 this->addDatabaseEntry(it_ineff->first,
name, std::vector<float>(),
false);
1876 it_ineff = this->mIneffPixID.erase(it_ineff);
1878 }
else if (this->mScanType ==
'P' || this->mScanType ==
'p' || mScanType ==
'R') {
1881 auto itchip = this->mPixelHits.cbegin();
1882 while (itchip != mPixelHits.cend()) {
1883 int iRU = getRUID(itchip->first);
1884 if (!mRunStopRequested && mRunTypeRU[iRU] <
nInjScaled * getNumberOfActiveLinks(mActiveLinks[iRU])) {
1888 thisRUs.insert(iRU);
1889 if (mVerboseOutput) {
1890 LOG(info) <<
"Extracting hits from pulse shape scan or vresetd scan, chip " << itchip->first;
1892 auto itrow = this->mPixelHits[itchip->first].cbegin();
1893 while (itrow != mPixelHits[itchip->first].cend()) {
1894 this->extractAndUpdate(itchip->first, itrow->first);
1897 if (mCalculate2DParams && (mScanType ==
'P' || mScanType ==
'p')) {
1898 this->addDatabaseEntry(itchip->first,
name, mScanType ==
'P' ? calculatePulseParams(itchip->first) : calculatePulseParams2D(itchip->first),
false);
1900 if (this->mVerboseOutput) {
1901 LOG(info) <<
"Chip " << itchip->first <<
" hits extracted";
1908 for (
auto& ru : thisRUs) {
1920 if (!isEnded && !mRunStopRequested) {
1921 LOGF(info,
"endOfStream report:", mSelfName);
1925 this->finalizeOutput();
1936 LOGF(info,
"stop() report:", mSelfName);
1937 this->finalizeOutput();
1947 std::vector<InputSpec> inputs;
1948 inputs.emplace_back(
"digits", detOrig,
"DIGITS", 0, Lifetime::Timeframe);
1949 inputs.emplace_back(
"digitsROF", detOrig,
"DIGITSROF", 0, Lifetime::Timeframe);
1950 inputs.emplace_back(
"calib", detOrig,
"GBTCALIB", 0, Lifetime::Timeframe);
1954 std::vector<OutputSpec> outputs;
1955 outputs.emplace_back(
"ITS",
"TSTR", inpConf.
chipModSel);
1956 outputs.emplace_back(
"ITS",
"PIXTYP", inpConf.
chipModSel);
1957 outputs.emplace_back(
"ITS",
"RUNT", inpConf.
chipModSel);
1958 outputs.emplace_back(
"ITS",
"SCANT", inpConf.
chipModSel);
1959 outputs.emplace_back(
"ITS",
"FITT", inpConf.
chipModSel);
1960 outputs.emplace_back(
"ITS",
"CONFDBV", inpConf.
chipModSel);
1961 outputs.emplace_back(
"ITS",
"QCSTR", inpConf.
chipModSel);
1967 AlgorithmSpec{adaptFromTask<ITSThresholdCalibrator>(inpConf)},
1968 Options{{
"fittype", VariantType::String,
"derivative", {
"Fit type to extract thresholds, with options: fit, derivative (default), hitcounting"}},
1969 {
"verbose", VariantType::Bool,
false, {
"Use verbose output mode"}},
1970 {
"output-dir", VariantType::String,
"./", {
"ROOT trees output directory"}},
1971 {
"meta-output-dir", VariantType::String,
"/dev/null", {
"Metadata output directory"}},
1972 {
"meta-type", VariantType::String,
"", {
"metadata type"}},
1973 {
"nthreads", VariantType::Int, 1, {
"Number of threads, default is 1"}},
1974 {
"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"}},
1975 {
"enable-single-pix-tag", VariantType::Bool,
false, {
"Use to enable tagging of single noisy pix in digital and analogue scan"}},
1976 {
"ccdb-mgr-url", VariantType::String,
"", {
"CCDB url to download confDBmap"}},
1977 {
"min-vcasn", VariantType::Int, 30, {
"Min value of VCASN in vcasn scan, default is 30"}},
1978 {
"max-vcasn", VariantType::Int, 70, {
"Max value of VCASN in vcasn scan, default is 70"}},
1979 {
"min-ithr", VariantType::Int, 25, {
"Min value of ITHR in ithr scan, default is 25"}},
1980 {
"max-ithr", VariantType::Int, 100, {
"Max value of ITHR in ithr scan, default is 100"}},
1981 {
"manual-mode", VariantType::Bool,
false, {
"Flag to activate the manual mode in case run type is not recognized"}},
1982 {
"manual-min", VariantType::Int, 0, {
"Min value of the variable used for the scan: use only in manual mode"}},
1983 {
"manual-max", VariantType::Int, 50, {
"Max value of the variable used for the scan: use only in manual mode"}},
1984 {
"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"}},
1985 {
"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"}},
1986 {
"manual-step", VariantType::Int, 1, {
"Step value: defines the steps between manual-min and manual-max. Default is 1. Use only in manual mode"}},
1987 {
"manual-step2", VariantType::Int, 1, {
"Step2 value: defines the steps between manual-min2 and manual-max2. Default is 1. Use only in manual mode"}},
1988 {
"manual-scantype", VariantType::String,
"T", {
"scan type, can be D, T, I, V, P, p: use only in manual mode"}},
1989 {
"manual-strobewindow", VariantType::Int, 5, {
"strobe duration in clock cycles, default is 5 = 125 ns: use only in manual mode"}},
1990 {
"save-tree", VariantType::Bool,
false, {
"Flag to save ROOT tree on disk: use only in manual mode"}},
1991 {
"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"}},
1992 {
"enable-mpv", VariantType::Bool,
false, {
"Flag to enable calculation of most-probable value in vcasn/ithr scans"}},
1993 {
"enable-cru-its", VariantType::Bool,
false, {
"Flag to enable the analysis of raw data on disk produced by CRU_ITS IB commissioning tools"}},
1994 {
"ninj", VariantType::Int, 50, {
"Number of injections per change, default is 50"}},
1995 {
"dump-scurves", VariantType::Bool,
false, {
"Dump any s-curve to disk in ROOT file. Works only with fit option."}},
1996 {
"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"}},
1997 {
"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"}},
1998 {
"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"}},
1999 {
"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"}},
2000 {
"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"}},
2001 {
"meb-select", VariantType::Int, -1, {
"Select from which multi-event buffer consider the hits: 0,1 or 2"}},
2002 {
"s-curve-col-step", VariantType::Int, 8, {
"save s-curves points to tree every s-curve-col-step pixels on 1 row"}},
2003 {
"percentage-cut", VariantType::Int, 25, {
"discard chip in ITHR/VCASN scan if the percentage of success is less than this cut"}}}};
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"
std::vector< Digit > digits