Skip to content

Commit 1db48b2

Browse files
authored
MCH: implement custom inputs spec for raw decoder (#5350)
The input dataspec might vary from the default "TF:MCH/RAWDATA", for example when a data sampling device is inserted beteen the raw proxy and the decoder. This PR allows to specify the input dataspec as a command-line option, giving more flexibility to the DPL chain. The documentation is updated accordingly. There is also some improvement in the textual output of the digits sink.
1 parent 93eccad commit 1db48b2

File tree

8 files changed

+185
-19
lines changed

8 files changed

+185
-19
lines changed

Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/OrbitInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class OrbitInfo
4242

4343
friend bool operator==(const OrbitInfo& o1, const OrbitInfo& o2);
4444
friend bool operator!=(const OrbitInfo& o1, const OrbitInfo& o2);
45+
friend bool operator<(const OrbitInfo& o1, const OrbitInfo& o2);
4546

4647
private:
4748
uint64_t mOrbitInfo = {0};
@@ -51,6 +52,7 @@ class OrbitInfo
5152

5253
bool operator==(const OrbitInfo& o1, const OrbitInfo& o2);
5354
bool operator!=(const OrbitInfo& o1, const OrbitInfo& o2);
55+
bool operator<(const OrbitInfo& o1, const OrbitInfo& o2);
5456

5557
} //namespace mch
5658
} //namespace o2

Detectors/MUON/MCH/Raw/Decoder/src/OrbitInfo.cxx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,9 @@ bool operator!=(const OrbitInfo& o1, const OrbitInfo& o2)
3939
return !(o1 == o2);
4040
}
4141

42+
bool operator<(const OrbitInfo& o1, const OrbitInfo& o2)
43+
{
44+
return (o1.mOrbitInfo < o2.mOrbitInfo);
45+
}
46+
4247
} // namespace o2::mch

Detectors/MUON/MCH/Workflow/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ o2_add_executable(
3434
COMPONENT_NAME mch
3535
PUBLIC_LINK_LIBRARIES O2::MCHWorkflow)
3636

