2121#include " ITSMFTReconstruction/ClustererParam.h"
2222#include " DetectorsCommonDataFormats/DetectorNameConf.h"
2323#include " DataFormatsITSMFT/PhysTrigger.h"
24+ #include " ITSMFTReconstruction/ChipMappingITS.h"
25+ #include " ITSMFTReconstruction/ChipMappingMFT.h"
2426
2527using namespace o2 ::framework;
2628
@@ -29,25 +31,28 @@ namespace o2
2931namespace itsmft
3032{
3133
32- EntropyDecoderSpec::EntropyDecoderSpec (o2::header::DataOrigin orig, int verbosity, bool getDigits)
33- : mOrigin (orig), mCTFCoder (o2::ctf::CTFCoderBase::OpType::Decoder, orig == o2::header::gDataOriginITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT), mGetDigits (getDigits)
34+ template <int N>
35+ EntropyDecoderSpec<N>::EntropyDecoderSpec(int verbosity, bool getDigits)
36+ : mCTFCoder (o2::ctf::CTFCoderBase::OpType::Decoder, N), mGetDigits (getDigits)
3437{
3538 assert (orig == o2::header::gDataOriginITS || orig == o2::header::gDataOriginMFT );
36- mDetPrefix = orig == o2::header::gDataOriginITS ? " _ITS" : " _MFT" ;
39+ mDetPrefix = Origin == o2::header::gDataOriginITS ? " _ITS" : " _MFT" ;
3740 mTimer .Stop ();
3841 mTimer .Reset ();
3942 mCTFCoder .setVerbosity (verbosity);
4043 mCTFCoder .setDictBinding (std::string (" ctfdict" ) + mDetPrefix );
4144}
4245
43- void EntropyDecoderSpec::init (o2::framework::InitContext& ic)
46+ template <int N>
47+ void EntropyDecoderSpec<N>::init(o2::framework::InitContext& ic)
4448{
4549 mCTFCoder .init <CTF>(ic);
4650 mMaskNoise = ic.options ().get <bool >(" mask-noise" );
4751 mUseClusterDictionary = !ic.options ().get <bool >(" ignore-cluster-dictionary" );
4852}
4953
50- void EntropyDecoderSpec::run (ProcessingContext& pc)
54+ template <int N>
55+ void EntropyDecoderSpec<N>::run(ProcessingContext& pc)
5156{
5257 if (pc.services ().get <o2::framework::TimingInfo>().globalRunNumberChanged ) {
5358 mTimer .Reset ();
@@ -63,33 +68,105 @@ void EntropyDecoderSpec::run(ProcessingContext& pc)
6368 // this produces weird memory problems in unrelated devices, to be understood
6469 // auto& trigs = pc.outputs().make<std::vector<o2::itsmft::PhysTrigger>>(OutputRef{"phystrig"}); // dummy output
6570
66- auto & rofs = pc.outputs ().make <std::vector<o2::itsmft::ROFRecord>>(OutputRef{" ROframes" });
67- if (mGetDigits ) {
68- auto & digits = pc.outputs ().make <std::vector<o2::itsmft::Digit>>(OutputRef{" Digits" });
69- if (buff.size ()) {
70- iosize = mCTFCoder .decode (o2::itsmft::CTF::getImage (buff.data ()), rofs, digits, mNoiseMap , mPattIdConverter );
71+ if constexpr (DPLAlpideParam<N>::supportsStaggering ()) {
72+ // for now we need to 'mock' the staggered output and sort ordering ourselves
73+ std::vector<o2::itsmft::ROFRecord> rofs;
74+ std::vector<o2::itsmft::Digit> digits;
75+ std::vector<o2::itsmft::CompClusterExt> clusters;
76+ std::vector<unsigned char > patterns;
77+ // do the actual read
78+ if (mGetDigits ) {
79+ if (buff.size ()) {
80+ iosize = mCTFCoder .decode (o2::itsmft::CTF::getImage (buff.data ()), rofs, digits, mNoiseMap , mPattIdConverter );
81+ }
82+ mTimer .Stop ();
83+ LOG (info) << " Decoded " << digits.size () << " digits in " << rofs.size () << " RO frames, (" << iosize.asString () << " ) in " << mTimer .CpuTime () - cput << " s" ;
84+ } else {
85+ if (buff.size ()) {
86+ iosize = mCTFCoder .decode (o2::itsmft::CTF::getImage (buff.data ()), rofs, clusters, patterns, mNoiseMap , mPattIdConverter );
87+ }
88+ mTimer .Stop ();
89+ LOG (info) << " Decoded " << clusters.size () << " clusters in " << rofs.size () << " RO frames, (" << iosize.asString () << " ) in " << mTimer .CpuTime () - cput << " s" ;
90+ }
91+ std::array<std::vector<o2::itsmft::ROFRecord>, NLayers> rofsPerLayer;
92+ std::array<std::vector<o2::itsmft::Digit>, NLayers> digitsPerLayer;
93+ std::array<std::vector<o2::itsmft::CompClusterExt>, NLayers> clustersPerLayer;
94+ std::array<std::vector<unsigned char >, NLayers> patternsPerLayer;
95+ std::array<std::vector<int >, NLayers> firstEntries;
96+ std::array<std::vector<int >, NLayers> nEntries;
97+ for (int iLayer{0 }; iLayer < NLayers; ++iLayer) {
98+ rofsPerLayer[iLayer] = rofs;
99+ firstEntries[iLayer].resize (rofs.size (), 0 );
100+ nEntries[iLayer].resize (rofs.size (), 0 );
101+ }
102+ // now we need to filter the data per layer
103+ // TODO implement also for cluster input
104+ for (size_t iROF{0 }; iROF < rofs.size (); ++iROF) {
105+ const auto & rof = rofs[iROF];
106+ for (int iEntry{rof.getFirstEntry ()}; iEntry < (rof.getFirstEntry () + rof.getNEntries ()); ++iEntry) {
107+ const auto & dig = digits[iEntry];
108+ int lay = ChipMappingITS::getLayer (dig.getChipIndex ());
109+ digitsPerLayer[lay].push_back (dig);
110+ ++(nEntries[lay][iROF]);
111+ }
112+ }
113+ for (int iLayer{0 }; iLayer < NLayers; ++iLayer) {
114+ std::exclusive_scan (nEntries[iLayer].begin (), nEntries[iLayer].end (), firstEntries[iLayer].begin (), 0 );
115+ for (int iROF{0 }; iROF < rofs.size (); ++iROF) {
116+ rofsPerLayer[iLayer][iROF].setFirstEntry (firstEntries[iLayer][iROF]);
117+ rofsPerLayer[iLayer][iROF].setNEntries (nEntries[iLayer][iROF]);
118+ }
119+ }
120+ for (uint32_t iLayer{0 }; iLayer < NLayers; ++iLayer) {
121+ pc.outputs ().snapshot (OutputRef{" ROframes" , iLayer}, rofsPerLayer[iLayer]);
122+ if (mGetDigits ) {
123+ pc.outputs ().snapshot (OutputRef{" Digits" , iLayer}, digitsPerLayer[iLayer]);
124+ } else {
125+ pc.outputs ().snapshot (OutputRef{" compClusters" , iLayer}, clustersPerLayer[iLayer]);
126+ pc.outputs ().snapshot (OutputRef{" patterns" , iLayer}, patternsPerLayer[iLayer]);
127+ }
71128 }
72- mTimer .Stop ();
73- LOG (info) << " Decoded " << digits.size () << " digits in " << rofs.size () << " RO frames, (" << iosize.asString () << " ) in " << mTimer .CpuTime () - cput << " s" ;
74129 } else {
75- auto & compcl = pc.outputs ().make <std::vector<o2::itsmft::CompClusterExt>>(OutputRef{" compClusters" });
76- auto & patterns = pc.outputs ().make <std::vector<unsigned char >>(OutputRef{" patterns" });
77- if (buff.size ()) {
78- iosize = mCTFCoder .decode (o2::itsmft::CTF::getImage (buff.data ()), rofs, compcl, patterns, mNoiseMap , mPattIdConverter );
130+ auto & rofs = pc.outputs ().make <std::vector<o2::itsmft::ROFRecord>>(OutputRef{" ROframes" , 0 });
131+ if (mGetDigits ) {
132+ auto & digits = pc.outputs ().make <std::vector<o2::itsmft::Digit>>(OutputRef{" Digits" , 0 });
133+ if (buff.size ()) {
134+ iosize = mCTFCoder .decode (o2::itsmft::CTF::getImage (buff.data ()), rofs, digits, mNoiseMap , mPattIdConverter );
135+ }
136+ mTimer .Stop ();
137+ LOG (info) << " Decoded " << digits.size () << " digits in " << rofs.size () << " RO frames, (" << iosize.asString () << " ) in " << mTimer .CpuTime () - cput << " s" ;
138+ } else {
139+ auto & compcl = pc.outputs ().make <std::vector<o2::itsmft::CompClusterExt>>(OutputRef{" compClusters" , 0 });
140+ auto & patterns = pc.outputs ().make <std::vector<unsigned char >>(OutputRef{" patterns" , 0 });
141+ if (buff.size ()) {
142+ iosize = mCTFCoder .decode (o2::itsmft::CTF::getImage (buff.data ()), rofs, compcl, patterns, mNoiseMap , mPattIdConverter );
143+ }
144+ mTimer .Stop ();
145+ LOG (info) << " Decoded " << compcl.size () << " clusters in " << rofs.size () << " RO frames, (" << iosize.asString () << " ) in " << mTimer .CpuTime () - cput << " s" ;
146+ }
147+ // hack: output empty messages to avoid dropping the TF
148+ for (uint32_t iLayer{1 }; iLayer < NLayers; ++iLayer) {
149+ pc.outputs ().make <std::vector<o2::itsmft::ROFRecord>>(OutputRef{" ROframes" , iLayer});
150+ if (mGetDigits ) {
151+ pc.outputs ().make <std::vector<o2::itsmft::Digit>>(OutputRef{" Digits" , iLayer});
152+ } else {
153+ pc.outputs ().make <std::vector<o2::itsmft::CompClusterExt>>(OutputRef{" compClusters" , iLayer});
154+ pc.outputs ().make <std::vector<unsigned char >>(OutputRef{" patterns" , iLayer});
155+ }
79156 }
80- mTimer .Stop ();
81- LOG (info) << " Decoded " << compcl.size () << " clusters in " << rofs.size () << " RO frames, (" << iosize.asString () << " ) in " << mTimer .CpuTime () - cput << " s" ;
82157 }
83158 pc.outputs ().snapshot ({" ctfrep" , 0 }, iosize);
84- }
159+ } // namespace itsmft
85160
86- void EntropyDecoderSpec::endOfStream (EndOfStreamContext& ec)
161+ template <int N>
162+ void EntropyDecoderSpec<N>::endOfStream(EndOfStreamContext& ec)
87163{
88164 LOGF (info, " %s Entropy Decoding total timing: Cpu: %.3e Real: %.3e s in %d slots" ,
89- mOrigin .as <std::string>(), mTimer .CpuTime (), mTimer .RealTime (), mTimer .Counter () - 1 );
165+ Origin .as <std::string>(), mTimer .CpuTime (), mTimer .RealTime (), mTimer .Counter () - 1 );
90166}
91167
92- void EntropyDecoderSpec::updateTimeDependentParams (ProcessingContext& pc)
168+ template <int N>
169+ void EntropyDecoderSpec<N>::updateTimeDependentParams(ProcessingContext& pc)
93170{
94171 if (pc.services ().get <o2::framework::TimingInfo>().globalRunNumberChanged ) { // this params need to be queried only once
95172 if (mMaskNoise ) {
@@ -102,15 +179,16 @@ void EntropyDecoderSpec::updateTimeDependentParams(ProcessingContext& pc)
102179 mCTFCoder .updateTimeDependentParams (pc, true );
103180}
104181
105- void EntropyDecoderSpec::finaliseCCDB (o2::framework::ConcreteDataMatcher& matcher, void * obj)
182+ template <int N>
183+ void EntropyDecoderSpec<N>::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void * obj)
106184{
107- if (matcher == ConcreteDataMatcher (mOrigin , " NOISEMAP" , 0 )) {
185+ if (matcher == ConcreteDataMatcher (Origin , " NOISEMAP" , 0 )) {
108186 mNoiseMap = (o2::itsmft::NoiseMap*)obj;
109- LOG (info) << mOrigin .as <std::string>() << " noise map updated" ;
187+ LOG (info) << Origin .as <std::string>() << " noise map updated" ;
110188 return ;
111189 }
112- if (matcher == ConcreteDataMatcher (mOrigin , " CLUSDICT" , 0 )) {
113- LOG (info) << mOrigin .as <std::string>() << " cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : " " );
190+ if (matcher == ConcreteDataMatcher (Origin , " CLUSDICT" , 0 )) {
191+ LOG (info) << Origin .as <std::string>() << " cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : " " );
114192 mPattIdConverter .setDictionary ((const TopologyDictionary*)obj);
115193 return ;
116194 }
@@ -119,42 +197,52 @@ void EntropyDecoderSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matche
119197 }
120198}
121199
122- DataProcessorSpec getEntropyDecoderSpec (o2::header::DataOrigin orig, int verbosity, bool getDigits, unsigned int sspec)
200+ template <int N>
201+ DataProcessorSpec getEntropyDecoderSpec (int verbosity, bool getDigits, unsigned int sspec)
123202{
203+ using EntropyDecoder = EntropyDecoderSpec<N>;
204+
205+ std::string det = EntropyDecoder::Origin.template as <std::string>();
206+ std::string nm = " _" + det;
207+ std::vector<InputSpec> inputs;
208+ inputs.emplace_back (std::string (" ctf" ) + nm, EntropyDecoder::Origin, " CTFDATA" , sspec, Lifetime::Timeframe);
209+ inputs.emplace_back (std::string (" noise" ) + nm, EntropyDecoder::Origin, " NOISEMAP" , 0 , Lifetime::Condition, ccdbParamSpec (fmt::format (" {}/Calib/NoiseMap" , det)));
210+ inputs.emplace_back (std::string (" cldict" ) + nm, EntropyDecoder::Origin, " CLUSDICT" , 0 , Lifetime::Condition, ccdbParamSpec (fmt::format (" {}/Calib/ClusterDictionary" , det)));
211+ inputs.emplace_back (std::string (" ctfdict" ) + nm, EntropyDecoder::Origin, " CTFDICT" , 0 , Lifetime::Condition, ccdbParamSpec (fmt::format (" {}/Calib/CTFDictionaryTree" , det)));
212+ inputs.emplace_back (std::string (" trigoffset" ), " CTP" , " Trig_Offset" , 0 , Lifetime::Condition, ccdbParamSpec (" CTP/Config/TriggerOffsets" ));
213+
124214 std::vector<OutputSpec> outputs;
125215 // this is a special dummy input which makes sense only in sync workflows
126216
127217 // this produces weird memory problems in unrelated devices, to be understood
128218 // outputs.emplace_back(OutputSpec{{"phystrig"}, orig, "PHYSTRIG", 0, Lifetime::Timeframe});
129219
130- if (getDigits) {
131- outputs.emplace_back (OutputSpec{{" Digits" }, orig, " DIGITS" , 0 , Lifetime::Timeframe});
132- outputs.emplace_back (OutputSpec{{" ROframes" }, orig, " DIGITSROF" , 0 , Lifetime::Timeframe});
133- } else {
134- outputs.emplace_back (OutputSpec{{" compClusters" }, orig, " COMPCLUSTERS" , 0 , Lifetime::Timeframe});
135- outputs.emplace_back (OutputSpec{{" ROframes" }, orig, " CLUSTERSROF" , 0 , Lifetime::Timeframe});
136- outputs.emplace_back (OutputSpec{{" patterns" }, orig, " PATTERNS" , 0 , Lifetime::Timeframe});
220+ for (uint32_t iLayer{0 }; iLayer < EntropyDecoder::NLayers; ++iLayer) {
221+ if (getDigits) {
222+ outputs.emplace_back (OutputSpec{{" Digits" }, EntropyDecoder::Origin, " DIGITS" , iLayer, Lifetime::Timeframe});
223+ outputs.emplace_back (OutputSpec{{" ROframes" }, EntropyDecoder::Origin, " DIGITSROF" , iLayer, Lifetime::Timeframe});
224+ } else {
225+ outputs.emplace_back (OutputSpec{{" compClusters" }, EntropyDecoder::Origin, " COMPCLUSTERS" , iLayer, Lifetime::Timeframe});
226+ outputs.emplace_back (OutputSpec{{" ROframes" }, EntropyDecoder::Origin, " CLUSTERSROF" , iLayer, Lifetime::Timeframe});
227+ outputs.emplace_back (OutputSpec{{" patterns" }, EntropyDecoder::Origin, " PATTERNS" , iLayer, Lifetime::Timeframe});
228+ }
137229 }
138- outputs.emplace_back (OutputSpec{{" ctfrep" }, orig, " CTFDECREP" , 0 , Lifetime::Timeframe});
139- std::string nm = orig == o2::header::gDataOriginITS ? " _ITS" : " _MFT" ;
140- std::vector<InputSpec> inputs;
141- inputs.emplace_back (std::string (" ctf" ) + nm, orig, " CTFDATA" , sspec, Lifetime::Timeframe);
142- inputs.emplace_back (std::string (" noise" ) + nm, orig, " NOISEMAP" , 0 , Lifetime::Condition, ccdbParamSpec (fmt::format (" {}/Calib/NoiseMap" , orig.as <std::string>())));
143- inputs.emplace_back (std::string (" cldict" ) + nm, orig, " CLUSDICT" , 0 , Lifetime::Condition, ccdbParamSpec (fmt::format (" {}/Calib/ClusterDictionary" , orig.as <std::string>())));
144- inputs.emplace_back (std::string (" ctfdict" ) + nm, orig, " CTFDICT" , 0 , Lifetime::Condition, ccdbParamSpec (fmt::format (" {}/Calib/CTFDictionaryTree" , orig.as <std::string>())));
145- inputs.emplace_back (std::string (" trigoffset" ), " CTP" , " Trig_Offset" , 0 , Lifetime::Condition, ccdbParamSpec (" CTP/Config/TriggerOffsets" ));
230+ outputs.emplace_back (OutputSpec{{" ctfrep" }, EntropyDecoder::Origin, " CTFDECREP" , 0 , Lifetime::Timeframe});
146231
147232 return DataProcessorSpec{
148- EntropyDecoderSpec::getName (orig) ,
149- inputs,
150- outputs,
151- AlgorithmSpec{adaptFromTask<EntropyDecoderSpec>(orig, verbosity, getDigits)},
152- Options{
233+ . name = EntropyDecoder::DeviceName ,
234+ . inputs = inputs,
235+ . outputs = outputs,
236+ . algorithm = AlgorithmSpec{adaptFromTask<EntropyDecoder>( verbosity, getDigits)},
237+ . options = Options{
153238 {" ctf-dict" , VariantType::String, " ccdb" , {" CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename" }},
154239 {" mask-noise" , VariantType::Bool, false , {" apply noise mask to digits or clusters (involves reclusterization)" }},
155240 {" ignore-cluster-dictionary" , VariantType::Bool, false , {" do not use cluster dictionary, always store explicit patterns" }},
156- {" ans -version" , VariantType::String, {" version of ans entropy coder implementation to use" }}}};
241+ {" and -version" , VariantType::String, {" version of and entropy coder implementation to use" }}}};
157242}
158243
244+ framework::DataProcessorSpec getITSEntropyDecoderSpec (int verbosity, bool getDigits, unsigned int sspec) { return getEntropyDecoderSpec<o2::detectors::DetID::ITS>(verbosity, getDigits, sspec); }
245+ framework::DataProcessorSpec getMFTEntropyDecoderSpec (int verbosity, bool getDigits, unsigned int sspec) { return getEntropyDecoderSpec<o2::detectors::DetID::MFT>(verbosity, getDigits, sspec); }
246+
159247} // namespace itsmft
160248} // namespace o2
0 commit comments