From 7748d4a2a4e7c751d072a65d23e13b54b6f45fa0 Mon Sep 17 00:00:00 2001 From: mfasel Date: Thu, 29 Jul 2021 12:24:58 +0200 Subject: [PATCH 1/2] [EMCAL-660] Implement FEC-FLP mapping Mapping implemented in mapping hander, providing the FLP number for a given EMCAL FEC. The mapping is implemeted according to https://alice.its.cern.ch/jira/browse/EMCAL-660 --- Detectors/EMCAL/base/include/EMCALBase/Mapper.h | 7 +++++++ Detectors/EMCAL/base/src/Mapper.cxx | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/Detectors/EMCAL/base/include/EMCALBase/Mapper.h b/Detectors/EMCAL/base/include/EMCALBase/Mapper.h index 32f606840affd..3eec281ce84c1 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/Mapper.h +++ b/Detectors/EMCAL/base/include/EMCALBase/Mapper.h @@ -345,6 +345,13 @@ class MappingHandler /// \param branch Branch index (0 or 1) in DDL int getFEEForChannelInDDL(int dll, int channelFEC, int branch); + /// \brief Get index of the FLP based on the DDL ID + /// \param ddl Absolute DDL index + /// \return FLP index + /// + /// Current DDL - FLP indexing can be found in EMCAL-660 + int getFLPIndex(int ddl); + private: std::array mMappings; ///< Mapping container diff --git a/Detectors/EMCAL/base/src/Mapper.cxx b/Detectors/EMCAL/base/src/Mapper.cxx index 4f6105f39c4bb..48c0e612ddee8 100644 --- a/Detectors/EMCAL/base/src/Mapper.cxx +++ b/Detectors/EMCAL/base/src/Mapper.cxx @@ -131,6 +131,17 @@ int MappingHandler::getFEEForChannelInDDL(int ddl, int channelFEC, int branch) return fecID; } +int MappingHandler::getFLPIndex(int ddl) +{ + if ((ddl >= 0 && ddl <= 23) || ddl == 44) { + return 146; // EMCAL Links (44 - STU) -> FLP 146 + } + if ((ddl >= 24 && ddl <= 38) || ddl == 45) { + return 147; // DCAL Links (45 - STU) -> FLP 147 + } + throw DDLInvalid(ddl); +} + std::ostream& o2::emcal::operator<<(std::ostream& stream, const Mapper::ChannelID& channel) { stream << "Row " << static_cast(channel.mRow) << ", Column " << static_cast(channel.mColumn) << ", type " << o2::emcal::channelTypeToString(channel.mChannelType); From 9c966b4f711d940b1841ac0854429b84237d7944 Mon Sep 17 00:00:00 2001 From: mfasel Date: Thu, 29 Jul 2021 12:29:47 +0200 Subject: [PATCH 2/2] [EMCAL-703] Add option to auto-configure subspecification In case of auto-configure mode the subspecification is determined based on the first header in the payload using the ID of the FLP determined via the FEE ID. The output specs are defined with wildcard subspecification according to the discussion in https://alice-talk.web.cern.ch/t/flp-specific-subspecifications/1035/6. In case of empty timeframe empty cell containers are sent to the deadbeaf subspecification which must be caught by receiver processors. --- .../EMCALWorkflow/RawToCellConverterSpec.h | 63 +++++++++++++------ .../include/EMCALWorkflow/RecoWorkflow.h | 2 - .../workflow/src/RawToCellConverterSpec.cxx | 46 ++++++++++---- Detectors/EMCAL/workflow/src/RecoWorkflow.cxx | 9 ++- .../EMCAL/workflow/src/emc-reco-workflow.cxx | 4 +- 5 files changed, 82 insertions(+), 42 deletions(-) diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h index f57739ae228c0..cf989fd9f8f9f 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h @@ -37,9 +37,8 @@ namespace reco_workflow class RawToCellConverterSpec : public framework::Task { public: - /// \brief Constructor - /// \param subspecification Output subspecification for parallel running on multiple nodes - RawToCellConverterSpec(int subspecification) : framework::Task(), mSubspecification(subspecification){}; + /// \brief Default constructor + RawToCellConverterSpec() = default; /// \brief Destructor ~RawToCellConverterSpec() override; @@ -63,7 +62,16 @@ class RawToCellConverterSpec : public framework::Task /// Error messages will be suppressed once the maximum is reached void setMaxErrorMessages(int maxMessages) { mMaxErrorMessages = maxMessages; } - void setNoiseThreshold(int thresold) { mNoiseThreshold = thresold; } + /// \brief Set the noise threshold + /// \param threshold Noise threshold + /// + /// ADC values below the noise threshold are suppressed in the raw fit + void setNoiseThreshold(int threshold) { mNoiseThreshold = threshold; } + + /// \brief Get the noise threshold + /// \return Noise threshold + /// + /// ADC values below the noise threshold are suppressed in the raw fit int getNoiseThreshold() const { return mNoiseThreshold; } /// \brief Set ID of the subspecification @@ -81,26 +89,43 @@ class RawToCellConverterSpec : public framework::Task header::DataHeader::SubSpecificationType getSubspecification() const { return mSubspecification; } private: + /// \brief Determine whether the timeframe is empty + /// \param ctx Processing context with all inputs + /// + /// Empty timeframes are detected via the deadbeaf + /// subspecification of the input channel. bool isLostTimeframe(framework::ProcessingContext& ctx) const; - void sendData(framework::ProcessingContext& ctx, const std::vector& cells, const std::vector& triggers, const std::vector& decodingErrors) const; - - header::DataHeader::SubSpecificationType mSubspecification = 0; ///< Subspecification for output channels - int mNoiseThreshold = 0; ///< Noise threshold in raw fit - int mNumErrorMessages = 0; ///< Current number of error messages - int mErrorMessagesSuppressed = 0; ///< Counter of suppressed error messages - int mMaxErrorMessages = 100; ///< Max. number of error messages - Geometry* mGeometry = nullptr; ///! mMapper = nullptr; ///! mRawFitter; ///! mOutputCells; ///< Container with output cells - std::vector mOutputTriggerRecords; ///< Container with output cells - std::vector mOutputDecoderErrors; ///< Container with decoder errors + + /// \brief Send data to output channels + /// \param cells Container with output cells for timeframe + /// \param triggers Container with trigger records for timeframe + /// \param decodingErrors Container with decoding errors for timeframe + /// \param subspecification Output subspecification + /// + /// Send data to all output channels for the given subspecification. The subspecification + /// is determined on the fly in the run method and therefore used as parameter. Consumers + /// must use wildcard subspecification via ConcreteDataTypeMatcher. + void sendData(framework::ProcessingContext& ctx, const std::vector& cells, const std::vector& triggers, const std::vector& decodingErrors, header::DataHeader::SubSpecificationType subspecification) const; + + header::DataHeader::SubSpecificationType mSubspecification = UINT32_MAX; ///< Subspecification for output channels + int mNoiseThreshold = 0; ///< Noise threshold in raw fit + int mNumErrorMessages = 0; ///< Current number of error messages + int mErrorMessagesSuppressed = 0; ///< Counter of suppressed error messages + int mMaxErrorMessages = 100; ///< Max. number of error messages + bool mAutoDefineSubspec = false; ///< Automatically determine the subspecification based on the FEE ID of the first RDH + Geometry* mGeometry = nullptr; ///! mMapper = nullptr; ///! mRawFitter; ///! mOutputCells; ///< Container with output cells + std::vector mOutputTriggerRecords; ///< Container with output cells + std::vector mOutputDecoderErrors; ///< Container with decoder errors }; /// \brief Creating DataProcessorSpec for the EMCAL Cell Converter Spec +/// \param askDISTSTF if true the task subscribes also to FLP/DISTSUBTIMEFRAME /// -/// Refer to RawToCellConverterSpec::run for input and output specs -framework::DataProcessorSpec getRawToCellConverterSpec(bool askDISTSTF, int subspecification); +/// Refer to RawToCellConverterSpec::run for input and output specs. +framework::DataProcessorSpec getRawToCellConverterSpec(bool askDISTSTF); } // namespace reco_workflow diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h index b92bfa0dc34af..9c84e81c8f5cc 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h @@ -48,7 +48,6 @@ enum struct OutputType { Digits, ///< EMCAL digits /// \param propagateMC If true MC labels are propagated to the output files /// \param askDISTSTF If true the Raw->Cell converter subscribes to FLP/DISTSUBTIMEFRAME /// \param enableDigitsPrinter If true then the simple digits printer is added as dummy task -/// \param subspecification Subspecification in case of running on different FLPs /// \param cfgInput Input objects processed in the workflow /// \param cfgOutput Output objects created in the workflow /// \return EMCAL reconstruction workflow for the configuration provided @@ -56,7 +55,6 @@ enum struct OutputType { Digits, ///< EMCAL digits framework::WorkflowSpec getWorkflow(bool propagateMC = true, bool askDISTSTF = true, bool enableDigitsPrinter = false, - int subspecification = 0, std::string const& cfgInput = "digits", std::string const& cfgOutput = "clusters", bool disableRootInput = false, diff --git a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx index 329930091ab2a..8d6861e008231 100644 --- a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx @@ -58,6 +58,12 @@ void RawToCellConverterSpec::init(framework::InitContext& ctx) LOG(ERROR) << "Failed to initialize mapper"; } + if (ctx.options().get("autosubspec")) { + mAutoDefineSubspec = true; + } else { + mSubspecification = ctx.options().get("subspec"); + } + auto fitmethod = ctx.options().get("fitmethod"); if (fitmethod == "standard") { LOG(INFO) << "Using standard raw fitter"; @@ -85,7 +91,7 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) mOutputDecoderErrors.clear(); if (isLostTimeframe(ctx)) { - sendData(ctx, mOutputCells, mOutputTriggerRecords, mOutputDecoderErrors); + sendData(ctx, mOutputCells, mOutputTriggerRecords, mOutputDecoderErrors, 0xdeadbeaf); return; } @@ -103,6 +109,19 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) continue; } + // handle subspecificaiton for output channels + if (mSubspecification == UINT32_MAX) { + // Subspecification not defined + if (mAutoDefineSubspec) { + // get the subspecification from the first FEE ID + mSubspecification = mMapper->getFLPIndex(raw::RDHUtils::getFEEID(rdhblock)); + } else { + // Use defaut subspecification 0 + mSubspecification = 0; + } + LOG(INFO) << "Using output subspecification " << mSubspecification; + } + //o2::emcal::RawReaderMemory rawreader(gsl::span(rawData.payload, o2::framework::DataRefUtils::getPayloadSize(rawData))); o2::emcal::RawReaderMemory rawreader(framework::DataRefUtils::as(rawData)); @@ -253,7 +272,7 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) } LOG(DEBUG) << "[EMCALRawToCellConverter - run] Writing " << mOutputCells.size() << " cells ..."; - sendData(ctx, mOutputCells, mOutputTriggerRecords, mOutputDecoderErrors); + sendData(ctx, mOutputCells, mOutputTriggerRecords, mOutputDecoderErrors, mSubspecification); } bool RawToCellConverterSpec::isLostTimeframe(framework::ProcessingContext& ctx) const @@ -272,22 +291,21 @@ bool RawToCellConverterSpec::isLostTimeframe(framework::ProcessingContext& ctx) return false; } -void RawToCellConverterSpec::sendData(framework::ProcessingContext& ctx, const std::vector& cells, const std::vector& triggers, const std::vector& decodingErrors) const +void RawToCellConverterSpec::sendData(framework::ProcessingContext& ctx, const std::vector& cells, const std::vector& triggers, const std::vector& decodingErrors, header::DataHeader::SubSpecificationType subspecification) const { constexpr auto originEMC = o2::header::gDataOriginEMC; - ctx.outputs().snapshot(framework::Output{originEMC, "CELLS", mSubspecification, framework::Lifetime::Timeframe}, cells); - ctx.outputs().snapshot(framework::Output{originEMC, "CELLSTRGR", mSubspecification, framework::Lifetime::Timeframe}, triggers); - ctx.outputs().snapshot(framework::Output{originEMC, "DECODERERR", mSubspecification, framework::Lifetime::Timeframe}, decodingErrors); + ctx.outputs().snapshot(framework::Output{originEMC, "CELLS", subspecification, framework::Lifetime::Timeframe}, cells); + ctx.outputs().snapshot(framework::Output{originEMC, "CELLSTRGR", subspecification, framework::Lifetime::Timeframe}, triggers); + ctx.outputs().snapshot(framework::Output{originEMC, "DECODERERR", subspecification, framework::Lifetime::Timeframe}, decodingErrors); } -o2::framework::DataProcessorSpec o2::emcal::reco_workflow::getRawToCellConverterSpec(bool askDISTSTF, int subspecification) +o2::framework::DataProcessorSpec o2::emcal::reco_workflow::getRawToCellConverterSpec(bool askDISTSTF) { constexpr auto originEMC = o2::header::gDataOriginEMC; - std::vector outputs; - - outputs.emplace_back(originEMC, "CELLS", subspecification, o2::framework::Lifetime::Timeframe); - outputs.emplace_back(originEMC, "CELLSTRGR", subspecification, o2::framework::Lifetime::Timeframe); - outputs.emplace_back(originEMC, "DECODERERR", subspecification, o2::framework::Lifetime::Timeframe); + std::vector outputs{ + {framework::ConcreteDataTypeMatcher(originEMC, "CELLS"), framework::Lifetime::Timeframe}, + {framework::ConcreteDataTypeMatcher(originEMC, "CELLSTRGR"), framework::Lifetime::Timeframe}, + {framework::ConcreteDataTypeMatcher(originEMC, "DECODERERR"), framework::Lifetime::Timeframe}}; std::vector inputs{{"stf", o2::framework::ConcreteDataTypeMatcher{originEMC, o2::header::gDataDescriptionRawData}, o2::framework::Lifetime::Optional}}; if (askDISTSTF) { @@ -297,8 +315,10 @@ o2::framework::DataProcessorSpec o2::emcal::reco_workflow::getRawToCellConverter return o2::framework::DataProcessorSpec{"EMCALRawToCellConverterSpec", inputs, outputs, - o2::framework::adaptFromTask(subspecification), + o2::framework::adaptFromTask(), o2::framework::Options{ + {"autosubspec", o2::framework::VariantType::Bool, false, {"Automatically configure output spec from RDH"}}, + {"subspec", o2::framework::VariantType::Int, 0, {"Subspecification (if set manually and not auto-configured"}}, {"fitmethod", o2::framework::VariantType::String, "gamma2", {"Fit method (standard or gamma2)"}}, {"maxmessage", o2::framework::VariantType::Int, 100, {"Max. amout of error messages to be displayed"}}}}; } diff --git a/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx b/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx index 528be3775953f..778779a9b6f73 100644 --- a/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx +++ b/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx @@ -48,7 +48,6 @@ namespace reco_workflow o2::framework::WorkflowSpec getWorkflow(bool propagateMC, bool askDISTSTF, bool enableDigitsPrinter, - int subspecification, std::string const& cfgInput, std::string const& cfgOutput, bool disableRootInput, @@ -170,7 +169,7 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, specs.emplace_back(o2::emcal::reco_workflow::getCellConverterSpec(propagateMC)); } else if (inputType == InputType::Raw) { // raw data will come from upstream - specs.emplace_back(o2::emcal::reco_workflow::getRawToCellConverterSpec(askDISTSTF, subspecification)); + specs.emplace_back(o2::emcal::reco_workflow::getRawToCellConverterSpec(askDISTSTF)); } } @@ -288,13 +287,13 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, specs.push_back(makeWriterSpec_CellsTR("emcal-cells-writer", "emccells.root", "o2sim", - BranchDefinition{o2::framework::InputSpec{"data", "EMC", "CELLS", 0}, + BranchDefinition{o2::framework::InputSpec{"data", framework::ConcreteDataTypeMatcher("EMC", "CELLS")}, "EMCALCell", "cell-branch-name"}, - BranchDefinition{o2::framework::InputSpec{"trigger", "EMC", "CELLSTRGR", 0}, + BranchDefinition{o2::framework::InputSpec{"trigger", framework::ConcreteDataTypeMatcher("EMC", "CELLSTRGR")}, "EMCALCellTRGR", "celltrigger-branch-name"}, - BranchDefinition{o2::framework::InputSpec{"errors", "EMC", "DECODERERR", 0}, + BranchDefinition{o2::framework::InputSpec{"errors", framework::ConcreteDataTypeMatcher("EMC", "DECODERERR")}, "EMCALDECODERERR", "decodererror-branch-name"})()); } diff --git a/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx b/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx index fa7b00da9d035..e9cf62c9075c3 100644 --- a/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx +++ b/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx @@ -37,8 +37,7 @@ void customize(std::vector& workflowOptions) {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not initialize root file writers"}}, {"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information"}}, - {"ignore-dist-stf", o2::framework::VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, - {"subspecification", o2::framework::VariantType::Int, 0, {"Subspecification in case the workflow runs in parallel on multiple nodes (i.e. different FLPs)"}}}; + {"ignore-dist-stf", o2::framework::VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}}; o2::raw::HBFUtilsInitializer::addConfigOption(options); @@ -65,7 +64,6 @@ o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext co auto wf = o2::emcal::reco_workflow::getWorkflow(!cfgc.options().get("disable-mc"), !cfgc.options().get("ignore-dist-stf"), cfgc.options().get("enable-digits-printer"), - cfgc.options().get("subspecification"), cfgc.options().get("input-type"), cfgc.options().get("output-type"), cfgc.options().get("disable-root-input"),