37+
o2_add_executable(
38+
raw-debug-workflow
39+
SOURCES src/raw-debug-workflow.cxx
40+
COMPONENT_NAME mch
41+
PUBLIC_LINK_LIBRARIES O2::MCHWorkflow)
42+
3743
o2_add_executable(
3844
cru-page-to-digits-workflow
3945
SOURCES src/cru-page-to-digits-workflow.cxx

Detectors/MUON/MCH/Workflow/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727

2828
`o2-mch-raw-to-digits-workflow`
2929

30+
The workflow accepts the following options:
31+
32+
* `--debug`: enable verbose output
33+
* `--dataspec`: selection string for the input data (default: `"TF:MCH/RAWDATA"`)
34+
* `--cru-map`: path to custom CRU mapping file
35+
* `--fec-map`: path to custom FEC mapping file
36+
* `--ds2manu`: convert channel numbering from Run3 to Run1-2 order
37+
3038
## Digits to preclusters
3139

3240
`o2-mch-digits-to-preclusters-workflow`

Detectors/MUON/MCH/Workflow/src/DataDecoderSpec.cxx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,35 +59,36 @@ using RDH = o2::header::RDHAny;
5959
class DataDecoderTask
6060
{
6161
public:
62+
DataDecoderTask(std::string spec) : mInputSpec(spec) {}
63+
6264
//_________________________________________________________________________________________________
6365
void init(framework::InitContext& ic)
6466
{
6567
SampaChannelHandler channelHandler;
6668
RdhHandler rdhHandler;
6769

6870
auto ds2manu = ic.options().get<bool>("ds2manu");
69-
mPrint = ic.options().get<bool>("print");
71+
mDebug = ic.options().get<bool>("debug");
7072
auto mapCRUfile = ic.options().get<std::string>("cru-map");
7173
auto mapFECfile = ic.options().get<std::string>("fec-map");
7274

73-
mDecoder = new DataDecoder(channelHandler, rdhHandler, mapCRUfile, mapFECfile, ds2manu, mPrint);
75+
mDecoder = new DataDecoder(channelHandler, rdhHandler, mapCRUfile, mapFECfile, ds2manu, mDebug);
7476
}
7577

7678
//_________________________________________________________________________________________________
77-
// the decodeTF() function processes the the messages generated by the (sub)TimeFrame builder
79+
// the decodeTF() function processes the messages generated by the (sub)TimeFrame builder
7880
void decodeTF(framework::ProcessingContext& pc)
7981
{
8082
// get the input buffer
8183
auto& inputs = pc.inputs();
82-
DPLRawParser parser(inputs, o2::framework::select("TF:MCH/RAWDATA"));
84+
DPLRawParser parser(inputs, o2::framework::select(mInputSpec.c_str()));
8385

8486
for (auto it = parser.begin(), end = parser.end(); it != end; ++it) {
85-
auto const* rdh = it.get_if<RDH>();
8687
auto const* raw = it.raw();
87-
size_t payloadSize = it.size();
88-
if (payloadSize == 0) {
88+
if (!raw) {
8989
continue;
9090
}
91+
size_t payloadSize = it.size();
9192

9293
gsl::span<const std::byte> buffer(reinterpret_cast<const std::byte*>(raw), sizeof(RDH) + payloadSize);
9394
mDecoder->decodeBuffer(buffer);
@@ -113,7 +114,7 @@ class DataDecoderTask
113114
// size of payload
114115
size_t payloadSize = header->payloadSize;
115116

116-
if (mPrint) {
117+
if (mDebug) {
117118
std::cout << nFrame << " payloadSize=" << payloadSize << std::endl;
118119
}
119120
nFrame += 1;
@@ -156,7 +157,7 @@ class DataDecoderTask
156157
auto& digits = mDecoder->getOutputDigits();
157158
auto& orbits = mDecoder->getOrbits();
158159

159-
if (mPrint) {
160+
if (mDebug) {
160161
for (auto d : digits) {
161162
std::cout << " DE# " << d.getDetID() << " PadId " << d.getPadID() << " ADC " << d.getADC() << " time " << d.getTime().sampaTime << std::endl;
162163
}
@@ -173,19 +174,21 @@ class DataDecoderTask
173174
}
174175

175176
private:
176-
bool mPrint = {false};
177-
DataDecoder* mDecoder = {nullptr};
177+
std::string mInputSpec; /// selection string for the input data
178+
bool mDebug = {false}; /// flag to enable verbose output
179+
DataDecoder* mDecoder = {nullptr}; /// pointer to the data decoder instance
178180
};
179181

180182
//_________________________________________________________________________________________________
181183
o2::framework::DataProcessorSpec getDecodingSpec(std::string inputSpec)
182184
{
185+
o2::mch::raw::DataDecoderTask task(inputSpec);
183186
return DataProcessorSpec{
184187
"DataDecoder",
185188
o2::framework::select(inputSpec.c_str()),
186189
Outputs{OutputSpec{"MCH", "DIGITS", 0, Lifetime::Timeframe}, OutputSpec{"MCH", "ORBITS", 0, Lifetime::Timeframe}},
187-
AlgorithmSpec{adaptFromTask<DataDecoderTask>()},
188-
Options{{"print", VariantType::Bool, false, {"print digits"}},
190+
AlgorithmSpec{adaptFromTask<DataDecoderTask>(std::move(task))},
191+
Options{{"debug", VariantType::Bool, false, {"enable verbose output"}},
189192
{"cru-map", VariantType::String, "", {"custom CRU mapping"}},
190193
{"fec-map", VariantType::String, "", {"custom FEC mapping"}},
191194
{"ds2manu", VariantType::Bool, false, {"convert channel numbering from Run3 to Run1-2 order"}}}};

Detectors/MUON/MCH/Workflow/src/digits-sink-workflow.cxx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,13 @@ class DigitsSinkTask
8484
// get the input digits
8585
auto digits = pc.inputs().get<gsl::span<Digit>>("digits");
8686
auto orbits = pc.inputs().get<gsl::span<OrbitInfo>>("orbits");
87+
std::set<OrbitInfo> ordered_orbits(orbits.begin(), orbits.end());
8788

8889
if (mText) {
89-
for (auto o : orbits) {
90-
mOutputFile << std::endl
91-
<< " FEEID " << o.getFeeID() << " LINK " << (int)o.getLinkID() << " ORBIT " << o.getOrbit() << std::endl;
90+
mOutputFile << std::endl
91+
<< "=======================" << std::endl;
92+
for (auto o : ordered_orbits) {
93+
mOutputFile << " FEEID " << o.getFeeID() << " LINK " << (int)o.getLinkID() << " ORBIT " << o.getOrbit() << std::endl;
9294
}
9395
mOutputFile << "---------------" << std::endl;
9496
for (auto d : digits) {
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
11+
///
12+
/// \file raw-parser.cxx
13+
/// \author Andrea Ferrero
14+
///
15+
/// \brief This is an executable that receives the TimeFrames from the raw proxy and prints the sequence of RDHs.
16+
///
17+
/// This is an executable that receives the TimeFrames from the raw proxy and prints the sequence of RDHs.
18+
/// Useful for debugging the DPL workflows involving input RAW data.
19+
///
20+
21+
#include <iostream>
22+
#include "Framework/WorkflowSpec.h"
23+
#include "Framework/DataSpecUtils.h"
24+
#include "Framework/CallbackService.h"
25+
#include "Framework/ControlService.h"
26+
#include "Framework/Task.h"
27+
28+
#include "Framework/ConfigParamSpec.h"
29+
#include "Framework/CompletionPolicyHelpers.h"
30+
31+
#include "Headers/RAWDataHeader.h"
32+
#include "DetectorsRaw/RDHUtils.h"
33+
#include "DPLUtils/DPLRawParser.h"
34+
35+
using namespace o2::framework;
36+
37+
void customize(std::vector<ConfigParamSpec>& workflowOptions)
38+
{
39+
workflowOptions.push_back(ConfigParamSpec{"dataspec", VariantType::String, "TF:MCH/RAWDATA", {"selection string for the input data"}});
40+
}
41+
42+
#include "Framework/runDataProcessing.h"
43+
44+
using namespace o2;
45+
using namespace o2::framework;
46+
using RDH = o2::header::RDHAny;
47+
48+
namespace o2
49+
{
50+
namespace mch
51+
{
52+
namespace raw
53+
{
54+
55+
//=======================
56+
// Data parser
57+
class DataParserTask
58+
{
59+
public:
60+
DataParserTask(std::string spec) : mInputSpec(spec) {}
61+
62+
//_________________________________________________________________________________________________
63+
void init(framework::InitContext& ic)
64+
{
65+
}
66+
67+
void decodeBuffer(gsl::span<const std::byte> page){};
68+
69+
//_________________________________________________________________________________________________
70+
void run(framework::ProcessingContext& pc)
71+
{
72+
// get the input buffer
73+
DPLRawParser parser(pc.inputs(), o2::framework::select(mInputSpec.c_str()));
74+
75+
int nRDH = 0;
76+
77+
const std::byte* raw = nullptr;
78+
for (auto it = parser.begin(), end = parser.end(); it != end; ++it) {
79+
raw = reinterpret_cast<const std::byte*>(it.raw());
80+
if (!raw) {
81+
continue;
82+
}
83+
84+
auto* rdh = reinterpret_cast<const RDH*>(raw);
85+
86+
if (nRDH == 0) {
87+
std::cout << std::endl
88+
<< "---------------" << std::endl;
89+
o2::raw::RDHUtils::printRDH(rdh);
90+
//std::cout << "......." << std::endl;
91+
}
92+
nRDH += 1;
93+
}
94+
95+
if (false && raw) {
96+
auto* rdh = reinterpret_cast<const RDH*>(raw);
97+
o2::raw::RDHUtils::printRDH(rdh);
98+
}
99+
std::cout << "---------------" << std::endl;
100+
}
101+
102+
private:
103+
std::string mInputSpec;
104+
};
105+
106+
} // namespace raw
107+
} // namespace mch
108+
} // end namespace o2
109+
110+
WorkflowSpec defineDataProcessing(const ConfigContext& config)
111+
{
112+
auto inputSpec = config.options().get<std::string>("dataspec");
113+
114+
WorkflowSpec specs;
115+
116+
o2::mch::raw::DataParserTask task(inputSpec);
117+
DataProcessorSpec parser{
118+
"RawParser",
119+
o2::framework::select(inputSpec.c_str()),
120+
Outputs{},
121+
AlgorithmSpec{adaptFromTask<o2::mch::raw::DataParserTask>(std::move(task))},
122+
Options{}};
123+
124+
specs.push_back(parser);
125+
126+
return specs;
127+
}

Detectors/MUON/MCH/Workflow/src/raw-to-digits-workflow.cxx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,30 @@
2323
#include "Framework/CallbackService.h"
2424
#include "Framework/ControlService.h"
2525
#include "Framework/Task.h"
26-
#include "Framework/runDataProcessing.h"
26+
27+
#include "Framework/ConfigParamSpec.h"
28+
#include "Framework/CompletionPolicyHelpers.h"
2729
#include "MCHWorkflow/DataDecoderSpec.h"
2830

31+
using namespace o2::framework;
32+
33+
void customize(std::vector<ConfigParamSpec>& workflowOptions)
34+
{
35+
workflowOptions.push_back(ConfigParamSpec{"dataspec", VariantType::String, "TF:MCH/RAWDATA", {"selection string for the input data"}});
36+
}
37+
38+
#include "Framework/runDataProcessing.h"
39+
2940
using namespace o2;
3041
using namespace o2::framework;
3142

32-
WorkflowSpec defineDataProcessing(const ConfigContext&)
43+
WorkflowSpec defineDataProcessing(const ConfigContext& config)
3344
{
45+
auto inputSpec = config.options().get<std::string>("dataspec");
46+
3447
WorkflowSpec specs;
3548

36-
DataProcessorSpec producer = o2::mch::raw::getDecodingSpec();
49+
DataProcessorSpec producer = o2::mch::raw::getDecodingSpec(inputSpec);
3750
specs.push_back(producer);
3851

3952
return specs;

0 commit comments

Comments
 (0)