Skip to content

Commit d855329

Browse files
dstoccoaphecetche
authored andcommitted
MID afterburner for digits synchronization with collision BC
1 parent f06d999 commit d855329

9 files changed

Lines changed: 453 additions & 30 deletions

File tree

Detectors/MUON/MID/Workflow/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ o2_add_library(
1313
MIDWorkflow
1414
TARGETVARNAME targetName
1515
SOURCES src/ClusterizerSpec.cxx
16+
src/ColumnDataSpecsUtils.cxx
1617
src/DecodedDataAggregatorSpec.cxx
1718
src/DigitReaderSpec.cxx
1819
src/EntropyDecoderSpec.cxx
@@ -26,6 +27,7 @@ o2_add_library(
2627
src/RawGBTDecoderSpec.cxx
2728
src/RawInputSpecHandler.cxx
2829
src/RawWriterSpec.cxx
30+
src/TimingSpec.cxx
2931
src/TrackerSpec.cxx
3032
src/TrackReaderSpec.cxx
3133
src/ZeroSuppressionSpec.cxx

Detectors/MUON/MID/Workflow/README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ The MID contribution can be added to CTF by attaching the `o2-mid-entropy-encode
8989
o2-raw-file-reader-workflow --input-conf MIDraw.cfg | o2-mid-raw-to-digits-workflow | o2-mid-entropy-encoder-workflow | o2-ctf-writer-workflow
9090
```
9191

92-
### Timing
92+
### CPU timing
9393

9494
In each device belonging to the reconstruction workflow, the execution time is measured using the `chrono` c++ library.
9595
At the end of the execution, when the *stop* command is launched, the execution time is written to the `LOG(info)`.
@@ -102,6 +102,19 @@ Processing time / 90 ROFs: full: 3.55542 us tracking: 2.02182 us
102102
Two timing values are provided: one is for the full execution of the device (including retrieval and sending of the DPL messages) and one which concerns only the execution of the algorithm (the tracking algorithm in the above example)
103103
The timing refers to the time needed to process one read-out-frame, i.e. one event.
104104

105+
### Afterburner
106+
107+
There is an offset between the collision BC and the BC that can be obtained from the electronics clock.
108+
This offset is in principle accounted for when decoding the raw data.
109+
However, the precise value of this offset depends on the delays that chosen electronics delay, and some adjustment might be needed.
110+
To avoid having to regenerate the CTF, the time offset of the digits can be adjusted on-the-fly by running the reconstruction with the option:
111+
112+
```bash
113+
o2-mid-reco-workflow --change-local-to-BC <value>
114+
```
115+
116+
where `<value>` is the chosen offset in number of BCs (can be negative).
117+
105118
### Reconstruction options
106119

107120
By default, the reconstruction produces clusters and tracks that are written on file.

Detectors/MUON/MID/Workflow/include/MIDWorkflow/ClusterizerSpec.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
#define O2_MID_CLUSTERIZERSPEC_H
1919

2020
#include "Framework/DataProcessorSpec.h"
21+
#include <string_view>
2122

2223
namespace o2
2324
{
2425
namespace mid
2526
{
26-
framework::DataProcessorSpec getClusterizerSpec(bool isMC);
27+
framework::DataProcessorSpec getClusterizerSpec(bool isMC, std::string_view inDataDesc, std::string_view inRofDesc, std::string_view inLabelsDesc);
2728
}
2829
} // namespace o2
2930

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
/// \file MIDWorkflow/ColumnDataSpecsUtils.h
13+
/// \brief Utilities for MID Column Data Specs
14+
/// \author Diego Stocco <Diego.Stocco at cern.ch>
15+
/// \date 05 April 2022
16+
17+
#ifndef O2_MID_COLUMNDATASPECSUTILS_H
18+
#define O2_MID_COLUMNDATASPECSUTILS_H
19+
20+
#include <array>
21+
#include <memory>
22+
#include <string>
23+
#include <string_view>
24+
#include <vector>
25+
#include <gsl/span>
26+
#include "fmt/format.h"
27+
28+
#include "Framework/DataAllocator.h"
29+
#include "Framework/InputRecordWalker.h"
30+
#include "Framework/InputSpec.h"
31+
#include "Framework/OutputSpec.h"
32+
#include "Framework/ProcessingContext.h"
33+
#include "SimulationDataFormat/MCTruthContainer.h"
34+
#include "DataFormatsMID/ColumnData.h"
35+
#include "DataFormatsMID/ROFRecord.h"
36+
#include "MIDSimulation/MCLabel.h"
37+
38+
namespace o2
39+
{
40+
namespace mid
41+
{
42+
namespace specs
43+
{
44+
45+
/// Returns the input specs for MID Column Data and corresponding ROFs and labels
46+
/// \param dataBind Data binding name
47+
/// \param dataDesc Input data description
48+
/// \param useMC Builds output specs for labels
49+
/// \return Vector of input specs
50+
std::vector<framework::InputSpec> buildInputSpecs(std::string_view dataBind, std::string_view dataDesc, bool useMC);
51+
52+
/// Returns the input specs for MID Column Data and corresponding ROFs and labels
53+
/// \param dataBind Data binding name
54+
/// \param dataDesc Input data description
55+
/// \param rofDesc Input ROF record description
56+
/// \param labelsDesc Input MC labels description
57+
/// \param useMC Builds output specs for labels
58+
/// \return Vector of input specs
59+
std::vector<framework::InputSpec> buildInputSpecs(std::string_view dataBind, std::string_view dataDesc, std::string_view rofDesc, std::string_view labelsDesc, bool useMC);
60+
61+
/// Returns the output specs for the different event types
62+
/// \param bind Binding name
63+
/// \param description Output data description
64+
/// \return Vector of Output specs
65+
std::vector<framework::OutputSpec> buildOutputSpecs(std::string_view bind, std::string_view description);
66+
67+
/// Returns the output specs for MID Column Data and corresponding ROFs and labels
68+
/// \param dataBind Data binding name
69+
/// \param dataDesc Output data description
70+
/// \param useMC Builds output specs for labels
71+
/// \return Vector of Output specs
72+
std::vector<framework::OutputSpec> buildStandardOutputSpecs(std::string_view dataBind, std::string_view dataDesc, bool useMC);
73+
74+
/// Returns the inputs for the different event types
75+
/// \param pc Processing context
76+
/// \param bind Binding name
77+
/// \return Array of spans
78+
template <typename T>
79+
std::array<gsl::span<const T>, NEvTypes> getInput(framework::ProcessingContext& pc, std::string_view bind)
80+
{
81+
std::array<gsl::span<const T>, 3> data;
82+
for (auto const& inputRef : framework::InputRecordWalker(pc.inputs())) {
83+
auto const* dh = framework::DataRefUtils::getHeader<o2::header::DataHeader*>(inputRef);
84+
auto subSpecIdx = static_cast<size_t>(dh->subSpecification);
85+
if (framework::DataRefUtils::match(inputRef, bind.data())) {
86+
data[subSpecIdx] = pc.inputs().get<gsl::span<T>>(inputRef);
87+
}
88+
}
89+
return data;
90+
}
91+
92+
/// Gets the outputs
93+
/// \param outputSpecs Vector of output specs
94+
/// \return vector of outputs
95+
std::vector<framework::Output> buildOutputs(std::vector<framework::OutputSpec> outputSpecs);
96+
97+
/// Returns the array of Column Data
98+
/// \param pc Processing context
99+
/// \param dataBind Data binding name
100+
/// \return Array of Column Data spans
101+
std::array<gsl::span<const ColumnData>, NEvTypes> getData(framework::ProcessingContext& pc, std::string_view dataBind);
102+
103+
/// Returns the Column Data for the specified event type
104+
/// \param pc Processing context
105+
/// \param dataBind Data binding name
106+
/// \param eventType Event type
107+
/// \return Span of ColumnData
108+
gsl::span<const ColumnData> getData(framework::ProcessingContext& pc, std::string_view dataBind, EventType eventType);
109+
110+
/// Returns the array of ROF records
111+
/// \param pc Processing context
112+
/// \param dataBind Data binding name
113+
/// \return Array of ROF Records spans
114+
std::array<gsl::span<const ROFRecord>, NEvTypes> getRofs(framework::ProcessingContext& pc, std::string_view dataBind);
115+
116+
/// Returns the ROF records for the specified event type
117+
/// \param pc Processing context
118+
/// \param dataBind Data binding name
119+
/// \param eventType Event type
120+
/// \return Span of ROF records
121+
gsl::span<const ROFRecord> getRofs(framework::ProcessingContext& pc, std::string_view dataBind, EventType eventType);
122+
123+
/// Returns the MC labels
124+
/// \param pc Processing context
125+
/// \param dataBind Data binding name
126+
/// \return Pointer to MC labels
127+
std::unique_ptr<const o2::dataformats::MCTruthContainer<MCLabel>> getLabels(framework::ProcessingContext& pc, std::string_view dataBind);
128+
129+
} // namespace specs
130+
} // namespace mid
131+
} // namespace o2
132+
133+
#endif // O2_MID_COLUMNDATASPECSUTILS_H
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
/// \file MIDWorkflow/TimingSpec.h
13+
/// \brief Device to synchronize MID clock with collision BC
14+
/// \author Diego Stocco <Diego.Stocco at cern.ch>
15+
/// \date 04 Avril 2022
16+
17+
#ifndef O2_MID_TIMINGSPEC_H
18+
#define O2_MID_TIMINGSPEC_H
19+
20+
#include "Framework/DataProcessorSpec.h"
21+
#include <string>
22+
#include <string_view>
23+
24+
namespace o2
25+
{
26+
namespace mid
27+
{
28+
framework::DataProcessorSpec getTimingSpec(int localToBC, std::string_view inRofDesc);
29+
}
30+
} // namespace o2
31+
32+
#endif // O2_MID_TIMINGSPEC_H

Detectors/MUON/MID/Workflow/src/ClusterizerSpec.cxx

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
2020
#include <vector>
2121
#include <chrono>
2222
#include <gsl/gsl>
23+
#include "fmt/format.h"
2324
#include "Framework/ControlService.h"
2425
#include "Framework/DataRefUtils.h"
2526
#include "Framework/InputRecordWalker.h"
2627
#include "Framework/Logger.h"
2728
#include "Framework/Output.h"
2829
#include "Framework/Task.h"
30+
#include "Framework/WorkflowSpec.h"
2931
#include "DataFormatsMID/Cluster.h"
3032
#include "DataFormatsMID/ColumnData.h"
3133
#include "DataFormatsMID/ROFRecord.h"
@@ -36,6 +38,7 @@
3638
#include "MIDSimulation/ClusterLabeler.h"
3739
#include "MIDSimulation/MCLabel.h"
3840
#include "MIDSimulation/PreClusterLabeler.h"
41+
#include "MIDWorkflow/ColumnDataSpecsUtils.h"
3942

4043
namespace of = o2::framework;
4144

@@ -64,7 +67,6 @@ class ClusterizerDeviceDPL
6467
}
6568

6669
auto stop = [this]() {
67-
LOG(info) << "Capacities: ROFRecords: " << mClusterizer.getROFRecords().capacity() << " preclusters: " << mPreClusterizer.getPreClusters().capacity() << " clusters: " << mClusterizer.getClusters().capacity();
6870
double scaleFactor = 1.e6 / mNROFs;
6971
LOG(info) << "Processing time / " << mNROFs << " ROFs: full: " << mTimer.count() * scaleFactor << " us pre-clustering: " << mTimerPreCluster.count() * scaleFactor << " us clustering: " << mTimerCluster.count() * scaleFactor << " us";
7072
};
@@ -75,22 +77,8 @@ class ClusterizerDeviceDPL
7577
{
7678
auto tStart = std::chrono::high_resolution_clock::now();
7779

78-
std::vector<of::InputSpec> filter = {
79-
{"check_data", of::ConcreteDataMatcher{header::gDataOriginMID, "DATA", 0}, of::Lifetime::Timeframe},
80-
{"check_rof", of::ConcreteDataMatcher{header::gDataOriginMID, "DATAROF", 0}, of::Lifetime::Timeframe},
81-
};
82-
83-
gsl::span<const ColumnData> patterns;
84-
gsl::span<const ROFRecord> inROFRecords;
85-
86-
for (auto const& inputRef : of::InputRecordWalker(pc.inputs(), filter)) {
87-
if (of::DataRefUtils::match(inputRef, "mid_data")) {
88-
patterns = pc.inputs().get<gsl::span<o2::mid::ColumnData>>(inputRef);
89-
}
90-
if (of::DataRefUtils::match(inputRef, "mid_data_rof")) {
91-
inROFRecords = pc.inputs().get<gsl::span<o2::mid::ROFRecord>>(inputRef);
92-
}
93-
}
80+
gsl::span<const ColumnData> patterns = specs::getData(pc, "mid_cluster_in", EventType::Standard);
81+
gsl::span<const ROFRecord> inROFRecords = specs::getRofs(pc, "mid_cluster_in", EventType::Standard);
9482

9583
// Pre-clustering
9684
auto tAlgoStart = std::chrono::high_resolution_clock::now();
@@ -105,7 +93,7 @@ class ClusterizerDeviceDPL
10593

10694
if (mIsMC) {
10795
// Labelling
108-
std::unique_ptr<const o2::dataformats::MCTruthContainer<MCLabel>> labels = mIsMC ? pc.inputs().get<const o2::dataformats::MCTruthContainer<MCLabel>*>("mid_data_labels") : nullptr;
96+
auto labels = specs::getLabels(pc, "mid_cluster_in");
10997
mPreClusterLabeler.process(mPreClusterizer.getPreClusters(), *labels, mPreClusterizer.getROFRecords(), inROFRecords);
11098
mClusterLabeler.process(mPreClusterizer.getPreClusters(), mPreClusterLabeler.getContainer(), mClusterizer.getClusters(), mCorrelation);
11199
// Clear the index correlations that will be used in the next cluster processing
@@ -137,19 +125,14 @@ class ClusterizerDeviceDPL
137125
unsigned long mNROFs{0}; ///< Total number of processed ROFs
138126
};
139127

140-
framework::DataProcessorSpec getClusterizerSpec(bool isMC)
128+
framework::DataProcessorSpec getClusterizerSpec(bool isMC, std::string_view inDataDesc, std::string_view inRofDesc, std::string_view inLabelsDesc)
141129
{
142-
std::vector<of::InputSpec> inputSpecs;
143-
inputSpecs.emplace_back("mid_data", of::ConcreteDataTypeMatcher(header::gDataOriginMID, "DATA"), of::Lifetime::Timeframe);
144-
inputSpecs.emplace_back("mid_data_rof", of::ConcreteDataTypeMatcher(header::gDataOriginMID, "DATAROF"), of::Lifetime::Timeframe);
145-
146-
std::vector<of::OutputSpec> outputSpecs{of::OutputSpec{"MID", "CLUSTERS"}, of::OutputSpec{"MID", "CLUSTERSROF"}};
130+
std::vector<of::OutputSpec> outputSpecs{of::OutputSpec{header::gDataOriginMID, "CLUSTERS"}, of::OutputSpec{header::gDataOriginMID, "CLUSTERSROF"}};
147131

148132
if (isMC) {
149-
inputSpecs.emplace_back(of::InputSpec{"mid_data_labels", "MID", "DATALABELS"});
150-
151-
outputSpecs.emplace_back(of::OutputSpec{"MID", "CLUSTERSLABELS"});
133+
outputSpecs.emplace_back(of::OutputSpec{header::gDataOriginMID, "CLUSTERSLABELS"});
152134
}
135+
auto inputSpecs = specs::buildInputSpecs("mid_cluster_in", inDataDesc, inRofDesc, inLabelsDesc, isMC);
153136

154137
return of::DataProcessorSpec{
155138
"MIDClusterizer",

0 commit comments

Comments
 (0)