Project
Loading...
Searching...
No Matches
EventBuilderSpec.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#include <fairlogger/Logger.h>
12
18#include <vector>
19
20using namespace o2::phos;
21
25
27{
28 // Merge subevents from two FLPs. FLPs send messages with non-zero subspecifications
29 // take TrigRecs with same BC stamps and copy corresponding cells
30 // sells are sorted, so find subspec with smaller absId and copy it first (exclude/handle trigger cells!)
31 // check if all halves of events were found, otherwise send warning
32
33 std::vector<o2::phos::Cell> outputCells;
34 std::vector<o2::phos::TriggerRecord> outputTriggers;
35 int nOutCells = 0;
36
37 int posCells = ctx.inputs().getPos("inputcells");
38 int posTriggerRecords = ctx.inputs().getPos("inputtriggers");
39 int numSlotsCells = ctx.inputs().getNofParts(posCells);
40 int numSlotsTriggerRecords = ctx.inputs().getNofParts(posTriggerRecords);
41
42 std::vector<SubspecSet> subspecs;
43
44 // Combine pairs (trigRec,cells) from different subspecs
45 for (int islot = 0; islot < numSlotsTriggerRecords; islot++) {
46 auto trgrecorddata = ctx.inputs().getByPos(posTriggerRecords, islot);
47 auto subspecification = framework::DataRefUtils::getHeader<header::DataHeader*>(trgrecorddata)->subSpecification;
48 // Discard message if it is a deadbeaf message (empty timeframe)
49 if (subspecification == 0xDEADBEEF) {
50 continue;
51 }
52 auto celldata = ctx.inputs().getByPos(posCells, islot);
53 // check if cells from the same source?
54 // if not try to find proper slot
55 if (framework::DataRefUtils::getHeader<header::DataHeader*>(celldata)->subSpecification != subspecification) {
56 for (int islotCell = 0; islotCell < numSlotsCells; islotCell++) {
57 celldata = ctx.inputs().getByPos(posCells, islotCell);
58 if (framework::DataRefUtils::getHeader<header::DataHeader*>(celldata)->subSpecification == subspecification) {
59 break;
60 }
61 }
62 // if still not found pair
63 if (framework::DataRefUtils::getHeader<header::DataHeader*>(celldata)->subSpecification != subspecification) {
64 LOG(error) << "Can not find cells for TrigRecords with subspecification " << subspecification;
65 continue;
66 }
67 }
68 subspecs.emplace_back(ctx.inputs().get<gsl::span<o2::phos::TriggerRecord>>(trgrecorddata),
69 ctx.inputs().get<gsl::span<o2::phos::Cell>>(celldata));
70 }
71
72 // Cells in vectors are sorted. Copy in correct order to preserve sorting
73 int first1 = 0; // which subspec should go first: 0: undefined yet, 1:[0],2:[1],
74 if (subspecs.size() == 1) { // one input, just copy to output
75 for (const Cell& c : subspecs[0].cellSpan) {
76 outputCells.emplace_back(c);
77 }
78 for (const TriggerRecord& r : subspecs[0].trSpan) {
79 outputTriggers.emplace_back(r);
80 }
81
82 } else {
83 if (subspecs.size() > 2) { // error
84 LOG(error) << " Too many subspecs for event building:" << subspecs.size();
85 } else { // combine two subspecs
86 auto tr1 = subspecs[0].trSpan.begin();
87 auto tr2 = subspecs[1].trSpan.begin();
88 while (tr1 != subspecs[0].trSpan.end() && tr2 != subspecs[1].trSpan.end()) {
89 if (tr1->getBCData() == tr2->getBCData()) { // OK, copy
90 if (first1 == 0) { // order of subspecs not yet defined
91 if (subspecs[0].cellSpan.size() > 0) {
92 short absId = subspecs[0].cellSpan[0].getAbsId();
93 if (absId > 0) { // this is readout cell
94 first1 = 1 + (absId - 1) / (2 * 64 * 56);
95 } else { // TRU cell
96 first1 = 1 + (subspecs[0].cellSpan[0].getTRUId() - 1) / (8 * 28 * 7);
97 }
98 } else {
99 if (subspecs[1].cellSpan.size() > 0) {
100 short absId = subspecs[1].cellSpan[0].getAbsId();
101 if (absId > 0) { // this is readout cell
102 first1 = 2 - (absId - 1) / (2 * 64 * 56);
103 } else { // TRU cell
104 first1 = 2 - (subspecs[1].cellSpan[0].getTRUId() - 1) / (8 * 28 * 7);
105 }
106 }
107 // if both lists are empty, keep first1 zero and try next time
108 }
109 }
110
111 gsl::details::span_iterator<const o2::phos::Cell> itC1, end1, itC2, end2;
112 if (first1 > 1) { // copy first set1 then set2
113 itC1 = subspecs[0].cellSpan.begin() + tr1->getFirstEntry();
114 end1 = subspecs[0].cellSpan.begin() + tr1->getFirstEntry() + tr1->getNumberOfObjects();
115 itC2 = subspecs[1].cellSpan.begin() + tr2->getFirstEntry();
116 end2 = subspecs[1].cellSpan.begin() + tr2->getFirstEntry() + tr2->getNumberOfObjects();
117 } else {
118 itC1 = subspecs[1].cellSpan.begin() + tr2->getFirstEntry();
119 end1 = subspecs[1].cellSpan.begin() + tr2->getFirstEntry() + tr2->getNumberOfObjects();
120 itC2 = subspecs[0].cellSpan.begin() + tr1->getFirstEntry();
121 end2 = subspecs[0].cellSpan.begin() + tr1->getFirstEntry() + tr1->getNumberOfObjects();
122 }
123 // first copy readout Cells from both events, then trigger
124 while (itC1 != end1) {
125 if (itC1->getAbsId() == 0) { // TRU cells further
126 break;
127 }
128 outputCells.emplace_back(*itC1);
129 ++itC1;
130 }
131 while (itC2 != end2) {
132 if (itC2->getAbsId() == 0) {
133 break;
134 }
135 outputCells.emplace_back(*itC2);
136 ++itC2;
137 }
138 // Copy trigger
139 while (itC1 != end1) {
140 outputCells.emplace_back(*itC1);
141 ++itC1;
142 }
143 while (itC2 != end2) {
144 outputCells.emplace_back(*itC2);
145 ++itC2;
146 }
147
148 outputTriggers.emplace_back(tr1->getBCData(), nOutCells, outputCells.size() - nOutCells);
149 nOutCells = outputCells.size();
150 ++tr1;
151 ++tr2;
152 } else { // inconsistent BCs
153 // find smaller BC and copy one part and mark as missing second part
154 if (tr1->getBCData() < tr2->getBCData()) {
155 auto itC1 = subspecs[0].cellSpan.begin() + tr1->getFirstEntry();
156 auto end1 = subspecs[0].cellSpan.begin() + tr1->getFirstEntry() + tr1->getNumberOfObjects();
157 while (itC1 != end1) {
158 outputCells.emplace_back(*itC1);
159 }
160 outputTriggers.emplace_back(tr1->getBCData(), nOutCells, outputCells.size() - nOutCells);
161 nOutCells = outputCells.size();
162 ++tr1;
163 } else {
164 auto itC1 = subspecs[1].cellSpan.begin() + tr2->getFirstEntry();
165 auto end1 = subspecs[1].cellSpan.begin() + tr2->getFirstEntry() + tr2->getNumberOfObjects();
166 while (itC1 != end1) {
167 outputCells.emplace_back(*itC1);
168 }
169 outputTriggers.emplace_back(tr2->getBCData(), nOutCells, outputCells.size() - nOutCells);
170 nOutCells = outputCells.size();
171 ++tr2;
172 }
173 }
174 }
175 if (tr1 != subspecs[0].trSpan.end() || tr2 != subspecs[1].trSpan.end()) {
176 LOG(error) << "Inconsistent number of TriggerRecords in subsec 1 and 2: " << subspecs[0].trSpan.size() << " and " << subspecs[1].trSpan.size();
177 }
178 }
179 }
180
181 ctx.outputs().snapshot(framework::Output{o2::header::gDataOriginPHS, "CELLS", 0}, outputCells);
182 ctx.outputs().snapshot(framework::Output{o2::header::gDataOriginPHS, "CELLTRIGREC", 0}, outputTriggers);
183}
184
186{
187 std::vector<o2::framework::InputSpec> inputs;
188 inputs.emplace_back("inputcells", "PHS", "CELLS", 1, o2::framework::Lifetime::Timeframe); // Input subspec 1, output subspec 0
189 inputs.emplace_back("inputtriggers", "PHS", "CELLTRIGREC", 1, o2::framework::Lifetime::Timeframe); // Input subspec 1, output subspec 0
190 // output should be anyway generated by raw converter. Or not?
191 // inputs.emplace_back("STFDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe);
192
194 {o2::header::gDataOriginPHS, "CELLS", 0, o2::framework::Lifetime::Timeframe}, // output is zero subspec
195 {o2::header::gDataOriginPHS, "CELLTRIGREC", 0, o2::framework::Lifetime::Timeframe}};
196
197 return o2::framework::DataProcessorSpec{"PHOSEventBuilder",
198 inputs,
199 outputs,
200 o2::framework::adaptFromTask<o2::phos::EventBuilderSpec>(),
202}
uint32_t c
Definition RawData.h:2
void snapshot(const Output &spec, T const &object)
int getPos(const char *name) const
decltype(auto) get(R binding, int part=0) const
static DataRef getByPos(std::vector< InputRoute > const &routes, InputSpan const &span, int pos, int part=0)
size_t getNofParts(int pos) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
void init(framework::InitContext &ctx) final
void run(framework::ProcessingContext &ctx) final
Header for data corresponding to the same hardware trigger adapted from DataFormatsEMCAL/TriggerRecor...
GLboolean r
Definition glcorearb.h:1233
constexpr o2::header::DataOrigin gDataOriginPHS
Definition DataHeader.h:574
std::vector< ConfigParamSpec > Options
std::vector< OutputSpec > Outputs
o2::framework::DataProcessorSpec getEventBuilderSpec()
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"