Skip to content

Commit ddd65a0

Browse files
Rework of the TPC reco workflow to support compressed clusters
New output types added - compressed-clusters - encoded-clusters - integrating the handling of compressed clusters object produced by the CA track, data is sent out with spec TPC/COMPCLUSTERS/0 - adding a skeleton for the TPC cluster encoder
1 parent c3cdd2f commit ddd65a0

File tree

7 files changed

+315
-30
lines changed

7 files changed

+315
-30
lines changed

Detectors/TPC/workflow/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ o2_add_library(TPCWorkflow
1515
src/ClustererSpec.cxx
1616
src/ClusterDecoderRawSpec.cxx
1717
src/CATrackerSpec.cxx
18+
src/EntropyEncoderSpec.cxx
1819
src/TrackReaderSpec.cxx
1920
src/RawToDigitsSpec.cxx
2021
src/LinkZSToDigitsSpec.cxx

Detectors/TPC/workflow/include/TPCWorkflow/CATrackerSpec.h

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,74 @@
1414
/// @brief Processor spec for running TPC CA tracking
1515

1616
#include "Framework/DataProcessorSpec.h"
17+
#include <utility> // std::forward
1718

1819
namespace o2
1920
{
2021
namespace tpc
2122
{
2223

24+
namespace ca
25+
{
26+
// The CA tracker is now a wrapper to not only the actual tracking on GPU but
27+
// also the decoding of the zero-suppressed raw format and the clusterer.
28+
enum struct Operation {
29+
CAClusterer, // run the CA clusterer
30+
ZSDecoder, // run the ZS raw data decoder
31+
OutputTracks, // publish tracks
32+
OutputCompClusters, // publish CompClusters container
33+
ProcessMC, // process MC labels
34+
Noop, // skip argument on the constructor
35+
};
36+
37+
struct Config {
38+
template <typename... Args>
39+
Config(Args&&... args)
40+
{
41+
init(std::forward<Args>(args)...);
42+
}
43+
44+
template <typename... Args>
45+
void init(Operation const& op, Args&&... args)
46+
{
47+
switch (op) {
48+
case Operation::CAClusterer:
49+
caClusterer = true;
50+
break;
51+
case Operation::ZSDecoder:
52+
zsDecoder = true;
53+
break;
54+
case Operation::OutputTracks:
55+
outputTracks = true;
56+
break;
57+
case Operation::OutputCompClusters:
58+
outputCompClusters = true;
59+
break;
60+
case Operation::ProcessMC:
61+
processMC = true;
62+
break;
63+
case Operation::Noop:
64+
break;
65+
default:
66+
throw std::runtime_error("invalid CATracker operation");
67+
}
68+
if constexpr (sizeof...(args) > 0) {
69+
init(std::forward<Args>(args)...);
70+
}
71+
}
72+
73+
bool caClusterer = false;
74+
bool zsDecoder = false;
75+
bool outputTracks = false;
76+
bool outputCompClusters = false;
77+
bool processMC = false;
78+
};
79+
80+
} // namespace ca
81+
2382
/// create a processor spec
2483
/// read simulated TPC clusters from file and publish
25-
framework::DataProcessorSpec getCATrackerSpec(bool processMC, bool caClusterer, bool zsDecoder, std::vector<int> const& inputIds);
84+
framework::DataProcessorSpec getCATrackerSpec(ca::Config const& config, std::vector<int> const& inputIds);
2685

2786
} // end namespace tpc
2887
} // end namespace o2
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
11+
#ifndef O2_TPC_ENTROPYENCODERSPEC_H
12+
#define O2_TPC_ENTROPYENCODERSPEC_H
13+
/// @file EntropyEncoderSpec.h
14+
/// @author Michael Lettrich, Matthias Richter
15+
/// @since 2020-01-16
16+
/// @brief ProcessorSpec for the TPC cluster entropy encoding
17+
18+
#include "Framework/DataProcessorSpec.h"
19+
20+
namespace o2
21+
{
22+
namespace tpc
23+
{
24+
25+
/// create a processor spec
26+
framework::DataProcessorSpec getEntropyEncoderSpec();
27+
28+
} // end namespace tpc
29+
} // end namespace o2
30+
31+
#endif // O2_TPC_ENTROPYENCODERSPEC_H

Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,24 @@ enum struct InputType { Digitizer, // directly read digits from channel {
3232
Digits, // read digits from file
3333
ClustersHardware, // read hardware clusters in raw page format from file
3434
Clusters, // read native clusters from file
35+
CompClusters, // read compressed cluster container
36+
EncodedClusters, // read encoded clusters
3537
ZSRaw,
3638
};
39+
40+
/// Output types of the workflow, workflow layout is built depending on configured types
41+
/// - Digits simulated digits
42+
/// - ClustersHardware the first attempt of a raw format storing ClusterHardware in 8k pages
43+
/// - Clusters decoded clusters, ClusterNative, as input to the tracker
44+
/// - Tracks tracks
45+
/// - CompClusters compressed clusters, CompClusters container
46+
/// - EncodedClusters the encoded CompClusters container
3747
enum struct OutputType { Digits,
3848
ClustersHardware,
3949
Clusters,
4050
Tracks,
51+
CompClusters,
52+
EncodedClusters,
4153
DisableWriter,
4254
};
4355

Detectors/TPC/workflow/src/CATrackerSpec.cxx

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
#include "Framework/ControlService.h"
2222
#include "Framework/ConfigParamRegistry.h"
2323
#include "Framework/InputRecordWalker.h"
24+
#include "Framework/SerializationMethods.h"
25+
#include "Framework/Logger.h"
2426
#include "DataFormatsTPC/TPCSectorHeader.h"
2527
#include "DataFormatsTPC/ClusterGroupAttribute.h"
2628
#include "DataFormatsTPC/ClusterNative.h"
2729
#include "DataFormatsTPC/ClusterNativeHelper.h"
30+
#include "DataFormatsTPC/CompressedClusters.h"
2831
#include "DataFormatsTPC/Helpers.h"
2932
#include "DataFormatsTPC/ZeroSuppression.h"
3033
#include "TPCReconstruction/GPUCATracking.h"
@@ -44,7 +47,6 @@
4447
#include "SimulationDataFormat/MCTruthContainer.h"
4548
#include "SimulationDataFormat/MCCompLabel.h"
4649
#include "Algorithm/Parser.h"
47-
#include <FairMQLogger.h>
4850
#include <memory> // for make_shared
4951
#include <vector>
5052
#include <iomanip>
@@ -60,8 +62,11 @@ namespace o2
6062
namespace tpc
6163
{
6264

63-
DataProcessorSpec getCATrackerSpec(bool processMC, bool caClusterer, bool zsDecoder, std::vector<int> const& inputIds)
65+
DataProcessorSpec getCATrackerSpec(ca::Config const& config, std::vector<int> const& inputIds)
6466
{
67+
auto& processMC = config.processMC;
68+
auto& caClusterer = config.caClusterer;
69+
auto& zsDecoder = config.zsDecoder;
6570
constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR;
6671
using ClusterGroupParser = o2::algorithm::ForwardParser<o2::tpc::ClusterGroupHeader>;
6772
struct ProcessAttributes {
@@ -578,20 +583,31 @@ DataProcessorSpec getCATrackerSpec(bool processMC, bool caClusterer, bool zsDeco
578583
LOG(ERROR) << "tracker returned error code " << retVal;
579584
}
580585
LOG(INFO) << "found " << tracks.size() << " track(s)";
581-
pc.outputs().snapshot(OutputRef{"outTracks"}, tracks);
582-
pc.outputs().snapshot(OutputRef{"outClusRefs"}, clusRefs);
583-
if (processMC) {
584-
LOG(INFO) << "sending " << tracksMCTruth.getIndexedSize() << " track label(s)";
585-
pc.outputs().snapshot(OutputRef{"mclblout"}, tracksMCTruth);
586+
// tracks are published if the output channel is configured
587+
if (pc.outputs().isAllowed({gDataOriginTPC, "TRACKS", 0})) {
588+
pc.outputs().snapshot(OutputRef{"outTracks"}, tracks);
589+
pc.outputs().snapshot(OutputRef{"outClusRefs"}, clusRefs);
590+
if (pc.outputs().isAllowed({gDataOriginTPC, "TRACKMCLBL", 0})) {
591+
LOG(INFO) << "sending " << tracksMCTruth.getIndexedSize() << " track label(s)";
592+
pc.outputs().snapshot(OutputRef{"mclblout"}, tracksMCTruth);
593+
}
586594
}
587595

588-
// TODO - Process Compressed Clusters Output
589-
const o2::tpc::CompressedClusters* compressedClusters = ptrs.compressedClusters; // This is a ROOT-serializable container with compressed TPC clusters
596+
// The tracker produces a ROOT-serializable container with compressed TPC clusters
597+
// It is published if the output channel for the CompClusters container is configured
590598
// Example to decompress clusters
591599
//#include "TPCClusterDecompressor.cxx"
592600
//o2::tpc::ClusterNativeAccess clustersNativeDecoded; // Cluster native access structure as used by the tracker
593601
//std::vector<o2::tpc::ClusterNative> clusterBuffer; // std::vector that will hold the actual clusters, clustersNativeDecoded will point inside here
594602
//mDecoder.decompress(clustersCompressed, clustersNativeDecoded, clusterBuffer, param); // Run decompressor
603+
if (pc.outputs().isAllowed({gDataOriginTPC, "COMPCLUSTERS", 0})) {
604+
const o2::tpc::CompressedClusters* compressedClusters = ptrs.compressedClusters;
605+
if (compressedClusters != nullptr) {
606+
pc.outputs().snapshot(Output{gDataOriginTPC, "COMPCLUSTERS", 0}, ROOTSerialized<o2::tpc::CompressedClusters const>(*compressedClusters));
607+
} else {
608+
LOG(ERROR) << "unable to get compressed cluster info from track";
609+
}
610+
}
595611

596612
processAttributes->bufferCache.clear();
597613
processAttributes->tpcZSmessagesReceived = 0;
@@ -617,20 +633,20 @@ DataProcessorSpec getCATrackerSpec(bool processMC, bool caClusterer, bool zsDeco
617633
// changing the binding name of the input in order to identify inputs by unique labels
618634
// in the processing. Think about how the processing can be made agnostic of input size,
619635
// e.g. by providing a span of inputs under a certain label
620-
auto createInputSpecs = [inputIds](bool makeMcInput, bool caClusterer, bool zsDecoder) {
636+
auto createInputSpecs = [&inputIds, &config]() {
621637
Inputs inputs;
622-
if (caClusterer) {
638+
if (config.caClusterer) {
623639
// We accept digits and MC labels also if we run on ZS Raw data, since they are needed for MC label propagation
624-
if (!zsDecoder) { // FIXME: We can have digits input in zs decoder mode for MC labels, to be made optional
640+
if (!config.zsDecoder) { // FIXME: We can have digits input in zs decoder mode for MC labels, to be made optional
625641
inputs.emplace_back(InputSpec{"input", gDataOriginTPC, "DIGITS", 0, Lifetime::Timeframe});
626642
}
627643
} else {
628644
inputs.emplace_back(InputSpec{"input", gDataOriginTPC, "CLUSTERNATIVE", 0, Lifetime::Timeframe});
629645
}
630-
if (makeMcInput) {
631-
if (caClusterer) {
646+
if (config.processMC) {
647+
if (config.caClusterer) {
632648
constexpr o2::header::DataDescription datadesc("DIGITSMCTR");
633-
if (!zsDecoder) { // FIXME: We can have digits input in zs decoder mode for MC labels, to be made optional
649+
if (!config.zsDecoder) { // FIXME: We can have digits input in zs decoder mode for MC labels, to be made optional
634650
inputs.emplace_back(InputSpec{"mclblin", gDataOriginTPC, datadesc, 0, Lifetime::Timeframe});
635651
}
636652
} else {
@@ -645,29 +661,36 @@ DataProcessorSpec getCATrackerSpec(bool processMC, bool caClusterer, bool zsDeco
645661
input.binding += std::to_string(inputIds[index]);
646662
DataSpecUtils::updateMatchingSubspec(input, inputIds[index]);
647663
}));
648-
if (zsDecoder) {
664+
if (config.zsDecoder) {
649665
// We add this after the mergeInputs, since we need to keep the subspecification
650666
tmp.emplace_back(InputSpec{"zsraw", ConcreteDataTypeMatcher{"TPC", "RAWDATA"}, Lifetime::Timeframe});
651667
}
652668
return tmp;
653669
};
654670

655-
auto createOutputSpecs = [](bool makeMcOutput) {
671+
auto createOutputSpecs = [&config]() {
656672
std::vector<OutputSpec> outputSpecs{
657673
OutputSpec{{"outTracks"}, gDataOriginTPC, "TRACKS", 0, Lifetime::Timeframe},
658674
OutputSpec{{"outClusRefs"}, gDataOriginTPC, "CLUSREFS", 0, Lifetime::Timeframe},
659675
};
660-
if (makeMcOutput) {
676+
if (!config.outputTracks) {
677+
// this case is the less unlikely one, that's why the logic this way
678+
outputSpecs.clear();
679+
}
680+
if (config.processMC && config.outputTracks) {
661681
OutputLabel label{"mclblout"};
662682
constexpr o2::header::DataDescription datadesc("TRACKMCLBL");
663683
outputSpecs.emplace_back(label, gDataOriginTPC, datadesc, 0, Lifetime::Timeframe);
664684
}
685+
if (config.outputCompClusters) {
686+
outputSpecs.emplace_back(gDataOriginTPC, "COMPCLUSTERS", 0, Lifetime::Timeframe);
687+
}
665688
return std::move(outputSpecs);
666689
};
667690

668691
return DataProcessorSpec{"tpc-tracker", // process id
669-
{createInputSpecs(processMC, caClusterer, zsDecoder)},
670-
{createOutputSpecs(processMC)},
692+
{createInputSpecs()},
693+
{createOutputSpecs()},
671694
AlgorithmSpec(initFunction),
672695
Options{
673696
{"tracker-options", VariantType::String, "", {"Option string passed to tracker"}},
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
11+
/// @file EntropyEncoderSpec.cxx
12+
/// @author Michael Lettrich, Matthias Richter
13+
/// @since 2020-01-16
14+
/// @brief ProcessorSpec for the TPC cluster entropy encoding
15+
16+
#include "TPCWorkflow/EntropyEncoderSpec.h"
17+
#include "Headers/DataHeader.h"
18+
#include "Framework/WorkflowSpec.h" // o2::framework::mergeInputs
19+
#include "Framework/DataRefUtils.h"
20+
#include "Framework/DataSpecUtils.h"
21+
#include "Framework/ControlService.h"
22+
#include "Framework/ConfigParamRegistry.h"
23+
#include "Framework/Logger.h"
24+
#include "DataFormatsTPC/CompressedClusters.h"
25+
//#include "TPCClusterDecompressor.cxx"
26+
#include <memory> // for make_shared
27+
#include <vector>
28+
29+
// TEMP: as a test, the processor simply writes the data to file, remove this
30+
#include <TFile.h>
31+
#include <TTree.h>
32+
33+
using namespace o2::framework;
34+
using namespace o2::header;
35+
36+
namespace o2
37+
{
38+
namespace tpc
39+
{
40+
41+
DataProcessorSpec getEntropyEncoderSpec()
42+
{
43+
struct ProcessAttributes {
44+
int verbosity = 1;
45+
};
46+
47+
auto initFunction = [](InitContext& ic) {
48+
auto processAttributes = std::make_shared<ProcessAttributes>();
49+
50+
auto processingFct = [processAttributes](ProcessingContext& pc) {
51+
auto compressed = pc.inputs().get<CompressedClusters*>("input");
52+
if (compressed == nullptr) {
53+
LOG(ERROR) << "invalid input";
54+
return;
55+
}
56+
LOG(INFO) << "input data with " << compressed->nTracks << " track(s) and " << compressed->nAttachedClusters << " attached clusters";
57+
58+
std::unique_ptr<TFile> testFile(TFile::Open("tpc-cluster-encoder.root", "RECREATE"));
59+
testFile->WriteObject(compressed.get(), "TPCCompressedClusters");
60+
testFile->Write();
61+
testFile->Close();
62+
63+
//o2::tpc::ClusterNativeAccess clustersNativeDecoded; // Cluster native access structure as used by the tracker
64+
//std::vector<o2::tpc::ClusterNative> clusterBuffer; // std::vector that will hold the actual clusters, clustersNativeDecoded will point inside here
65+
//mDecoder.decompress(clustersCompressed, clustersNativeDecoded, clusterBuffer, param); // Run decompressor
66+
};
67+
68+
return processingFct;
69+
};
70+
71+
return DataProcessorSpec{"tpc-entropy-encoder", // process id
72+
{{"input", "TPC", "COMPCLUSTERS", 0, Lifetime::Timeframe}},
73+
{},
74+
AlgorithmSpec(initFunction)};
75+
}
76+
77+
} // namespace tpc
78+
} // namespace o2

0 commit comments

Comments
 (0)