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"
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
6062namespace 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" }},
0 commit comments