2121#include " DataFormatsTPC/Digit.h"
2222#include " CommonUtils/ConfigurableParam.h"
2323#include " DetectorsRaw/HBFUtilsInitializer.h"
24+ #include " TPCReaderWorkflow/PublisherSpec.h"
2425#include " TPCSimulation/CommonMode.h"
2526#include " DetectorsBase/Detector.h"
27+ #include " DPLUtils/MakeRootTreeWriterSpec.h"
2628#include < SimulationDataFormat/MCCompLabel.h>
2729#include < SimulationDataFormat/MCTruthContainer.h>
2830#include < SimulationDataFormat/ConstMCTruthContainer.h>
@@ -52,6 +54,10 @@ using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType;
5254using namespace o2 ::framework;
5355using namespace o2 ::header;
5456
57+ template <typename T>
58+ using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition<T>;
59+ using DigitOutputType = std::vector<o2::tpc::Digit>;
60+
5561void customize (std::vector<o2::framework::CallbacksPolicy>& policies)
5662{
5763 o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback (policies);
@@ -74,6 +80,7 @@ void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions)
7480 // option to disable MC truth
7581 workflowOptions.push_back (ConfigParamSpec{" disable-mc" , o2::framework::VariantType::Bool, false , {" disable mc-truth" }});
7682 workflowOptions.push_back (ConfigParamSpec{" configKeyValues" , VariantType::String, " " , {" Semicolon separated key=value strings ..." }});
83+ workflowOptions.push_back (ConfigParamSpec{" write-digits-file" , VariantType::Int, 0 , {" Enable writing of tpcdigis.root file" }});
7784 o2::raw::HBFUtilsInitializer::addConfigOption (workflowOptions);
7885}
7986
@@ -255,7 +262,7 @@ class Task
255262// / create the processor spec
256263// / describing a processor aggregating digits for various TPC sectors and writing them to file
257264// / MC truth information is also aggregated and written out
258- DataProcessorSpec getSpec (std::vector<int > const & laneConfiguration, std::vector<int > const & tpcsectors, bool mctruth, bool publish = true )
265+ void getSpec (WorkflowSpec& specs, std::vector<int > const & laneConfiguration, std::vector<int > const & tpcsectors, bool mctruth, bool publish = true , bool writeDigitsFile = false )
259266{
260267 // data definitions
261268 using DigitsOutputType = std::vector<o2::tpc::Digit>;
@@ -273,8 +280,75 @@ DataProcessorSpec getSpec(std::vector<int> const& laneConfiguration, std::vector
273280 }
274281 }
275282
276- return DataProcessorSpec{
277- " TPCDigitMerger" , {}, outputs, AlgorithmSpec{o2::framework::adaptFromTask<Task>(laneConfiguration, tpcsectors, mctruth)}, Options{}};
283+ specs.emplace_back (DataProcessorSpec{" TPCDigitMerger" , {}, outputs, AlgorithmSpec{o2::framework::adaptFromTask<Task>(laneConfiguration, tpcsectors, mctruth)}, Options{}});
284+
285+ if (writeDigitsFile) {
286+ // Using publishing logic from TPC: RecoWorkflow.cxx
287+ auto getIndex = [tpcsectors](o2::framework::DataRef const & ref) {
288+ auto const * tpcSectorHeader = o2::framework::DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(ref);
289+ if (!tpcSectorHeader) {
290+ throw std::runtime_error (" TPC sector header missing in header stack" );
291+ }
292+ if (tpcSectorHeader->sector () < 0 ) {
293+ // special data sets, don't write
294+ return ~(size_t )0 ;
295+ }
296+ size_t index = 0 ;
297+ for (auto const & sector : tpcsectors) {
298+ if (sector == tpcSectorHeader->sector ()) {
299+ return index;
300+ }
301+ ++index;
302+ }
303+ throw std::runtime_error (" sector " + std::to_string (tpcSectorHeader->sector ()) + " not configured for writing" );
304+ };
305+ auto getName = [tpcsectors](std::string base, size_t index) {
306+ return base + " _" + std::to_string (tpcsectors.at (index));
307+ };
308+ auto makeWriterSpec = [tpcsectors, laneConfiguration, mctruth, getIndex, getName](const char * processName,
309+ const char * defaultFileName,
310+ const char * defaultTreeName,
311+ auto && databranch,
312+ auto && mcbranch,
313+ bool singleBranch = false ) {
314+ if (tpcsectors.size () == 0 ) {
315+ throw std::invalid_argument (std::string (" writer process configuration needs list of TPC sectors" ));
316+ }
317+
318+ auto amendInput = [tpcsectors, laneConfiguration](InputSpec& input, size_t index) {
319+ input.binding += std::to_string (laneConfiguration[index]);
320+ DataSpecUtils::updateMatchingSubspec (input, laneConfiguration[index]);
321+ };
322+ auto amendBranchDef = [laneConfiguration, amendInput, tpcsectors, getIndex, getName, singleBranch](auto && def, bool enableMC = true ) {
323+ if (!singleBranch) {
324+ def.keys = mergeInputs (def.keys , laneConfiguration.size (), amendInput);
325+ // the branch is disabled if set to 0
326+ def.nofBranches = enableMC ? tpcsectors.size () : 0 ;
327+ def.getIndex = getIndex;
328+ def.getName = getName;
329+ } else {
330+ // instead of the separate sector branches only one is going to be written
331+ def.nofBranches = enableMC ? 1 : 0 ;
332+ }
333+ return std::move (def);
334+ };
335+
336+ return std::move (MakeRootTreeWriterSpec (processName, defaultFileName, defaultTreeName,
337+ std::move (amendBranchDef (databranch)),
338+ std::move (amendBranchDef (mcbranch, mctruth)))());
339+ };
340+
341+ using DigitOutputType = std::vector<o2::tpc::Digit>;
342+ specs.push_back (makeWriterSpec (" tpc-digits-writer" ,
343+ " tpcdigits.root" ,
344+ " o2sim" ,
345+ BranchDefinition<DigitOutputType>{InputSpec{" data" , " TPC" , " DIGITS" , 0 },
346+ " TPCDigit" ,
347+ " digit-branch-name" },
348+ BranchDefinition<o2::dataformats::MCLabelContainer>{InputSpec{" mc" , " TPC" , " DIGITSMCTR" , 0 },
349+ " TPCDigitMCTruth" ,
350+ " digitmc-branch-name" }));
351+ }
278352}
279353
280354} // end namespace tpc
@@ -287,11 +361,12 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext)
287361
288362 auto numlanes = configcontext.options ().get <int >(" tpc-lanes" );
289363 bool mctruth = !configcontext.options ().get <bool >(" disable-mc" );
364+ bool writeDigitsFile = configcontext.options ().get <bool >(" write-digits-file" );
290365 auto tpcsectors = o2::RangeTokenizer::tokenize<int >(configcontext.options ().get <std::string>(" tpc-sectors" ));
291366
292367 std::vector<int > lanes (numlanes);
293368 std::iota (lanes.begin (), lanes.end (), 0 );
294- specs. emplace_back ( o2::tpc::getSpec (lanes, tpcsectors, mctruth) );
369+ o2::tpc::getSpec (specs, lanes, tpcsectors, mctruth, true , writeDigitsFile );
295370
296371 // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit
297372 o2::raw::HBFUtilsInitializer hbfIni (configcontext, specs);
0 commit comments