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); 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"),