Project
Loading...
Searching...
No Matches
clusters-sink-workflow.cxx
Go to the documentation of this file.
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
16
17#include <iostream>
18#include <fstream>
19#include <array>
20#include <stdexcept>
21#include <vector>
22
23#include <fmt/format.h>
24
25#include <gsl/span>
26
31#include "Framework/Lifetime.h"
32#include "Framework/Task.h"
33#include "Framework/Logger.h"
36
41
42using namespace std;
43using namespace o2::framework;
44using namespace o2::mch;
45
47{
48 public:
49 ClusterSinkTask(bool doDigits = true) : mDoDigits{doDigits} {}
50
51 //_________________________________________________________________________________________________
52 void init(InitContext& ic)
53 {
55 LOG(info) << "initializing cluster sink";
56
57 mText = ic.options().get<bool>("txt");
58
59 auto outputFileName = ic.options().get<std::string>("outfile");
60 mOutputFile.open(outputFileName, (mText ? ios::out : (ios::out | ios::binary)));
61 if (!mOutputFile.is_open()) {
62 throw invalid_argument("Cannot open output file" + outputFileName);
63 }
64
65 mUseRun2DigitUID = ic.options().get<bool>("useRun2DigitUID");
66
67 auto stop = [this]() {
69 LOG(info) << "stop cluster sink";
70 this->mOutputFile.close();
71 };
72 ic.services().get<CallbackService>().set<CallbackService::Id::Stop>(stop);
73 }
74
75 //_________________________________________________________________________________________________
77 {
79
80 // get the input clusters and associated digits
81 auto rofs = pc.inputs().get<gsl::span<ROFRecord>>("rofs");
82 auto clusters = pc.inputs().get<gsl::span<Cluster>>("clusters");
83 gsl::span<const Digit> digits;
84 if (mDoDigits) {
85 digits = pc.inputs().get<gsl::span<Digit>>("digits");
86 }
87
88 std::vector<Cluster> eventClusters{};
89 for (const auto& rof : rofs) {
90
91 if (mText) {
92
93 // write the clusters in ascii format
94 mOutputFile << rof.getNEntries() << " clusters:" << endl;
95 for (const auto& cluster : clusters.subspan(rof.getFirstIdx(), rof.getNEntries())) {
96 mOutputFile << cluster << endl;
97 }
98
99 } else {
100
101 // get the clusters and associated digits of the current event
102 auto eventDigits = getEventClustersAndDigits(rof, clusters, digits, eventClusters);
103
104 // write the number of clusters
105 int nClusters = eventClusters.size();
106 mOutputFile.write(reinterpret_cast<char*>(&nClusters), sizeof(int));
107
108 // write the total number of digits in these clusters
109 int nDigits = eventDigits.size();
110 mOutputFile.write(reinterpret_cast<char*>(&nDigits), sizeof(int));
111
112 // write the clusters
113 mOutputFile.write(reinterpret_cast<const char*>(eventClusters.data()), eventClusters.size() * sizeof(Cluster));
114
115 // write the digits (after converting the pad ID into a digit UID if requested)
116 if (nDigits > 0) {
117 if (mUseRun2DigitUID) {
118 std::vector<Digit> digitsCopy(eventDigits.begin(), eventDigits.end());
119 convertPadID2DigitUID(digitsCopy);
120 mOutputFile.write(reinterpret_cast<char*>(digitsCopy.data()), digitsCopy.size() * sizeof(Digit));
121 } else {
122 mOutputFile.write(reinterpret_cast<const char*>(eventDigits.data()), eventDigits.size_bytes());
123 }
124 }
125 }
126 }
127 }
128
129 private:
130 //_________________________________________________________________________________________________
131 gsl::span<const Digit> getEventClustersAndDigits(const ROFRecord& rof, gsl::span<const Cluster> clusters,
132 gsl::span<const Digit> digits,
133 std::vector<Cluster>& eventClusters) const
134 {
138
139 eventClusters.clear();
140
141 if (rof.getNEntries() < 1) {
142 return {};
143 }
144
145 if (rof.getLastIdx() >= clusters.size()) {
146 throw length_error("missing clusters");
147 }
148
149 eventClusters.insert(eventClusters.end(), clusters.begin() + rof.getFirstIdx(),
150 clusters.begin() + rof.getLastIdx() + 1);
151
152 if (mDoDigits) {
153
154 auto digitOffset = eventClusters.front().firstDigit;
155 for (auto& cluster : eventClusters) {
156 cluster.firstDigit -= digitOffset;
157 }
158
159 auto nDigits = eventClusters.back().firstDigit + eventClusters.back().nDigits;
160 if (digitOffset + nDigits > digits.size()) {
161 throw length_error("missing digits");
162 }
163
164 return digits.subspan(digitOffset, nDigits);
165 }
166
167 return {};
168 }
169
170 //_________________________________________________________________________________________________
171 void convertPadID2DigitUID(std::vector<Digit>& digits)
172 {
174
175 // cathode number of the bending plane for each DE
176 static const std::array<std::vector<int>, 10> bendingCathodes{
177 {{0, 1, 0, 1},
178 {0, 1, 0, 1},
179 {0, 1, 0, 1},
180 {0, 1, 0, 1},
181 {0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1},
182 {0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1},
183 {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1},
184 {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1},
185 {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1},
186 {0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}}};
187
188 for (auto& digit : digits) {
189
190 int deID = digit.getDetID();
192 int padID = digit.getPadID();
193 int cathode = bendingCathodes[deID / 100 - 1][deID % 100];
194 if (!segmentation.isBendingPad(padID)) {
195 cathode = 1 - cathode;
196 }
197 int manuID = segmentation.padDualSampaId(padID);
198 int manuCh = segmentation.padDualSampaChannel(padID);
199
200 int digitID = (deID) | (manuID << 12) | (manuCh << 24) | (cathode << 30);
201 digit.setPadID(digitID);
202 }
203 }
204
205 std::ofstream mOutputFile{};
206 bool mText = false;
207 bool mUseRun2DigitUID = false;
208 bool mDoDigits = true;
209};
210
211//_________________________________________________________________________________________________
212void customize(std::vector<ConfigParamSpec>& workflowOptions)
213{
215 workflowOptions.emplace_back("global", VariantType::Bool, false,
216 ConfigParamSpec::HelpString{"read clusters with positions expressed in global reference frame"});
217 workflowOptions.emplace_back("no-digits", VariantType::Bool, false,
218 ConfigParamSpec::HelpString{"do not look for digits"});
219}
220
221//_________________________________________________________________________________________________
223
225{
226 std::string inputConfig = fmt::format("rofs:MCH/CLUSTERROFS/0;clusters:MCH/{}CLUSTERS/0",
227 cc.options().get<bool>("global") ? "GLOBAL" : "");
228
229 bool doDigits = not cc.options().get<bool>("no-digits");
230
231 if (doDigits) {
232 inputConfig += ";digits:MCH/CLUSTERDIGITS/0";
233 }
234 std::cout << "inputConfig=" << inputConfig << "\n";
235
236 return WorkflowSpec{
238 "ClusterSink",
239 Inputs{o2::framework::select(inputConfig.c_str())},
240 Outputs{},
241 AlgorithmSpec{adaptFromTask<ClusterSinkTask>(doDigits)},
242 Options{
243 {"outfile", VariantType::String, "clusters.out", {"output filename"}},
244 {"txt", VariantType::Bool, false, {"output clusters in text format"}},
245 {"useRun2DigitUID", VariantType::Bool, false, {"mPadID = digit UID in run2 format"}}}}};
246}
Definition of the MCH cluster minimal structure.
Definition of the MCH ROFrame record.
int nClusters
void init(InitContext &ic)
ClusterSinkTask(bool doDigits=true)
void run(ProcessingContext &pc)
ServiceRegistryRef services()
Definition InitContext.h:34
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
InputRecord & inputs()
The inputs associated with this processing context.
MCH digit implementation.
Definition Digit.h:31
int getLastIdx() const
get the index of the last associated object
Definition ROFRecord.h:59
int getNEntries() const
get the number of associated objects
Definition ROFRecord.h:55
int getFirstIdx() const
get the index of the first associated object
Definition ROFRecord.h:57
int padDualSampaId(int dePadIndex) const
bool isBendingPad(int dePadIndex) const
int padDualSampaChannel(int dePadIndex) const
WorkflowSpec defineDataProcessing(const ConfigContext &cc)
void customize(std::vector< ConfigParamSpec > &workflowOptions)
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< DataProcessorSpec > WorkflowSpec
std::vector< InputSpec > select(char const *matcher="")
std::vector< InputSpec > Inputs
std::vector< OutputSpec > Outputs
O2MCHMAPPINGIMPL3_EXPORT const Segmentation & segmentation(int detElemId)
Defining DataPointCompositeObject explicitly as copiable.
cluster minimal structure
Definition Cluster.h:31
std::vector< o2::mch::ChannelCode > cc
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Cluster > clusters
std::vector< Digit > digits