1717#include " DataFormatsITSMFT/Digit.h"
1818#include " DataFormatsITSMFT/CompCluster.h"
1919#include " DataFormatsITSMFT/TimeDeadMap.h"
20+ #include " ITSMFTReconstruction/DecodingStat.h"
21+ #include < TFile.h>
22+ #include < TTree.h>
2023
2124namespace o2
2225{
@@ -87,6 +90,20 @@ void ITSMFTDeadMapBuilder::init(InitContext& ic)
8790
8891 LOG (info) << " Sampling one TF every " << mTFSampling << " with " << mTFSamplingTolerance << " TF tolerance" ;
8992
93+ mStuckPixelFileName = ic.options ().get <std::string>(" save-stuck-pixels" );
94+
95+ if (!mRunMFT && !mStuckPixelFileName .empty ()) {
96+ LOG (info) << " Stuck pixel saving ENABLED. Output file: " << mStuckPixelFileName ;
97+ mErrorTree = new TTree (" ErrorTree" , " Stuck Pixel Errors" );
98+ mErrorTree ->SetDirectory (nullptr );
99+ mErrorTree ->Branch (" orbit" , &mErrOrbit , " orbit/L" );
100+ mErrorTree ->Branch (" chipid" , &mErrChipID , " chipid/S" );
101+ mErrorTree ->Branch (" row" , &mErrRow , " row/S" );
102+ mErrorTree ->Branch (" col" , &mErrCol , " col/S" );
103+ } else {
104+ LOG (info) << " Stuck pixel saving DISABLED." ;
105+ }
106+
90107 return ;
91108}
92109
@@ -172,6 +189,21 @@ void ITSMFTDeadMapBuilder::finalizeOutput()
172189 outfile.WriteObjectAny (&mMapObject , " o2::itsmft::TimeDeadMap" , " ccdb_object" );
173190 outfile.Close ();
174191 }
192+
193+ if (mErrorTree && !mStuckPixelFileName .empty ()) {
194+ std::string stuckOutFileName = mLocalOutputDir + " /" + mStuckPixelFileName ;
195+ TFile stuckOutFile (stuckOutFileName.c_str (), " RECREATE" );
196+
197+ if (!stuckOutFile.IsZombie ()) {
198+ stuckOutFile.cd ();
199+ mErrorTree ->Write ();
200+ stuckOutFile.Close ();
201+ LOG (info) << " Stuck Pixel Tree saved to separate file: " << stuckOutFileName;
202+ } else {
203+ LOG (error) << " Failed to open " << stuckOutFileName << " for stuck pixel tree." ;
204+ }
205+ }
206+
175207 return ;
176208}
177209
@@ -213,6 +245,21 @@ void ITSMFTDeadMapBuilder::run(ProcessingContext& pc)
213245 }
214246
215247 mStepCounter ++;
248+
249+ if (mErrorTree ) {
250+ const auto repErrors = pc.inputs ().get <gsl::span<o2::itsmft::ErrorMessage>>(" repErr" );
251+ for (const auto & err : repErrors) {
252+ if (err.errType == o2::itsmft::ChipStat::RepeatingPixel) {
253+ mErrOrbit = (long )mFirstOrbitTF ;
254+ mErrChipID = (short )err.id ;
255+ mErrRow = (short )err.errInfo0 ;
256+ mErrCol = (short )err.errInfo1 ;
257+
258+ mErrorTree ->Fill ();
259+ }
260+ }
261+ }
262+
216263 LOG (info) << " Processing step #" << mStepCounter << " out of " << mTFCounter << " good TF received. First orbit " << mFirstOrbitTF ;
217264
218265 mDeadMapTF .clear ();
@@ -304,84 +351,96 @@ void ITSMFTDeadMapBuilder::run(ProcessingContext& pc)
304351}
305352
306353// ////////////////////////////////////////////////////////////////////////////
307- void ITSMFTDeadMapBuilder::PrepareOutputCcdb (EndOfStreamContext* ec, std::string ccdburl = " " )
354+ void ITSMFTDeadMapBuilder::PrepareOutputCcdb (EndOfStreamContext* ec, std::string ccdburl)
308355{
309-
310- // if ccdburl is specified, the object is sent to ccdb from this workflow
311-
312356 long tend = o2::ccdb::getCurrentTimestamp ();
313-
314357 std::map<std::string, std::string> md = {{" map_version" , MAP_VERSION }, {" runNumber" , std::to_string (mRunNumber )}};
315-
316358 std::string path = mRunMFT ? " MFT/Calib/" : " ITS/Calib/" ;
317- std::string name_str = " TimeDeadMap" ;
318359
319- o2::ccdb::CcdbObjectInfo info ((path + name_str), name_str, mObjectName , md, mTimeStart - 120 * 1000 , tend + 60 * 1000 );
320360
321- auto image = o2::ccdb::CcdbApi::createObjectImage (&mMapObject , &info);
322- info.setFileName (mObjectName );
361+ if (mMapObject .getEvolvingMapSize () > 0 ) {
362+ std::string name_str = " TimeDeadMap" ;
363+ o2::ccdb::CcdbObjectInfo info ((path + name_str), name_str, mObjectName , md, mTimeStart - 120 * 1000 , tend + 60 * 1000 );
364+ auto image = o2::ccdb::CcdbApi::createObjectImage (&mMapObject , &info);
365+ info.setFileName (mObjectName );
366+ info.setAdjustableEOV ();
323367
324- info.setAdjustableEOV ();
325-
326- if (ec != nullptr ) {
327-
328- LOG (important) << " Sending object " << info.getPath () << " /" << info.getFileName ()
329- << " to ccdb-populator, of size " << image->size () << " bytes, valid for "
330- << info.getStartValidityTimestamp () << " : " << info.getEndValidityTimestamp ();
331-
332- if (mRunMFT ) {
333- ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBPayload , " TimeDeadMap" , 1 }, *image.get ());
334- ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBWrapper , " TimeDeadMap" , 1 }, info);
335- } else {
336- ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBPayload , " TimeDeadMap" , 0 }, *image.get ());
337- ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBWrapper , " TimeDeadMap" , 0 }, info);
368+ if (ec != nullptr ) {
369+ LOG (important) << " Sending object " << info.getPath () << " /" << info.getFileName ()
370+ << " to ccdb-populator, of size " << image->size () << " bytes" ;
371+ if (mRunMFT ) {
372+ ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBPayload , " TimeDeadMap" , 1 }, *image.get ());
373+ ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBWrapper , " TimeDeadMap" , 1 }, info);
374+ } else {
375+ ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBPayload , " TimeDeadMap" , 0 }, *image.get ());
376+ ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBWrapper , " TimeDeadMap" , 0 }, info);
377+ }
378+ } else if (!ccdburl.empty ()) {
379+ LOG (important) << mSelfName << " sending object " << ccdburl << " /browse/" << info.getPath () << " /" << info.getFileName ();
380+ o2::ccdb::CcdbApi mApi ;
381+ mApi .init (ccdburl);
382+ mApi .storeAsBinaryFile (
383+ &image->at (0 ), image->size (), info.getFileName (), info.getObjectType (),
384+ info.getPath (), info.getMetaData (),
385+ info.getStartValidityTimestamp (), info.getEndValidityTimestamp ());
386+ o2::ccdb::adjustOverriddenEOV (mApi , info);
338387 }
388+ } else {
389+ LOG (warning) << " Time-dependent dead map is empty and will not be forwarded as output" ;
339390 }
340391
341- else if (!ccdburl.empty ()) { // send from this workflow
342392
343- LOG (important) << mSelfName << " sending object " << ccdburl << " /browse/" << info.getPath () << " /" << info.getFileName ()
344- << " of size " << image->size () << " bytes, valid for "
345- << info.getStartValidityTimestamp () << " : " << info.getEndValidityTimestamp ();
393+ if (mErrorTree && !mStuckPixelFileName .empty ()) {
394+ std::string name_sp = " StuckPixels" ;
395+ o2::ccdb::CcdbObjectInfo info_sp ((path + name_sp), name_sp, mStuckPixelFileName , md, mTimeStart - 120 * 1000 , tend + 60 * 1000 );
396+
346397
347- o2::ccdb::CcdbApi mApi ;
348- mApi .init (ccdburl);
349- mApi .storeAsBinaryFile (
350- &image->at (0 ), image->size (), info.getFileName (), info.getObjectType (),
351- info.getPath (), info.getMetaData (),
352- info.getStartValidityTimestamp (), info.getEndValidityTimestamp ());
353- o2::ccdb::adjustOverriddenEOV (mApi , info);
354- }
398+ auto image_sp = o2::ccdb::CcdbApi::createObjectImage (mErrorTree , &info_sp);
399+ info_sp.setFileName (mStuckPixelFileName );
400+ info_sp.setAdjustableEOV ();
355401
356- else {
402+ if (ec != nullptr ) {
403+ LOG (important) << " Sending StuckPixels object to ccdb-populator, Path: " << info_sp.getPath ();
404+ if (mRunMFT ) {
405+ ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBPayload , " StuckPixels" , 1 }, *image_sp.get ());
406+ ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBWrapper , " StuckPixels" , 1 }, info_sp);
407+ } else {
408+ ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBPayload , " StuckPixels" , 0 }, *image_sp.get ());
409+ ec->outputs ().snapshot (Output{o2::calibration::Utils::gDataOriginCDBWrapper , " StuckPixels" , 0 }, info_sp);
410+ }
411+ } else if (!ccdburl.empty ()) {
412+ LOG (important) << mSelfName << " sending StuckPixels to external CCDB: " << ccdburl << " /browse/" << info_sp.getPath ();
413+ o2::ccdb::CcdbApi mApi_sp ;
414+ mApi_sp .init (ccdburl);
415+ mApi_sp .storeAsBinaryFile (
416+ &image_sp->at (0 ), image_sp->size (), info_sp.getFileName (), info_sp.getObjectType (),
417+ info_sp.getPath (), info_sp.getMetaData (),
418+ info_sp.getStartValidityTimestamp (), info_sp.getEndValidityTimestamp ());
419+ o2::ccdb::adjustOverriddenEOV (mApi_sp , info_sp);
420+ }
357421
358- LOG (warning) << " PrepareOutputCcdb called with empty arguments. Doing nothing." ;
422+ delete mErrorTree ;
423+ mErrorTree = nullptr ;
359424 }
360425
361426 return ;
362427}
363428
364429// ////////////////////////////////////////////////////////////////////////////
365- // O2 functionality allowing to do post-processing when the upstream device
366- // tells that there will be no more input data
367430void ITSMFTDeadMapBuilder::endOfStream (EndOfStreamContext& ec)
368431{
369432 if (!isEnded) {
370433 LOG (info) << " endOfStream report: " << mSelfName ;
371434 finalizeOutput ();
372- if (mMapObject .getEvolvingMapSize () > 0 ) {
373- PrepareOutputCcdb (&ec);
374- } else {
375- LOG (warning) << " Time-dependent dead map is empty and will not be forwarded as output" ;
376- }
435+ // 데이터 유무 및 업로드 조건 처리를 내부에서 독립적으로 검증하도록 PrepareOutputCcdb를 무조건 호출구조로 변경
436+ PrepareOutputCcdb (&ec);
377437 LOG (info) << " Stop process of new data because of endOfStream" ;
378438 isEnded = true ;
379439 }
380440 return ;
381441}
382442
383443// ////////////////////////////////////////////////////////////////////////////
384- // DDS stop method: create local output if endOfStream not processed
385444void ITSMFTDeadMapBuilder::stop ()
386445{
387446 if (!isEnded) {
@@ -421,12 +480,18 @@ DataProcessorSpec getITSMFTDeadMapBuilderSpec(std::string datasource, bool doMFT
421480 } else if (datasource == " chipsstatus" ) {
422481 inputs.emplace_back (" elements" , detOrig, " CHIPSSTATUS" , 0 , Lifetime::Timeframe);
423482 } else {
424- return DataProcessorSpec{0x0 }; // TODO: ADD PROTECTION
483+ return DataProcessorSpec{0x0 };
425484 }
426485
486+ inputs.emplace_back (" repErr" , detOrig, " ErrorInfo" , 0 , Lifetime::Timeframe);
487+
427488 std::vector<OutputSpec> outputs;
489+
428490 outputs.emplace_back (ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload , " TimeDeadMap" }, Lifetime::Sporadic);
429491 outputs.emplace_back (ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper , " TimeDeadMap" }, Lifetime::Sporadic);
492+ // New CCDB for StuckPixels
493+ outputs.emplace_back (ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload , " StuckPixels" }, Lifetime::Sporadic);
494+ outputs.emplace_back (ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper , " StuckPixels" }, Lifetime::Sporadic);
430495
431496 std::string detector = doMFT ? " mft" : " its" ;
432497 std::string objectname_default = detector + " _time_deadmap.root" ;
@@ -445,8 +510,11 @@ DataProcessorSpec getITSMFTDeadMapBuilderSpec(std::string datasource, bool doMFT
445510 {" ccdb-url" , VariantType::String, " " , {" CCDB url. Ignored if endOfStream is processed." }},
446511 {" outfile" , VariantType::String, objectname_default, {" ROOT object file name." }},
447512 {" local-output" , VariantType::Bool, false , {" Save ROOT tree file locally." }},
448- {" output-dir" , VariantType::String, " ./" , {" ROOT tree local output directory." }}}};
513+ {" output-dir" , VariantType::String, " ./" , {" ROOT tree local output directory." }},
514+
515+ {" save-stuck-pixels" , VariantType::String, " " , {" Save stuck pixels to a separate ROOT file. If empty, stuck pixel computation is disabled." }}
516+ }};
449517}
450518
451519} // namespace itsmft
452- } // namespace o2
520+ } // namespace o2
0 commit comments