Project
Loading...
Searching...
No Matches
EntropyEncoderSpec.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
22#include "Headers/DataHeader.h"
25#include "GPUO2InterfaceUtils.h"
26#include "GPUParam.h"
28#include "TPCClusterDecompressionCore.inc"
29#include "GPUTPCCompressionKernels.inc"
32
33using namespace o2::framework;
34using namespace o2::header;
35using namespace o2::base;
36
37namespace o2
38{
39namespace tpc
40{
41
43
44EntropyEncoderSpec::EntropyEncoderSpec(bool fromFile, bool selIR, std::shared_ptr<o2::base::GRPGeomRequest> pgg) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mFromFile(fromFile), mSelIR(selIR)
45{
46 if (mSelIR) {
47 mGRPRequest = pgg;
49 }
50 mTimer.Stop();
51 mTimer.Reset();
52}
53
55{
56 if (mCTFCoder.finaliseCCDB<CTF>(matcher, obj)) {
57 return;
58 }
59 if (mSelIR && mTPCVDriftHelper->accountCCDBInputs(matcher, obj)) {
60 return;
61 }
62 if (mSelIR && GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
63 return;
64 }
65}
66
68{
69 mCTFCoder.init<CTF>(ic);
70 mCTFCoder.setCombineColumns(!ic.options().get<bool>("no-ctf-columns-combining"));
71
72 mFastTransform = std::move(TPCFastTransformHelperO2::instance()->create(0));
73
74 mParam = GPUO2InterfaceUtils::getFullParam(0.f, 0, &mConfig, &mConfParam, &mAutoContinuousMaxTimeBin);
75
76 if (mSelIR) {
77 mTPCVDriftHelper.reset(new VDriftHelper);
78 }
79
80 mNThreads = ic.options().get<unsigned int>("nThreads-tpc-encoder");
81 mMaxZ = ic.options().get<float>("irframe-clusters-maxz");
82 mMaxEta = ic.options().get<float>("irframe-clusters-maxeta");
83
84 mEtaFactor = 1.f / (tanf(2 * atanf(expf(-mMaxEta))));
85}
86
88{
89 if (mSelIR) {
91 if (GRPGeomHelper::instance().getGRPECS()->isDetReadOut(o2::detectors::DetID::TPC) && mConfParam->tpcTriggeredMode ^ !GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::TPC)) {
92 LOG(fatal) << "configKeyValue tpcTriggeredMode does not match GRP isDetContinuousReadOut(TPC) setting";
93 }
94
95 mConfig->configGRP.grpContinuousMaxTimeBin = GPUO2InterfaceUtils::getTpcMaxTimeBinFromNHbf(GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF());
96 mConfig->configGRP.solenoidBzNominalGPU = GPUO2InterfaceUtils::getNominalGPUBz(*GRPGeomHelper::instance().getGRPMagField());
97 mParam->UpdateSettings(&mConfig->configGRP);
98
99 mTPCVDriftHelper->extractCCDBInputs(pc);
100 if (mTPCVDriftHelper->isUpdated()) {
101 TPCFastTransformHelperO2::instance()->updateCalibration(*mFastTransform, 0, mTPCVDriftHelper->getVDriftObject().corrFact, mTPCVDriftHelper->getVDriftObject().refVDrift, mTPCVDriftHelper->getVDriftObject().getTimeOffset());
102 }
103 }
104
105 mCTFCoder.updateTimeDependentParams(pc, true);
106
108 static o2::tpc::detail::TriggerInfo trigComp;
109
110 if (mFromFile) {
111 auto tmp = pc.inputs().get<CompressedClustersROOT*>("input");
112 if (tmp == nullptr) {
113 LOG(error) << "invalid input";
114 return;
115 }
116 clusters = *tmp;
117 } else {
118 auto tmp = pc.inputs().get<CompressedClustersFlat*>("input");
119 if (tmp == nullptr) {
120 LOG(error) << "invalid input";
121 return;
122 }
123 clusters = *tmp;
124 }
125 auto triggers = pc.inputs().get<gsl::span<o2::tpc::TriggerInfoDLBZS>>("trigger");
126 auto cput = mTimer.CpuTime();
127 mTimer.Start(false);
128 auto& buffer = pc.outputs().make<std::vector<o2::ctf::BufferType>>(Output{"TPC", "CTFDATA", 0});
129 std::vector<bool> rejectHits, rejectTracks, rejectTrackHits, rejectTrackHitsReduced;
130 CompressedClusters clustersFiltered = clusters;
131 std::vector<std::pair<std::vector<unsigned int>, std::vector<unsigned short>>> tmpBuffer(std::max<int>(mNThreads, 1));
132
133 // prepare trigger info
134 trigComp.clear();
135 for (const auto& trig : triggers) {
136 for (int it = 0; it < o2::tpc::TriggerWordDLBZS::MaxTriggerEntries; it++) {
137 if (trig.triggerWord.isValid(it)) {
138 trigComp.deltaOrbit.push_back(trig.orbit);
139 trigComp.deltaBC.push_back(trig.triggerWord.getTriggerBC(it));
140 trigComp.triggerType.push_back(trig.triggerWord.getTriggerType(it));
141 } else {
142 break;
143 }
144 }
145 }
146
147 if (mSelIR) {
148 if (clusters.nTracks && clusters.solenoidBz != -1e6f && clusters.solenoidBz != mParam->bzkG) {
149 throw std::runtime_error("Configured solenoid Bz does not match value used for track model encoding");
150 }
151 if (clusters.nTracks && clusters.maxTimeBin != -1e6 && clusters.maxTimeBin != mParam->continuousMaxTimeBin) {
152 throw std::runtime_error("Configured max time bin does not match value used for track model encoding");
153 }
154 mCTFCoder.setSelectedIRFrames(pc.inputs().get<gsl::span<o2::dataformats::IRFrame>>("selIRFrames"));
155 rejectHits.resize(clusters.nUnattachedClusters);
156 rejectTracks.resize(clusters.nTracks);
157 rejectTrackHits.resize(clusters.nAttachedClusters);
158 rejectTrackHitsReduced.resize(clusters.nAttachedClustersReduced);
159
160 const auto& tinfo = pc.services().get<o2::framework::TimingInfo>();
161 const auto firstIR = o2::InteractionRecord(0, tinfo.firstTForbit);
162 const float totalT = std::max(mFastTransform->getMaxDriftTime(0), mFastTransform->getMaxDriftTime(GPUCA_NSECTORS / 2));
163
164 unsigned int offset = 0, lasti = 0;
165 const unsigned int maxTime = (mParam->continuousMaxTimeBin + 1) * o2::tpc::ClusterNative::scaleTimePacked - 1;
166#ifdef WITH_OPENMP
167#pragma omp parallel for firstprivate(offset, lasti) num_threads(mNThreads)
168#endif
169 for (unsigned int i = 0; i < clusters.nTracks; i++) {
170 unsigned int tMinP = maxTime, tMaxP = 0;
171 auto checker = [&tMinP, &tMaxP](const o2::tpc::ClusterNative& cl, unsigned int offset) {
172 if (cl.getTimePacked() > tMaxP) {
173 tMaxP = cl.getTimePacked();
174 }
175 if (cl.getTimePacked() < tMinP) {
176 tMinP = cl.getTimePacked();
177 }
178 };
179 if (i < lasti) {
180 offset = lasti = 0; // dynamic OMP scheduling, need to reinitialize offset
181 }
182 while (lasti < i) {
183 offset += clusters.nTrackClusters[lasti++];
184 }
185 lasti++;
186 o2::gpu::TPCClusterDecompressionCore::decompressTrack(clusters, *mParam, maxTime, i, offset, checker);
187 const float tMin = o2::tpc::ClusterNative::unpackTime(tMinP), tMax = o2::tpc::ClusterNative::unpackTime(tMaxP);
188 const auto chkVal = firstIR + (tMin * constants::LHCBCPERTIMEBIN);
189 const auto chkExt = totalT > tMax - tMin ? ((totalT - (tMax - tMin)) * constants::LHCBCPERTIMEBIN + 1) : 0;
190 const bool reject = mCTFCoder.getIRFramesSelector().check(o2::dataformats::IRFrame(chkVal, chkVal + 1), chkExt, 0) < 0;
191 if (reject) {
192 for (unsigned int k = offset - clusters.nTrackClusters[i]; k < offset; k++) {
193 rejectTrackHits[k] = true;
194 }
195 for (unsigned int k = offset - clusters.nTrackClusters[i] - i; k < offset - i - 1; k++) {
196 rejectTrackHitsReduced[k] = true;
197 }
198 rejectTracks[i] = true;
199 static std::atomic_flag lock = ATOMIC_FLAG_INIT;
200 while (lock.test_and_set(std::memory_order_acquire)) {
201 }
202 clustersFiltered.nTracks--;
203 clustersFiltered.nAttachedClusters -= clusters.nTrackClusters[i];
204 clustersFiltered.nAttachedClustersReduced -= clusters.nTrackClusters[i] - 1;
205 lock.clear(std::memory_order_release);
206 }
207 }
208 offset = 0;
210 for (unsigned int i = 0; i < GPUCA_NSECTORS; i++) {
211 for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) {
212 if (i * GPUCA_ROW_COUNT + j >= clusters.nSliceRows) {
213 break;
214 }
215 offsets[i][j] = offset;
216 offset += (i * GPUCA_ROW_COUNT + j >= clusters.nSliceRows) ? 0 : clusters.nSliceRowClusters[i * GPUCA_ROW_COUNT + j];
217 }
218 }
219
220#ifdef WITH_OPENMP
221#pragma omp parallel for num_threads(mNThreads) schedule(static, (GPUCA_NSECTORS + mNThreads - 1) / mNThreads) // Static round-robin scheduling with one chunk per thread to ensure correct order of the final vector
222#endif
223 for (unsigned int ii = 0; ii < clusters.nSliceRows; ii++) {
224 unsigned int i = ii / GPUCA_ROW_COUNT;
225 unsigned int j = ii % GPUCA_ROW_COUNT;
227#ifdef WITH_OPENMP
228 int myThread = omp_get_thread_num();
229#else
230 int myThread = 0;
231#endif
232 unsigned int count = 0;
233 const float x = mParam->tpcGeometry.Row2X(j);
234 auto checker = [i, j, firstIR, totalT, x, this, &preCl, &count, &outBuffer = tmpBuffer[myThread], &rejectHits, &clustersFiltered](const o2::tpc::ClusterNative& cl, unsigned int k) {
235 const float y = mParam->tpcGeometry.LinearPad2Y(i, j, cl.getPad());
236 const float r = sqrtf(x * x + y * y);
237 const float maxz = r * mEtaFactor + mMaxZ;
238 const unsigned int deltaBC = std::max<float>(0.f, totalT - mFastTransform->convDeltaZtoDeltaTimeInTimeFrameAbs(maxz)) * constants::LHCBCPERTIMEBIN;
239 const auto chkVal = firstIR + (cl.getTime() * constants::LHCBCPERTIMEBIN) - deltaBC;
240 const auto chkExt = totalT * constants::LHCBCPERTIMEBIN - deltaBC;
241 const bool reject = mCTFCoder.getIRFramesSelector().check(o2::dataformats::IRFrame(chkVal, chkVal + 1), chkExt, 0) < 0;
242 if (reject) {
243 rejectHits[k] = true;
244 clustersFiltered.nSliceRowClusters[i * GPUCA_ROW_COUNT + j]--;
245 static std::atomic_flag lock = ATOMIC_FLAG_INIT;
246 while (lock.test_and_set(std::memory_order_acquire)) {
247 }
248 clustersFiltered.nUnattachedClusters--;
249 lock.clear(std::memory_order_release);
250 } else {
251 outBuffer.first.emplace_back(0);
252 outBuffer.second.emplace_back(0);
253 GPUTPCCompression_EncodeUnattached(clustersFiltered.nComppressionModes, cl, outBuffer.first.back(), outBuffer.second.back(), count++ ? &preCl : nullptr);
254 preCl = cl;
255 }
256 };
257 unsigned int end = offsets[i][j] + clusters.nSliceRowClusters[i * GPUCA_ROW_COUNT + j];
258 o2::gpu::TPCClusterDecompressionCore::decompressHits(clusters, offsets[i][j], end, checker);
259 }
260 tmpBuffer[0].first.reserve(clustersFiltered.nUnattachedClusters);
261 tmpBuffer[0].second.reserve(clustersFiltered.nUnattachedClusters);
262 for (int i = 1; i < mNThreads; i++) {
263 tmpBuffer[0].first.insert(tmpBuffer[0].first.end(), tmpBuffer[i].first.begin(), tmpBuffer[i].first.end());
264 tmpBuffer[i].first.clear();
265 tmpBuffer[0].second.insert(tmpBuffer[0].second.end(), tmpBuffer[i].second.begin(), tmpBuffer[i].second.end());
266 tmpBuffer[i].second.clear();
267 }
268 clustersFiltered.timeDiffU = tmpBuffer[0].first.data();
269 clustersFiltered.padDiffU = tmpBuffer[0].second.data();
270 }
271
272 // transform trigger info to differential form
273 uint32_t prevOrbit = -1;
274 uint16_t prevBC = -1;
275 if (trigComp.triggerType.size()) {
276 prevOrbit = trigComp.firstOrbit = trigComp.deltaOrbit[0];
277 prevBC = trigComp.deltaBC[0];
278 trigComp.deltaOrbit[0] = 0;
279 for (size_t it = 1; it < trigComp.triggerType.size(); it++) {
280 if (trigComp.deltaOrbit[it] == prevOrbit) {
281 auto bc = trigComp.deltaBC[it];
282 trigComp.deltaBC[it] -= prevBC;
283 prevBC = bc;
284 trigComp.deltaOrbit[it] = 0;
285 } else {
286 auto orb = trigComp.deltaOrbit[it];
287 trigComp.deltaOrbit[it] -= prevOrbit;
288 prevOrbit = orb;
289 }
290 }
291 }
292
293 auto iosize = mCTFCoder.encode(buffer, clusters, clustersFiltered, trigComp, mSelIR ? &rejectHits : nullptr, mSelIR ? &rejectTracks : nullptr, mSelIR ? &rejectTrackHits : nullptr, mSelIR ? &rejectTrackHitsReduced : nullptr);
294 pc.outputs().snapshot({"ctfrep", 0}, iosize);
295 mTimer.Stop();
296 if (mSelIR) {
297 mCTFCoder.getIRFramesSelector().clear();
298 }
299 LOG(info) << iosize.asString() << " in " << mTimer.CpuTime() - cput << " s";
300}
301
303{
304 LOGF(info, "TPC Entropy Encoding total timing: Cpu: %.3e Real: %.3e s in %d slots",
305 mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1);
306}
307
308DataProcessorSpec getEntropyEncoderSpec(bool inputFromFile, bool selIR)
309{
310 std::vector<InputSpec> inputs;
311 header::DataDescription inputType = inputFromFile ? header::DataDescription("COMPCLUSTERS") : header::DataDescription("COMPCLUSTERSFLAT");
312 inputs.emplace_back("input", "TPC", inputType, 0, Lifetime::Timeframe);
313 inputs.emplace_back("trigger", "TPC", "TRIGGERWORDS", 0, Lifetime::Timeframe);
314 inputs.emplace_back("ctfdict", "TPC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TPC/Calib/CTFDictionaryTree"));
315
316 std::shared_ptr<o2::base::GRPGeomRequest> ggreq;
317 if (selIR) {
318 inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe);
319 ggreq = std::make_shared<o2::base::GRPGeomRequest>(false, true, false, true, false, o2::base::GRPGeomRequest::None, inputs, true);
321 }
322 return DataProcessorSpec{
323 "tpc-entropy-encoder", // process id
324 inputs,
325 Outputs{{"TPC", "CTFDATA", 0, Lifetime::Timeframe},
326 {{"ctfrep"}, "TPC", "CTFENCREP", 0, Lifetime::Timeframe}},
327 AlgorithmSpec{adaptFromTask<EntropyEncoderSpec>(inputFromFile, selIR, ggreq)},
328 Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}},
329 {"no-ctf-columns-combining", VariantType::Bool, false, {"Do not combine correlated columns in CTF"}},
330 {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}},
331 {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}},
332 {"irframe-clusters-maxeta", VariantType::Float, 1.5f, {"Max eta for non-assigned clusters"}},
333 {"irframe-clusters-maxz", VariantType::Float, 25.f, {"Max z for non assigned clusters (combined with maxeta)"}},
334 {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}},
335 {"nThreads-tpc-encoder", VariantType::UInt32, 1u, {"number of threads to use for decoding"}},
336 {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}};
337}
338
339} // namespace tpc
340} // namespace o2
Class of a TPC cluster in TPC-native coordinates (row, time)
Container to store compressed TPC cluster data.
uint64_t bc
Definition RawEventData.h:5
int32_t i
#define GPUCA_NSECTORS
#define GPUCA_ROW_COUNT
Helper for geometry and GRP related CCDB requests.
uint32_t j
Definition RawData.h:0
class to create TPC fast transformation
ProcessorSpec for the TPC cluster entropy encoding.
Helper class to extract VDrift from different sources.
Definitions of TPC Zero Suppression Data Headers.
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
void updateTimeDependentParams(o2::framework::ProcessingContext &pc, bool askTree=false)
void init(o2::framework::InitContext &ic)
void setSelectedIRFrames(const SPAN &sp)
o2::utils::IRFrameSelector & getIRFramesSelector()
bool finaliseCCDB(o2::framework::ConcreteDataMatcher &matcher, void *obj)
static constexpr ID TPC
Definition DetID.h:64
void snapshot(const Output &spec, T const &object)
decltype(auto) make(const Output &spec, Args... args)
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
static uint32_t getTpcMaxTimeBinFromNHbf(uint32_t nHbf)
static float getNominalGPUBz(T &src)
static std::unique_ptr< GPUParam > getFullParam(float solenoidBz, uint32_t nHbfPerTf=0, std::unique_ptr< GPUO2InterfaceConfiguration > *pConfiguration=nullptr, std::unique_ptr< GPUSettingsO2 > *pO2Settings=nullptr, bool *autoMaxTimeBin=nullptr)
o2::ctf::CTFIOSize encode(VEC &buff, const CompressedClusters &ccl, const CompressedClusters &cclFiltered, const detail::TriggerInfo &trigComp, std::vector< bool > *rejectHits=nullptr, std::vector< bool > *rejectTracks=nullptr, std::vector< bool > *rejectTrackHits=nullptr, std::vector< bool > *rejectTrackHitsReduced=nullptr)
entropy-encode compressed clusters to flat buffer
Definition CTFCoder.h:184
void setCombineColumns(bool v)
Definition CTFCoder.h:162
void init(o2::framework::InitContext &ic) final
void endOfStream(o2::framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void finaliseCCDB(o2::framework::ConcreteDataMatcher &matcher, void *obj) final
EntropyEncoderSpec(bool fromFile, bool selIR=false, std::shared_ptr< o2::base::GRPGeomRequest > pgg=std::shared_ptr< o2::base::GRPGeomRequest >())
void run(o2::framework::ProcessingContext &pc) final
int updateCalibration(TPCFastTransform &transform, Long_t TimeStamp, float vDriftFactor=1.f, float vDriftRef=0.f, float driftTimeOffset=0.f)
Updates the transformation with the new time stamp.
static TPCFastTransformHelperO2 * instance()
Singleton.
static void requestCCDBInputs(std::vector< o2::framework::InputSpec > &inputs, bool laser=true, bool itstpcTgl=true)
long check(o2::dataformats::IRFrame fr, size_t bwd=0, size_t fwd=0)
GLint GLenum GLint x
Definition glcorearb.h:403
GLint GLsizei count
Definition glcorearb.h:399
GLuint buffer
Definition glcorearb.h:655
GLuint GLsizei const GLuint const GLintptr * offsets
Definition glcorearb.h:2595
GLuint GLuint end
Definition glcorearb.h:469
GLintptr offset
Definition glcorearb.h:660
GLboolean r
Definition glcorearb.h:1233
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
std::vector< ConfigParamSpec > Options
std::vector< OutputSpec > Outputs
O2 data header classes and API, v0.1.
Definition DetID.h:49
Descriptor< gSizeDataDescriptionString > DataDescription
Definition DataHeader.h:551
constexpr int LHCBCPERTIMEBIN
Definition Constants.h:38
framework::DataProcessorSpec getEntropyEncoderSpec(bool inputFromFile, bool selIR=false)
create a processor spec
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
wrapper for the Entropy-encoded clusters of the TF
Definition CTF.h:36
static constexpr int scaleTimePacked
static constexpr uint16_t MaxTriggerEntries
Maximum number of trigger information.
std::vector< int32_t > deltaOrbit
Definition CTFCoder.h:45
std::vector< int16_t > deltaBC
Definition CTFCoder.h:46
std::vector< uint8_t > triggerType
Definition CTFCoder.h:47
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Cluster > clusters