forked from AliceO2Group/AliceO2
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCalibDataProcessorSpec.cxx
More file actions
165 lines (145 loc) · 7 KB
/
CalibDataProcessorSpec.cxx
File metadata and controls
165 lines (145 loc) · 7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
/// \file MID/Workflow/src/CalibDataProcessorSpec.cxx
/// \brief Device to convert the calibration data into a list of bad channel candidates
/// \author Diego Stocco <Diego.Stocco at cern.ch>
/// \date 25 October 2022
#include "MIDWorkflow/CalibDataProcessorSpec.h"
#include <array>
#include <vector>
#include <gsl/gsl>
#include "Framework/ConfigParamRegistry.h"
#include "Framework/ControlService.h"
#include "Framework/DataRefUtils.h"
#include "Framework/InputRecordWalker.h"
#include "Framework/InputSpec.h"
#include "Framework/Logger.h"
#include "Framework/Task.h"
#include "DetectorsCalibration/Utils.h"
#include "CCDB/CcdbObjectInfo.h"
#include "DataFormatsMID/ColumnData.h"
#include "DataFormatsMID/ROFRecord.h"
#include "MIDBase/ColumnDataHandler.h"
#include "MIDFiltering/FetToDead.h"
#include "MIDFiltering/MaskMaker.h"
namespace of = o2::framework;
namespace o2
{
namespace mid
{
class CalibDataProcessorDPL
{
public:
CalibDataProcessorDPL(const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks)
{
auto refMasks = makeDefaultMasksFromCrateConfig(feeIdConfig, crateMasks);
mFetToDead.setMasks(refMasks);
}
void init(of::InitContext& ic)
{
mMinDiff = ic.options().get<int64_t>("mid-merge-fet-bc-diff-min");
mMaxDiff = ic.options().get<int64_t>("mid-merge-fet-bc-diff-max");
}
void run(of::ProcessingContext& pc)
{
std::array<gsl::span<const ColumnData>, 3> data;
std::array<gsl::span<const ROFRecord>, 3> dataRof;
for (o2::header::DataHeader::SubSpecificationType subSpec = 0; subSpec < NEvTypes; ++subSpec) {
data[subSpec] = pc.inputs().get<gsl::span<o2::mid::ColumnData>>(fmt::format("mid_data_{}", subSpec));
dataRof[subSpec] = pc.inputs().get<gsl::span<o2::mid::ROFRecord>>(fmt::format("mid_data_rof_{}", subSpec));
}
mNoise.clear();
mNoiseROF.clear();
mDead.clear();
mDeadROF.clear();
if (data[1].empty()) {
mNoise.insert(mNoise.end(), data[0].begin(), data[0].end());
mNoiseROF.insert(mNoiseROF.end(), dataRof[0].begin(), dataRof[0].end());
} else {
mNoise.insert(mNoise.end(), data[1].begin(), data[1].end());
mNoiseROF.insert(mNoiseROF.end(), dataRof[1].begin(), dataRof[1].end());
mergeChannels(data[2], dataRof[2], data[0], dataRof[0]);
}
pc.outputs().snapshot(of::Output{header::gDataOriginMID, "NOISE", 0}, mNoise);
pc.outputs().snapshot(of::Output{header::gDataOriginMID, "NOISEROF", 0}, mNoiseROF);
pc.outputs().snapshot(of::Output{header::gDataOriginMID, "DEAD", 0}, mDead);
pc.outputs().snapshot(of::Output{header::gDataOriginMID, "DEADROF", 0}, mDeadROF);
}
private:
FetToDead mFetToDead{}; ///< FET to dead channels converter
std::vector<ColumnData> mNoise; ///< Merged noise
std::vector<ROFRecord> mNoiseROF; ///< Merged noise ROFs
std::vector<ColumnData> mDead; ///< Merged dead
std::vector<ROFRecord> mDeadROF; ///< Merged dead ROFs
int64_t mMinDiff = -1; /// Maximum BC difference for FET merging
int64_t mMaxDiff = 1; /// Minimum BC difference for FET merging
void mergeChannels(gsl::span<const ColumnData> fetData, gsl::span<const ROFRecord> fetDataRof, gsl::span<const ColumnData> selfTrigData, gsl::span<const ROFRecord> selfTrigDataRof)
{
// This method selects the self-triggered events that are close in time with a FET event and merges them with the fet event.
// This is needed since the detector answer is not perfectly aligned in time.
// Since calibration runs occur with no beam, all other self-triggers are actually noise.
ColumnDataHandler handler;
// The FET data can be split into different BCs.
// Try to merge the expected FET data with the data in the close BCs
// which are probably badly tagged FET data
auto auxRofIt = selfTrigDataRof.begin();
// Loop on FET ROF
for (auto& rof : fetDataRof) {
handler.clear();
auto eventFetData = fetData.subspan(rof.firstEntry, rof.nEntries);
handler.merge(eventFetData);
for (; auxRofIt != selfTrigDataRof.end(); ++auxRofIt) {
auto bcDiff = auxRofIt->interactionRecord.differenceInBC(rof.interactionRecord);
if (bcDiff > mMaxDiff) {
// ROFs are time ordered. If the difference is larger than the maximum difference for merging,
// it means that the auxRofIt is in the future.
// We break and compare it to the next rof.
break;
} else if (bcDiff >= mMinDiff) {
// With the previous condition, this implies mMinDiff <= bcDiff <= mMaxDiff
auto auxFet = selfTrigData.subspan(auxRofIt->firstEntry, auxRofIt->nEntries);
handler.merge(auxFet);
} else {
// If bcDiff is < mMinDiff, it means that the auxRofIt is too much in the past
// So this was actually noise
mNoise.insert(mNoise.end(), selfTrigData.begin() + auxRofIt->firstEntry, selfTrigData.begin() + auxRofIt->getEndIndex());
mNoiseROF.emplace_back(*auxRofIt);
}
}
auto eventDeadChannels = mFetToDead.process(handler.getMerged());
mDeadROF.emplace_back(rof.interactionRecord, rof.eventType, mDead.size(), eventDeadChannels.size());
mDead.insert(mDead.end(), eventDeadChannels.begin(), eventDeadChannels.end());
}
}
};
of::DataProcessorSpec getCalibDataProcessorSpec(const FEEIdConfig& feeIdConfig, const CrateMasks& crateMasks)
{
std::vector<of::InputSpec> inputSpecs;
for (o2::header::DataHeader::SubSpecificationType subSpec = 0; subSpec < NEvTypes; ++subSpec) {
inputSpecs.emplace_back(fmt::format("mid_data_{}", subSpec), header::gDataOriginMID, "DATA", subSpec, of::Lifetime::Timeframe);
inputSpecs.emplace_back(fmt::format("mid_data_rof_{}", subSpec), header::gDataOriginMID, "DATAROF", subSpec, of::Lifetime::Timeframe);
}
std::vector<of::OutputSpec> outputSpecs;
outputSpecs.emplace_back(header::gDataOriginMID, "NOISE", 0);
outputSpecs.emplace_back(header::gDataOriginMID, "NOISEROF", 0);
outputSpecs.emplace_back(header::gDataOriginMID, "DEAD", 0);
outputSpecs.emplace_back(header::gDataOriginMID, "DEADROF", 0);
return of::DataProcessorSpec{
"MIDFetToDead",
{inputSpecs},
{outputSpecs},
of::AlgorithmSpec{of::adaptFromTask<o2::mid::CalibDataProcessorDPL>(feeIdConfig, crateMasks)},
of::Options{
{"mid-merge-fet-bc-diff-min", of::VariantType::Int, -1, {"Merge to FET if BC-BC_FET >= this value"}},
{"mid-merge-fet-bc-diff-max", of::VariantType::Int, 1, {"Merge to FET if BC-BC_FET <= this value"}}}};
}
} // namespace mid
} // namespace o2