1313// / \file RawDataQcTask.cxx
1414// / \author Marek Bombara
1515// / \author Lucia Anna Tarasovicova
16+ // / \author Jan Musinsky
17+ // / \date 2026-02-17
1618// /
1719
1820#include < TCanvas.h>
21+ #include < TLine.h>
1922#include < TH1.h>
2023
2124#include " QualityControl/QcInfoLogger.h"
2225#include " CTP/RawDataQcTask.h"
26+ #include < DataFormatsParameters/GRPLHCIFData.h>
27+ #include < DetectorsBase/GRPGeomHelper.h>
2328#include " DetectorsRaw/RDHUtils.h"
2429#include " Headers/RAWDataHeader.h"
2530#include " DataFormatsCTP/Digits.h"
@@ -37,6 +42,15 @@ namespace o2::quality_control_modules::ctp
3742
3843CTPRawDataReaderTask::~CTPRawDataReaderTask ()
3944{
45+ for (auto & h : mHisInputs ) {
46+ delete h;
47+ }
48+ for (auto & h : mHisInputsNotLHC ) { // must be before mHisInputsYesLHC
49+ delete h;
50+ }
51+ for (auto & h : mHisInputsYesLHC ) {
52+ delete h;
53+ }
4054}
4155
4256void CTPRawDataReaderTask::initialize (o2::framework::InitContext& /* ctx*/ )
@@ -57,6 +71,27 @@ void CTPRawDataReaderTask::initialize(o2::framework::InitContext& /*ctx*/)
5771 getObjectsManager ()->startPublishing (mHistoInputRatios .get ());
5872 getObjectsManager ()->startPublishing (mHistoBCMinBias1 .get ());
5973 getObjectsManager ()->startPublishing (mHistoBCMinBias2 .get ());
74+ std::string sTmp1 , sTmp2 ;
75+ for (std::size_t i = 0 ; i < mHisInputs .size (); i++) {
76+ sTmp1 = std::format (" input{:02}" , i);
77+ sTmp2 = std::format (" input[{:02}] {}" , i, o2::ctp::CTPInputsConfiguration::getInputNameFromIndex (i + 1 ));
78+ // getInputNameFromIndex in range [1-48]
79+ mHisInputs [i] = new TH1D (sTmp1 .c_str (), sTmp2 .c_str (), norbits, 0 , norbits);
80+
81+ sTmp1 = std::format (" input{:02}_yesLHC" , i);
82+ mHisInputsYesLHC [i] = new TH1D (sTmp1 .c_str (), sTmp2 .c_str (), norbits, 0 , norbits);
83+ mHisInputsYesLHC [i]->SetLineColor (kGreen + 2 );
84+ mHisInputsYesLHC [i]->SetFillColor (kGreen + 2 );
85+
86+ sTmp1 = std::format (" input{:02}_notLHC" , i);
87+ mHisInputsNotLHC [i] = new TH1D (sTmp1 .c_str (), sTmp2 .c_str (), norbits, 0 , norbits);
88+ mHisInputsNotLHC [i]->SetLineColor (kRed + 1 );
89+ mHisInputsNotLHC [i]->SetFillColor (kRed + 1 );
90+
91+ getObjectsManager ()->startPublishing (mHisInputs [i]);
92+ getObjectsManager ()->startPublishing (mHisInputsYesLHC [i]);
93+ // getObjectsManager()->startPublishing(mHisInputsNotLHC[i]);
94+ }
6095
6196 mDecoder .setDoLumi (1 );
6297 mDecoder .setDoDigits (1 );
@@ -76,9 +111,19 @@ void CTPRawDataReaderTask::startOfActivity(const Activity& activity)
76111 mHistoInputRatios ->Reset ();
77112 mHistoBCMinBias1 ->Reset ();
78113 mHistoBCMinBias2 ->Reset ();
114+ for (auto & h : mHisInputs ) {
115+ h->Reset ();
116+ }
117+ for (auto & h : mHisInputsYesLHC ) {
118+ h->Reset (" ICES" );
119+ }
120+ for (auto & h : mHisInputsNotLHC ) {
121+ h->Reset ();
122+ }
79123
80124 mRunNumber = activity.mId ;
81125 mTimestamp = activity.mValidity .getMin ();
126+ readLHCFillingScheme (); // call after mTimestamp is set
82127
83128 std::string readCTPConfig = getFromExtendedConfig<std::string>(activity, mCustomParameters , " readCTPconfigInMonitorData" , " false" );
84129 if (readCTPConfig == " true" ) {
@@ -211,8 +256,21 @@ void CTPRawDataReaderTask::startOfActivity(const Activity& activity)
211256 mDecoder .setCheckConsistency (1 );
212257 mDecoder .setDecodeInps (1 );
213258 mPerformConsistencyCheck = true ;
259+ for (std::size_t i = 0 ; i < shiftBC.size (); i++) {
260+ shiftBC[i] = 0 ; // no shift
261+ }
214262 } else {
215263 mDecoder .setCheckConsistency (0 );
264+ for (std::size_t i = 0 ; i < shiftBC.size (); i++) {
265+ if (i <= 10 ) {
266+ shiftBC[i] = 0 ; // [00-10] without shift
267+ }
268+ if (i >= 11 && i <= 23 ) {
269+ shiftBC[i] = 15 ; // [11-23] shift by 15 BCs
270+ } else if (i >= 24 && i <= 47 ) {
271+ shiftBC[i] = 296 ; // [24-47] shift by 296 BCs
272+ }
273+ }
216274 }
217275
218276 if (mPerformConsistencyCheck ) {
@@ -284,7 +342,7 @@ void CTPRawDataReaderTask::monitorData(o2::framework::ProcessingContext& ctx)
284342 for (auto const digit : outputDigits) {
285343 uint16_t bcid = digit.intRecord .bc ;
286344 if (digit.CTPInputMask .count ()) {
287- for (int i = 0 ; i < o2::ctp::CTP_NINPUTS ; i++) {
345+ for (int i = 0 ; i < mUsedInputsMax ; i++) {
288346 if (digit.CTPInputMask [i]) {
289347 mHistoInputs ->getNum ()->Fill (i);
290348 mHistoInputRatios ->getNum ()->Fill (i);
@@ -297,6 +355,9 @@ void CTPRawDataReaderTask::monitorData(o2::framework::ProcessingContext& ctx)
297355 int bc = bcid - mShiftInput2 >= 0 ? bcid - mShiftInput2 : bcid - mShiftInput2 + 3564 ;
298356 mHistoBCMinBias2 ->Fill (bc, 1 . / mScaleInput2 );
299357 }
358+ // int bc = (bcid - shiftBC[i]) >= 0 ? bcid - shiftBC[i] : bcid - shiftBC[i] + o2::constants::lhc::LHCMaxBunches;
359+ int bc = bcid - shiftBC[i];
360+ mHisInputs [i]->Fill (bc);
300361 }
301362 }
302363 }
@@ -327,6 +388,60 @@ void CTPRawDataReaderTask::endOfCycle()
327388 mHistoInputRatios ->update ();
328389 mHistoClasses ->update ();
329390 mHistoClassRatios ->update ();
391+ splitSortInputs ();
392+ }
393+
394+ void CTPRawDataReaderTask::splitSortInputs ()
395+ {
396+ struct BC { // BC (Bunch Crossing)
397+ int id; // id [0-3563]
398+ double entries; // number of entries for id
399+ // TH1::GetBinContent(i) return always double over TH1::RetrieveBinContent(i) implemented in TH1*
400+ };
401+
402+ std::vector<BC> BCs; // ?! std::array<BC, 3564> BCs = {} ?!
403+ for (std::size_t ih = 0 ; ih < mHisInputs .size (); ih++) {
404+ if (mHisInputs [ih]->GetEntries () == 0 ) {
405+ continue ;
406+ }
407+ BCs.clear ();
408+ for (int ib = 1 ; ib <= mHisInputs [ih]->GetNbinsX (); ib++) { // skip underflow bin
409+ BCs.emplace_back (ib - 1 , mHisInputs [ih]->GetBinContent (ib));
410+ }
411+
412+ std::sort (BCs.begin (), BCs.end (),
413+ [](const BC& a, const BC& b) { return a.entries > b.entries ; }); // sort by BC.entries
414+ // std::cout << "size: " << BCs.size() << std::endl;
415+ // for (const BC& bc : BCs) {
416+ // std::cout << "BC.id: " << std::setw(4) << bc.id << ", BC.entries: " << bc.entries << std::endl;
417+ // }
418+
419+ mHisInputsYesLHC [ih]->Reset (" ICES" ); // don't delete mHisInputsNotLHC[ih] object
420+ mHisInputsNotLHC [ih]->Reset ();
421+ for (std::size_t ibc = 0 ; ibc < BCs.size (); ibc++) { // skip underflow bin (in loop)
422+ if (mLHCBCs .test (BCs[ibc].id )) {
423+ mHisInputsYesLHC [ih]->SetBinContent (ibc + 1 , BCs[ibc].entries );
424+ } else {
425+ mHisInputsNotLHC [ih]->SetBinContent (ibc + 1 , BCs[ibc].entries );
426+ }
427+ }
428+
429+ TLine* line = nullptr ;
430+ if (!mHisInputsYesLHC [ih]->FindObject (mHisInputsNotLHC [ih])) { // only once
431+ // temporary hack: hisNotLHC->Draw("same")
432+ mHisInputsYesLHC [ih]->GetListOfFunctions ()->Add (mHisInputsNotLHC [ih], " same" );
433+ // temporary hack: line->Draw("same")
434+ line = new TLine (mLHCBCs .count (), 0 , mLHCBCs .count (), mHisInputsYesLHC [ih]->GetMaximum () * 1.05 );
435+ line->SetLineStyle (kDotted );
436+ line->SetLineColor (mHisInputsYesLHC [ih]->GetLineColor ());
437+ mHisInputsYesLHC [ih]->GetListOfFunctions ()->Add (line, " same" );
438+ } else { // always set Y2 line maximum (is different for each cycle)
439+ line = dynamic_cast <TLine*>(mHisInputsYesLHC [ih]->FindObject (" TLine" ));
440+ if (line) {
441+ line->SetY2 (mHisInputsYesLHC [ih]->GetMaximum () * 1.05 );
442+ }
443+ }
444+ }
330445}
331446
332447void CTPRawDataReaderTask::endOfActivity (const Activity& /* activity*/ )
@@ -345,8 +460,46 @@ void CTPRawDataReaderTask::reset()
345460 mHistoClassRatios ->Reset ();
346461 mHistoBCMinBias1 ->Reset ();
347462 mHistoBCMinBias2 ->Reset ();
463+ for (auto & h : mHisInputs ) {
464+ h->Reset ();
465+ }
466+ for (auto & h : mHisInputsYesLHC ) {
467+ h->Reset (" ICES" );
468+ }
469+ for (auto & h : mHisInputsNotLHC ) {
470+ h->Reset ();
471+ }
348472 if (mPerformConsistencyCheck )
349473 mHistoDecodeError ->Reset ();
350474}
351475
476+ void CTPRawDataReaderTask::readLHCFillingScheme ()
477+ {
478+ // mTimestamp = activity.mValidity.getMin(); // set in startOfActivity()
479+ //
480+ // manually added timestamps corresponding to known fills and runs (for testing)
481+ // mTimestamp = 1716040930304 + 1; // fill: 9644, run: 551731
482+ // mTimestamp = 1754317528872 + 1; // fill: 10911, run: 565118
483+ // mTimestamp = 1760845636156 + 1; // fill: 11203, run: 567147
484+
485+ std::map<std::string, std::string> metadata; // can be empty
486+ auto lhcifdata = UserCodeInterface::retrieveConditionAny<o2::parameters::GRPLHCIFData>(" GLO/Config/GRPLHCIF" , metadata, mTimestamp );
487+ if (lhcifdata == nullptr ) {
488+ ILOG (Info, Support) << " LHC data not found for (task) timestamp:" << mTimestamp << ENDM;
489+ lhcDataFileFound = false ;
490+ return ;
491+ } else {
492+ ILOG (Info, Support) << " LHC data found for (task) timestamp:" << mTimestamp << ENDM;
493+ lhcDataFileFound = true ;
494+ // lhcifdata->print();
495+ }
496+ auto bfilling = lhcifdata->getBunchFilling ();
497+ std::vector<int > bcs = bfilling.getFilledBCs ();
498+ mLHCBCs .reset ();
499+ for (auto const & bc : bcs) {
500+ mLHCBCs .set (bc, 1 );
501+ }
502+ // ?! test on mLHCBCs.size() == or <= o2::constants::lhc::LHCMaxBunches ?!
503+ }
504+
352505} // namespace o2::quality_control_modules::ctp
0 commit comments