diff --git a/k4MarlinWrapper/CMakeLists.txt b/k4MarlinWrapper/CMakeLists.txt index df1cdad6..e7223732 100644 --- a/k4MarlinWrapper/CMakeLists.txt +++ b/k4MarlinWrapper/CMakeLists.txt @@ -23,6 +23,7 @@ gaudi_install(SCRIPTS) # k4MarlinWrapperPlugins gaudi_add_module(k4MarlinWrapperPlugins SOURCES + src/components/CellIDEncodingFiller.cpp src/components/LcioEventAlgo.cpp src/components/LcioEventOutput.cpp src/components/MarlinProcessorWrapper.cpp diff --git a/k4MarlinWrapper/examples/clicRec_e4h_input.py b/k4MarlinWrapper/examples/clicRec_e4h_input.py index ee9e7f42..1b24ef14 100644 --- a/k4MarlinWrapper/examples/clicRec_e4h_input.py +++ b/k4MarlinWrapper/examples/clicRec_e4h_input.py @@ -21,11 +21,15 @@ from Gaudi.Configuration import DEBUG, WARNING -from Configurables import MarlinProcessorWrapper from k4MarlinWrapper.parseConstants import parseConstants -from Configurables import Lcio2EDM4hepTool, EDM4hep2LcioTool -from Configurables import k4DataSvc, PodioInput, PodioOutput, EventDataSvc +from Configurables import ( + MarlinProcessorWrapper, + Lcio2EDM4hepTool, + EDM4hep2LcioTool, + EventDataSvc, + MetadataSvc, +) from k4FWCore import ApplicationMgr, IOSvc from k4FWCore.parseArgs import parser @@ -39,12 +43,6 @@ parseConstants(CONSTANTS) -parser.add_argument( - "--no-iosvc", - action="store_true", - default=False, - help="Use k4DataSvc instead of IOSvc", -) parser.add_argument( "--rec-output", default="Output_REC_e4h_input.slcio", help="Output file name for the REC file" ) @@ -54,27 +52,15 @@ parser.add_argument( "--gaudi-output", default="my_output.root", help="Output file name for the Gaudi file" ) - args = parser.parse_known_args()[0] -if not args.no_iosvc: - evtsvc = EventDataSvc("EventDataSvc") - iosvc = IOSvc() - iosvc.Input = os.path.join( - "$TEST_DIR/inputFiles/", os.environ.get("INPUTFILE", "ttbar_edm4hep_frame.root") - ) - iosvc.Output = args.gaudi_output - iosvc.outputCommands = ["keep *", "drop RefinedVertexJets_PID_RefinedVertex"] -else: - evtsvc = k4DataSvc("EventDataSvc") - evtsvc.input = os.path.join( - "$TEST_DIR/inputFiles/", os.environ.get("INPUTFILE", "ttbar_edm4hep_frame.root") - ) - - inp = PodioInput("InputReader") - inp.OutputLevel = DEBUG - - out = PodioOutput("PodioOutput", filename=args.gaudi_output) - out.outputCommands = ["keep *", "drop RefinedVertexJets_PID_RefinedVertex"] + +evtsvc = EventDataSvc("EventDataSvc") +iosvc = IOSvc() +iosvc.Input = os.path.join( + "$TEST_DIR/inputFiles/", os.environ.get("INPUTFILE", "ttbar_edm4hep_frame.root") +) +iosvc.Output = args.gaudi_output +iosvc.outputCommands = ["keep *", "drop RefinedVertexJets_PID_RefinedVertex"] MyAIDAProcessor = MarlinProcessorWrapper("MyAIDAProcessor") MyAIDAProcessor.OutputLevel = WARNING @@ -2504,7 +2490,6 @@ algList.append(Output_REC) algList.append(Output_DST) -if args.no_iosvc: - algList = [inp] + algList + [out] - -ApplicationMgr(TopAlg=algList, EvtSel="NONE", EvtMax=3, ExtSvc=[evtsvc], OutputLevel=WARNING) +ApplicationMgr( + TopAlg=algList, EvtSel="NONE", EvtMax=3, ExtSvc=[evtsvc, MetadataSvc()], OutputLevel=WARNING +) diff --git a/k4MarlinWrapper/k4MarlinWrapper/converters/EDM4hep2Lcio.h b/k4MarlinWrapper/k4MarlinWrapper/converters/EDM4hep2Lcio.h index f5052163..e70b04fd 100644 --- a/k4MarlinWrapper/k4MarlinWrapper/converters/EDM4hep2Lcio.h +++ b/k4MarlinWrapper/k4MarlinWrapper/converters/EDM4hep2Lcio.h @@ -31,9 +31,7 @@ #include #include -class PodioDataSvc; class IDataProviderSvc; -class IMetadataSvc; template using ObjMapT = k4EDM4hep2LcioConv::VecMapT; @@ -66,11 +64,8 @@ class EDM4hep2LcioTool : public AlgTool, virtual public IEDMConverter { Gaudi::Property> m_collNames{this, "collNameMapping", {}}; Gaudi::Property m_convertAll{this, "convertAll", true}; - PodioDataSvc* m_podioDataSvc; // EventDataSvc that is used together with IOSvc ServiceHandle m_eventDataSvc; - // Metadata service from k4FWCore that is used together with IOSvc - SmartIF m_metadataSvc; /// A (caching) "map" of original to new collection names that will be populated /// during the first conversion std::vector> m_collsToConvert{}; @@ -121,8 +116,6 @@ class EDM4hep2LcioTool : public AlgTool, virtual public IEDMConverter { std::vector& pidCollections, std::vector& dQdxCollections); - const podio::Frame& getEDM4hepEvent() const; - /// Get an EDM4hep collection by name, consulting either the podio based data /// svc or the IOSvc podio::CollectionBase* getEDM4hepCollection(const std::string& name, bool allowToFail = false) const; diff --git a/k4MarlinWrapper/k4MarlinWrapper/converters/Lcio2EDM4hep.h b/k4MarlinWrapper/k4MarlinWrapper/converters/Lcio2EDM4hep.h index 3b6b24d8..0fdfa1a9 100644 --- a/k4MarlinWrapper/k4MarlinWrapper/converters/Lcio2EDM4hep.h +++ b/k4MarlinWrapper/k4MarlinWrapper/converters/Lcio2EDM4hep.h @@ -22,8 +22,6 @@ #include #include -#include "k4FWCore/IMetadataSvc.h" - #include "k4MarlinWrapper/converters/IEDMConverter.h" #include @@ -40,13 +38,9 @@ namespace EVENT { class LCCollection; } -class PodioDataSvc; - class Lcio2EDM4hepTool : public AlgTool, virtual public IEDMConverter { public: Lcio2EDM4hepTool(const std::string& type, const std::string& name, const IInterface* parent); - StatusCode initialize() final; - StatusCode finalize() final; // ********************************** // - Convert all collections indicated in Tool parameters @@ -61,8 +55,8 @@ class Lcio2EDM4hepTool : public AlgTool, virtual public IEDMConverter { Gaudi::Property m_convertAll{this, "convertAll", true}; ServiceHandle m_eventDataSvc; - SmartIF m_metadataSvc; - PodioDataSvc* m_podioDataSvc; + + std::map m_cellIDEncodings{}; // ********************************** // Check if a collection was already registered to skip it diff --git a/k4MarlinWrapper/src/components/CellIDEncodingFiller.cpp b/k4MarlinWrapper/src/components/CellIDEncodingFiller.cpp new file mode 100644 index 00000000..b9cc6248 --- /dev/null +++ b/k4MarlinWrapper/src/components/CellIDEncodingFiller.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019-2024 Key4hep-Project. + * + * This file is part of Key4hep. + * See https://key4hep.github.io/key4hep-doc/ for further info. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include +#include + +class CellIDEncodingFiller final : public Gaudi::Algorithm { +public: + CellIDEncodingFiller(const std::string& name, ISvcLocator* pSL) : Gaudi::Algorithm(name, pSL) {} + + StatusCode initialize() override { + if (Gaudi::Algorithm::initialize().isFailure()) { + return StatusCode::FAILURE; + } + for (const auto& [collName, encoding] : m_cellIDEncodings) { + debug() << "Putting CellID encoding for collection '" << collName << "': " << encoding << endmsg; + k4FWCore::putCellIDEncoding(collName, encoding, this); + } + return StatusCode::SUCCESS; + } + + StatusCode execute(const EventContext&) const override { return StatusCode::SUCCESS; } + +private: + Gaudi::Property> m_cellIDEncodings{ + this, "CellIDEncodings", {}, "Map of collection names to CellID encoding strings"}; +}; + +DECLARE_COMPONENT(CellIDEncodingFiller) diff --git a/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp b/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp index d130337d..2d05b87b 100644 --- a/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp +++ b/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp @@ -26,15 +26,12 @@ #include "edm4hep/utils/ParticleIDUtils.h" #include "k4FWCore/DataHandle.h" -#include "k4FWCore/FunctionalUtils.h" -#include "k4FWCore/MetaDataHandle.h" -#include "k4FWCore/PodioDataSvc.h" +#include #include "GaudiKernel/AnyDataWrapper.h" #include "GaudiKernel/IDataManagerSvc.h" #include "GaudiKernel/IDataProviderSvc.h" -#include #include DECLARE_COMPONENT(EDM4hep2LcioTool); @@ -69,16 +66,6 @@ StatusCode EDM4hep2LcioTool::initialize() { return StatusCode::FAILURE; } - m_podioDataSvc = dynamic_cast(m_eventDataSvc.get()); - - if (!m_podioDataSvc) { - m_metadataSvc = service("MetadataSvc", false); - if (!m_metadataSvc) { - error() << "Could not retrieve MetadataSvc" << endmsg; - return StatusCode::FAILURE; - } - } - return AlgTool::initialize(); } @@ -107,11 +94,10 @@ void EDM4hep2LcioTool::convertTrackerHits(TrackerHitMap& trackerhits_vec, const this}; const auto trackerhits_coll = trackerhits_handle.get(); - k4FWCore::MetaDataHandle cellIDStrHandle{trackerhits_handle, edm4hep::labels::CellIDEncoding, - Gaudi::DataHandle::Reader}; + const auto cellIDencoding = k4FWCore::getCellIDEncoding(trackerhits_handle.objKey(), this); + debug() << "Retrieved CellID encoding: " << cellIDencoding.value_or("") << endmsg; - auto conv_trackerhits = - EDM4hep2LCIOConv::convertTrackerHits(trackerhits_coll, cellIDStrHandle.get(""), trackerhits_vec); + auto conv_trackerhits = EDM4hep2LCIOConv::convertTrackerHits(trackerhits_coll, cellIDencoding, trackerhits_vec); // Add all trackerhits to event lcio_event->addCollection(conv_trackerhits.release(), lcio_coll_name); @@ -129,11 +115,10 @@ void EDM4hep2LcioTool::convertTrackerHitPlanes(TrackerHitPlaneMap& trackerhits_v this}; const auto trackerhits_coll = trackerhits_handle.get(); - k4FWCore::MetaDataHandle cellIDStrHandle{trackerhits_handle, edm4hep::labels::CellIDEncoding, - Gaudi::DataHandle::Reader}; + const auto cellIDencoding = k4FWCore::getCellIDEncoding(trackerhits_handle.objKey(), this); + debug() << "Retrieved CellID encoding: " << cellIDencoding.value_or("") << endmsg; - auto conv_trackerhits = - EDM4hep2LCIOConv::convertTrackerHitPlanes(trackerhits_coll, cellIDStrHandle.get(""), trackerhits_vec); + auto conv_trackerhits = EDM4hep2LCIOConv::convertTrackerHitPlanes(trackerhits_coll, cellIDencoding, trackerhits_vec); // Add all trackerhits to event lcio_event->addCollection(conv_trackerhits.release(), lcio_coll_name); @@ -148,12 +133,11 @@ void EDM4hep2LcioTool::convertSimTrackerHits(SimTrackerHitMap& simtrackerhits_ve this}; const auto simtrackerhits_coll = simtrackerhits_handle.get(); - k4FWCore::MetaDataHandle cellIDHandle{simtrackerhits_handle, edm4hep::labels::CellIDEncoding, - Gaudi::DataHandle::Reader}; - const auto cellIDstr = cellIDHandle.get(); + const auto cellIDencoding = k4FWCore::getCellIDEncoding(simtrackerhits_handle.objKey(), this); + debug() << "Retrieved CellID encoding: " << cellIDencoding.value_or("") << endmsg; auto conv_simtrackerhits = - EDM4hep2LCIOConv::convertSimTrackerHits(simtrackerhits_coll, cellIDstr, simtrackerhits_vec); + EDM4hep2LCIOConv::convertSimTrackerHits(simtrackerhits_coll, cellIDencoding, simtrackerhits_vec); // Add all simtrackerhits to event lcio_event->addCollection(conv_simtrackerhits.release(), lcio_coll_name); @@ -168,11 +152,10 @@ void EDM4hep2LcioTool::convertCalorimeterHits(CaloHitMap& calo_hits_vec, const s this}; const auto calohit_coll = calohit_handle.get(); - k4FWCore::MetaDataHandle cellIDHandle{calohit_handle, edm4hep::labels::CellIDEncoding, - Gaudi::DataHandle::Reader}; - const auto cellIDstr = cellIDHandle.get(); + const auto cellIDencoding = k4FWCore::getCellIDEncoding(calohit_handle.objKey(), this); + debug() << "Retrieved CellID encoding: " << cellIDencoding.value_or("") << endmsg; - auto conv_calohits = EDM4hep2LCIOConv::convertCalorimeterHits(calohit_coll, cellIDstr, calo_hits_vec); + auto conv_calohits = EDM4hep2LCIOConv::convertCalorimeterHits(calohit_coll, cellIDencoding, calo_hits_vec); // Add all Calorimeter Hits to event lcio_event->addCollection(conv_calohits.release(), lcio_coll_name); @@ -202,12 +185,12 @@ void EDM4hep2LcioTool::convertSimCalorimeterHits(SimCaloHitMap& sim_calo_hits_ve Gaudi::DataHandle::Reader, this}; const auto simcalohit_coll = sim_calohit_handle.get(); - k4FWCore::MetaDataHandle cellIDHandle{sim_calohit_handle, edm4hep::labels::CellIDEncoding, - Gaudi::DataHandle::Reader}; - const auto cellIDstr = cellIDHandle.get(); + const auto cellIDencoding = k4FWCore::getCellIDEncoding(sim_calohit_handle.objKey(), this); + debug() << "Retrieved CellID encoding: " << cellIDencoding.value_or("") << endmsg; // TODO mcparticles_vdc - auto conv_simcalohits = EDM4hep2LCIOConv::convertSimCalorimeterHits(simcalohit_coll, cellIDstr, sim_calo_hits_vec); + auto conv_simcalohits = + EDM4hep2LCIOConv::convertSimCalorimeterHits(simcalohit_coll, cellIDencoding, sim_calo_hits_vec); // Add all Sim Calorimeter Hits to event lcio_event->addCollection(conv_simcalohits.release(), lcio_coll_name); @@ -337,7 +320,6 @@ void EDM4hep2LcioTool::convertAdd(const std::string& e4h_coll_name, const std::s lcio::LCEventImpl* lcio_event, CollectionPairMappings& collection_pairs, std::vector& pidCollections, std::vector& dQdxCollections) { - const auto& metadata = m_podioDataSvc->getMetaDataFrame(); const auto collPtr = getEDM4hepCollection(e4h_coll_name); const auto fulltype = collPtr->getValueTypeName(); @@ -370,13 +352,7 @@ void EDM4hep2LcioTool::convertAdd(const std::string& e4h_coll_name, const std::s } else if (fulltype == "edm4hep::EventHeader") { convertEventHeader(e4h_coll_name, lcio_event); } else if (fulltype == "edm4hep::ParticleID") { - std::optional pidInfo; - if (m_podioDataSvc) { - pidInfo = edm4hep::utils::PIDHandler::getAlgoInfo(metadata, e4h_coll_name); - } else { - pidInfo = m_metadataSvc->get(e4h_coll_name); - } - + const auto pidInfo = k4FWCore::getParameter(e4h_coll_name, this); pidCollections.emplace_back(e4h_coll_name, static_cast(collPtr), pidInfo); } else if (fulltype == "edm4hep::RecDqDx") { dQdxCollections.emplace_back(e4h_coll_name, static_cast(collPtr)); @@ -395,45 +371,10 @@ void EDM4hep2LcioTool::convertAdd(const std::string& e4h_coll_name, const std::s } } -const podio::Frame& EDM4hep2LcioTool::getEDM4hepEvent() const { - debug() << "Retrieving EDM4hep event (Frame)" << endmsg; - if (m_podioDataSvc) { - debug() << "Getting it from PodioDataSvc" << endmsg; - return m_podioDataSvc->getEventFrame(); - } else { - debug() << "Trying to get it from TES" << endmsg; - DataObject* p; - StatusCode code = m_eventDataSvc->retrieveObject("/Event" + k4FWCore::frameLocation, p); - if (code.isSuccess()) { - auto* frame = dynamic_cast*>(p); - return frame->getData(); - } - } - - // We can do this because the following assumptions are true: - // - We only end up here if we are using the IOSvc and we are NOT reading - // EDM4hep data. Otherwise the Reader will be scheduled as FIRST algorithm, - // most importantly BEFORE any of the wrapped Marlin processors to which - // this converter is attached. - // - The empty Frame we introduce into the TES here does not interfere with - // the Writer for EDM4hep output (which is always scheduled last), as that - // will simply get this Frame instead of creating an empty one itself - // - There are no scheduling issues / race conditions, since the - // MarlinProcessorWrapper algorithm is not re-entrant and can thus not be - // run in parallel - debug() << "Could not retrieve Frame from expected location. Registering a new empty Frame into the TES" << endmsg; - auto tmp = new AnyDataWrapper(podio::Frame()); - if (m_eventDataSvc->registerObject("/Event" + k4FWCore::frameLocation, tmp).isFailure()) { - error() << "Could not retrieve Frame from expected location in TES and could not register a new one" << endmsg; - throw std::runtime_error("Could not get EDM4hep event (Frame) for conversions"); - } - return tmp->getData(); -} - // Parse property parameters and convert the indicated collections. // Use the collection names in the parameters to read and write them StatusCode EDM4hep2LcioTool::convertCollections(lcio::LCEventImpl* lcio_event) { - const auto& edmEvent = getEDM4hepEvent(); + const auto& edmEvent = getEDM4hepEvent(this); // use m_collsToConvert to detect whether we run the first time and cache the // results as we can assume that all the events have the same contents if (m_collsToConvert.empty()) { @@ -451,16 +392,6 @@ StatusCode EDM4hep2LcioTool::convertCollections(lcio::LCEventImpl* lcio_event) { if (m_convertAll) { info() << "Converting all collections from EDM4hep to LCIO" << endmsg; - if (m_podioDataSvc) { - // If we have the PodioDataSvc get the collections available from frame - for (const auto& name : edmEvent.getAvailableCollections()) { - const auto& [_, inserted] = collNameMapping.emplace(name, name); - debug() << fmt::format("Adding '{}' from Frame to conversion? {}", name, inserted) << endmsg; - } - } - // Always check the contents of the TES because algorithms that do not use - // the PodioDataSvc (e.g. all Functional ones) go to the TES directly and - // the PodioDataSvc Frame doesn't now about them. std::optional> idToNameOpt(std::move(m_idToName)); for (const auto& name : getAvailableCollectionsFromStore(this, idToNameOpt)) { const auto& [_, inserted] = collNameMapping.emplace(name, name); @@ -500,21 +431,16 @@ StatusCode EDM4hep2LcioTool::convertCollections(lcio::LCEventImpl* lcio_event) { for (const auto& pidCollMeta : pidCollections) { auto algoId = attachParticleIDMetaData(lcio_event, edmEvent, pidCollMeta); if (!algoId.has_value()) { - // Now go over the collections that have been produced in a functional algorithm (if any) - bool found = false; - if (!m_podioDataSvc) { - const auto id = (*pidCollMeta.coll)[0].getParticle().id().collectionID; - if (auto it = m_idToName.find(id); it != m_idToName.end()) { - auto name = it->second; - if (pidCollMeta.metadata.has_value()) { - UTIL::PIDHandler pidHandler(lcio_event->getCollection(name)); - algoId = - pidHandler.addAlgorithm(pidCollMeta.metadata.value().algoName, pidCollMeta.metadata.value().paramNames); - found = true; - } + // Check if we can figure out the collection from information on the TES + const auto id = (*pidCollMeta.coll)[0].getParticle().id().collectionID; + if (auto it = m_idToName.find(id); it != m_idToName.end()) { + auto name = it->second; + if (pidCollMeta.metadata.has_value()) { + UTIL::PIDHandler pidHandler(lcio_event->getCollection(name)); + algoId = + pidHandler.addAlgorithm(pidCollMeta.metadata.value().algoName, pidCollMeta.metadata.value().paramNames); } - } - if (!found) { + } else { warning() << "Could not determine algorithm type for ParticleID collection " << pidCollMeta.name << " for setting consistent metadata" << endmsg; } diff --git a/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp b/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp index baf18dc8..5d40b3a8 100644 --- a/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp +++ b/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp @@ -27,10 +27,8 @@ #include -#include #include -#include -#include +#include #include "GaudiKernel/AnyDataWrapper.h" @@ -50,33 +48,19 @@ Lcio2EDM4hepTool::Lcio2EDM4hepTool(const std::string& type, const std::string& n } } -StatusCode Lcio2EDM4hepTool::initialize() { - m_podioDataSvc = dynamic_cast(m_eventDataSvc.get()); - - if (!m_podioDataSvc) { - m_metadataSvc = service("MetadataSvc", false); - if (!m_metadataSvc) { - error() << "Could not retrieve MetadataSvc" << endmsg; - return StatusCode::FAILURE; - } +StatusCode Lcio2EDM4hepTool::finalize() { + for (const auto& [key, value] : m_cellIDEncodings) { + k4FWCore::putParameter(key, value, this); } - - return AlgTool::initialize(); + return AlgTool::finalize(); } -StatusCode Lcio2EDM4hepTool::finalize() { return AlgTool::finalize(); } - // ********************************** // Check if a collection was already registered to skip it // ********************************** bool Lcio2EDM4hepTool::collectionExist(const std::string& collection_name) { - std::vector collections; - if (m_podioDataSvc) { - collections = m_podioDataSvc->getEventFrame().getAvailableCollections(); - } else { - std::optional> dummy = std::nullopt; - collections = getAvailableCollectionsFromStore(this, dummy, true); - } + std::optional> dummy = std::nullopt; + const auto collections = getAvailableCollectionsFromStore(this, dummy, true); if (std::find(collections.begin(), collections.end(), collection_name) != collections.end()) { debug() << "Collection named " << collection_name << " already registered, skipping conversion." << endmsg; return true; @@ -92,9 +76,8 @@ void Lcio2EDM4hepTool::registerCollection( return; } - auto wrapper = new DataWrapper(); - wrapper->setData(e4hColl.release()); - + debug() << fmt::format("Adding collection '{}' () to the TES", name, e4hColl->getTypeName()) << endmsg; + auto wrapper = new AnyDataWrapper>(std::move(e4hColl)); // No need to check for pre-existing collections, since we only ever end up // here if that is not the case auto sc = m_eventDataSvc->registerObject("/Event", "/" + std::string(name), wrapper); @@ -110,16 +93,7 @@ void Lcio2EDM4hepTool::registerCollection( for (auto& elem : string_keys) { if (elem == edm4hep::labels::CellIDEncoding) { const auto& lcio_coll_cellid_str = lcioColl->getParameters().getStringVal(lcio::LCIO::CellIDEncoding); - if (m_podioDataSvc) { - auto& mdFrame = m_podioDataSvc->getMetaDataFrame(); - mdFrame.putParameter(podio::collMetadataParamName(name, edm4hep::labels::CellIDEncoding), - lcio_coll_cellid_str); - } else { - k4FWCore::putParameter(podio::collMetadataParamName(name, edm4hep::labels::CellIDEncoding), - lcio_coll_cellid_str); - } - debug() << "Storing CellIDEncoding " << podio::collMetadataParamName(name, edm4hep::labels::CellIDEncoding) - << " value: " << lcio_coll_cellid_str << endmsg; + m_cellIDEncodings[podio::collMetadataParamName(name, edm4hep::labels::CellIDEncoding)] = lcio_coll_cellid_str; } else { // TODO: figure out where this actually needs to go } @@ -149,21 +123,8 @@ struct ObjectMappings { } // namespace StatusCode Lcio2EDM4hepTool::convertCollections(lcio::LCEventImpl* the_event) { - // Convert event parameters - if (m_podioDataSvc) { - LCIO2EDM4hepConv::convertObjectParameters(the_event, m_podioDataSvc->m_eventframe); - } else { - DataObject* p; - StatusCode code = m_eventDataSvc->retrieveObject("/Event" + k4FWCore::frameLocation, p); - if (code.isSuccess()) { - auto* frameWrapper = dynamic_cast*>(p); - LCIO2EDM4hepConv::convertObjectParameters(the_event, frameWrapper->getData()); - } else { - warning() << "Could not retrieve the event frame; event parameters will not be converted. This is a known " - "limitation when running with IOSvc without an input file." - << endmsg; - } - } + auto& event = getEDM4hepEvent(this); + LCIO2EDM4hepConv::convertObjectParameters(the_event, event); // Convert Event Header outside the collections loop if (!collectionExist(edm4hep::labels::EventHeader)) { @@ -237,16 +198,8 @@ StatusCode Lcio2EDM4hepTool::convertCollections(lcio::LCEventImpl* the_event) { } } - // Set the ParticleID meta information - if (m_podioDataSvc) { - auto& metadataFrame = m_podioDataSvc->getMetaDataFrame(); - for (const auto& [collName, pidInfo] : pidInfos) { - edm4hep::utils::PIDHandler::setAlgoInfo(metadataFrame, collName, pidInfo); - } - } else { - for (const auto& [collName, pidInfo] : pidInfos) { - m_metadataSvc->put(collName, pidInfo); - } + for (const auto& [collName, pidInfo] : pidInfos) { + k4FWCore::putParameter(collName, pidInfo, this); } auto& globalObjMap = getGlobalObjectMap(this); diff --git a/k4MarlinWrapper/src/components/StoreUtils.cpp b/k4MarlinWrapper/src/components/StoreUtils.cpp index bedb5bc4..4aa176a2 100644 --- a/k4MarlinWrapper/src/components/StoreUtils.cpp +++ b/k4MarlinWrapper/src/components/StoreUtils.cpp @@ -119,3 +119,34 @@ k4MarlinWrapper::GlobalConvertedObjectsMap& getGlobalObjectMap(AlgTool* thisTool auto globalObjMapWrapper = static_cast*>(obj); return globalObjMapWrapper->getData(); } + +podio::Frame& getEDM4hepEvent(AlgTool* thisTool) { + thisTool->debug() << "Retrieving EDM4hep event (Frame) from TES" << endmsg; + DataObject* p; + StatusCode code = thisTool->evtSvc()->retrieveObject("/Event" + k4FWCore::frameLocation, p); + if (code.isSuccess()) { + auto* frame = dynamic_cast*>(p); + return frame->getData(); + } + + // We can do this because the following assumptions are true: + // - We only end up here if we are using the IOSvc and we are NOT reading + // EDM4hep data. Otherwise the Reader will be scheduled as FIRST algorithm, + // most importantly BEFORE any of the wrapped Marlin processors to which + // this converter is attached. + // - The empty Frame we introduce into the TES here does not interfere with + // the Writer for EDM4hep output (which is always scheduled last), as that + // will simply get this Frame instead of creating an empty one itself + // - There are no scheduling issues / race conditions, since the + // MarlinProcessorWrapper algorithm is not re-entrant and can thus not be + // run in parallel + thisTool->debug() << "Could not retrieve Frame from expected location. Registering a new empty Frame into the TES" + << endmsg; + auto tmp = new AnyDataWrapper(podio::Frame()); + if (thisTool->evtSvc()->registerObject("/Event" + k4FWCore::frameLocation, tmp).isFailure()) { + thisTool->error() << "Could not retrieve Frame from expected location in TES and could not register a new one" + << endmsg; + throw std::runtime_error("Could not get EDM4hep event (Frame) for conversions"); + } + return tmp->getData(); +} diff --git a/k4MarlinWrapper/src/components/StoreUtils.h b/k4MarlinWrapper/src/components/StoreUtils.h index 0d60c85f..3f25f3f4 100644 --- a/k4MarlinWrapper/src/components/StoreUtils.h +++ b/k4MarlinWrapper/src/components/StoreUtils.h @@ -23,6 +23,10 @@ #include #include +namespace podio { +class Frame; +} + // This functionality is used in the Writer from k4FWCore and is reimplemented // here with some additions to make it useful for converting both from EDM4hep // to LCIO and vice versa @@ -31,3 +35,6 @@ std::vector getAvailableCollectionsFromStore(const AlgTool* thisCla bool returnFrameCollections = false); k4MarlinWrapper::GlobalConvertedObjectsMap& getGlobalObjectMap(AlgTool* thisTool); + +/// Get the Frame that underpins the current event from the TES +podio::Frame& getEDM4hepEvent(AlgTool* thisTool); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 05d13e07..4b130f78 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,6 +19,7 @@ limitations under the License. gaudi_add_module(GaudiTestAlgorithms SOURCES + src/CellIDEncodingChecker.cc src/MCRecoLinkChecker.cc src/MCRecoLinkCheckerFunctional.cc src/PseudoRecoAlgorithm.cc @@ -89,9 +90,7 @@ set_tests_properties( skip_events PASS_REGULAR_EXPRESSION "Output has expected number of events") # Test clicReconstruction with EDM4hep input and output -ExternalData_Add_Test( marlinwrapper_tests NAME clicRec_edm4hep_input COMMAND bash -c "${CMAKE_CURRENT_SOURCE_DIR}/scripts/clicRec_e4h_input.sh DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} --no-iosvc") -ExternalData_Add_Test( marlinwrapper_tests NAME clicRec_edm4hep_input_iosvc COMMAND bash -c "${CMAKE_CURRENT_SOURCE_DIR}/scripts/clicRec_e4h_input.sh DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} --iosvc") -add_test( clicRec_edm4hep_input_compare_output bash -c "diff <(podio-dump CLICPerformance/clicConfig/my_output.root | grep -v 'input file:') <(podio-dump CLICPerformance/clicConfig/my_output_iosvc.root | grep -v 'input file:')") +ExternalData_Add_Test( marlinwrapper_tests NAME clicRec_edm4hep_input COMMAND bash -c "${CMAKE_CURRENT_SOURCE_DIR}/scripts/clicRec_e4h_input.sh DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root}") # Run clicReconstruction sequence with LCIO input and output, no converters, with inter-event parallelism ExternalData_Add_Test( marlinwrapper_tests NAME clicRec_lcio_mt COMMAND bash -c "${CMAKE_CURRENT_SOURCE_DIR}/scripts/clicRec_lcio_mt.sh DATA{${PROJECT_SOURCE_DIR}/tests/input_files/testSimulation.slcio}") @@ -103,40 +102,27 @@ add_test( clic_geo_test ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/geoTest_ # multiple processors ExternalData_Add_Test( marlinwrapper_tests NAME global_converter_maps - COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_global_converter_maps.py --no-iosvc --EventDataSvc.input DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} -) -ExternalData_Add_Test( marlinwrapper_tests - NAME global_converter_maps_algorithm - COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_global_converter_maps.py --no-iosvc --use-gaudi-algorithm --OutputWriter.filename=global_converter_maps_algorithm.root --EventDataSvc.input DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} -) - -ExternalData_Add_Test( marlinwrapper_tests - NAME global_converter_maps_iosvc COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_global_converter_maps.py --IOSvc.Input DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} ) ExternalData_Add_Test( marlinwrapper_tests - NAME global_converter_maps_iosvc_functional + NAME global_converter_maps_functional COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_global_converter_maps.py --use-functional-checker --IOSvc.Input DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} ) ExternalData_Add_Test( marlinwrapper_tests - NAME global_converter_maps_iosvc_algorithm - COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_global_converter_maps.py --use-gaudi-algorithm --IOSvc.Input DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} --IOSvc.Output=global_converter_maps_iosvc_algorithm.root + NAME global_converter_maps_algorithm + COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_global_converter_maps.py --use-gaudi-algorithm --IOSvc.Input DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} --IOSvc.Output=global_converter_maps_algorithm.root ) ExternalData_Add_Test( marlinwrapper_tests - NAME global_converter_maps_iosvc_algorithm_functional - COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_global_converter_maps.py --use-gaudi-algorithm --use-functional-checker --IOSvc.Input DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} --IOSvc.Output=global_converter_maps_iosvc_algorithm_functional.root + NAME global_converter_maps_algorithm_functional + COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_global_converter_maps.py --use-gaudi-algorithm --use-functional-checker --IOSvc.Input DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} --IOSvc.Output=global_converter_maps_algorithm_functional.root ) ExternalData_Add_Test( marlinwrapper_tests NAME link_conversion_edm4hep_to_lcio - COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_link_conversion_edm4hep.py --no-iosvc --inputfile DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} -) -ExternalData_Add_Test( marlinwrapper_tests - NAME link_conversion_edm4hep_to_lcio_iosvc COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_link_conversion_edm4hep.py --inputfile DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} ) ExternalData_Add_Test( marlinwrapper_tests - NAME link_conversion_edm4hep_to_lcio_iosvc_gaudi_algorithm + NAME link_conversion_edm4hep_to_lcio_gaudi_algorithm COMMAND ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_link_conversion_edm4hep.py --use-gaudi-algorithm --inputfile DATA{${PROJECT_SOURCE_DIR}/tests/input_files/ttbar_20240223_edm4hep.root} ) @@ -196,6 +182,8 @@ set_tests_properties( DEPENDS partial_edm4hep_to_lcio ) +add_test( cellid_encoding_filler ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/test_cellid_encoding_filler.py ) + add_test( event_header_conversion bash -c "k4run ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/createEventHeader.py && anajob test.slcio | grep 'EVENT: 42'" ) add_test(event_header_conversion_no_header ${K4RUN} ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/createEventHeader.py --no-event-header ) @@ -207,17 +195,11 @@ set_tests_properties(event_header_conversion_no_header ExternalData_Add_Target(marlinwrapper_tests) set_tests_properties( - clicRec clicRec_lcio_mt clicRec_edm4hep_input clicRec_edm4hep_input_iosvc + clicRec clicRec_lcio_mt clicRec_edm4hep_input PROPERTIES DEPENDS CLICPerformance_setup ) -set_tests_properties( - clicRec_edm4hep_input_compare_output - PROPERTIES - DEPENDS "clicRec_edm4hep_input;clicRec_edm4hep_input_iosvc" -) - # For LD_LIBRARY_PATH # ${PROJECT_BINARY_DIR} # The files .components and .confdb are here diff --git a/tests/gaudi_opts/test_cellid_encoding_filler.py b/tests/gaudi_opts/test_cellid_encoding_filler.py new file mode 100644 index 00000000..060f7462 --- /dev/null +++ b/tests/gaudi_opts/test_cellid_encoding_filler.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2019-2024 Key4hep-Project. +# +# This file is part of Key4hep. +# See https://key4hep.github.io/key4hep-doc/ for further info. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from Gaudi.Configuration import INFO + +from Configurables import EventDataSvc, MetadataSvc +from Configurables import CellIDEncodingFiller, CellIDEncodingChecker + +from k4FWCore import ApplicationMgr + +TEST_ENCODINGS = { + "SiVertexBarrelCollection": "system:5,side:0-0,layer:1-4,module:1-8,sensor:0-3", + "SiTrackerBarrelCollection": "system:5,side:0-0,layer:1-5,module:1-12,sensor:0-1", +} + +filler = CellIDEncodingFiller("CellIDEncodingFiller") +filler.CellIDEncodings = TEST_ENCODINGS + +checker = CellIDEncodingChecker("CellIDEncodingChecker") +checker.ExpectedEncodings = TEST_ENCODINGS + +ApplicationMgr( + TopAlg=[filler, checker], + EvtSel="NONE", + EvtMax=1, + ExtSvc=[EventDataSvc(), MetadataSvc()], + OutputLevel=INFO, +) diff --git a/tests/gaudi_opts/test_global_converter_maps.py b/tests/gaudi_opts/test_global_converter_maps.py index a72540a8..83c1d1a7 100644 --- a/tests/gaudi_opts/test_global_converter_maps.py +++ b/tests/gaudi_opts/test_global_converter_maps.py @@ -19,13 +19,10 @@ # -from Gaudi.Configuration import INFO, DEBUG +from Gaudi.Configuration import DEBUG from Configurables import ( - PodioInput, - PodioOutput, MarlinProcessorWrapper, - k4DataSvc, Lcio2EDM4hepTool, EDM4hep2LcioTool, MCRecoLinkChecker, @@ -38,12 +35,6 @@ from k4FWCore.parseArgs import parser -parser.add_argument( - "--no-iosvc", - action="store_true", - default=False, - help="Use k4DataSvc instead of IOSvc", -) parser.add_argument( "--use-functional-checker", action="store_true", default=False, help="Use functional checker" ) @@ -59,24 +50,14 @@ if args.use_functional_checker: from Configurables import MCRecoLinkCheckerFunctional as MCRecoLinkChecker -if not args.no_iosvc: - evtsvc = EventDataSvc("EventDataSvc") -else: - evtsvc = k4DataSvc("EventDataSvc") - -if not args.no_iosvc: - iosvc = IOSvc() - iosvc.CollectionNames = ["EventHeader", "MCParticles"] - if not args.use_functional_checker: - iosvc.Output = "global_converter_maps_iosvc.root" - else: - iosvc.Output = "global_converter_maps_iosvc_functional.root" +evtsvc = EventDataSvc("EventDataSvc") + +iosvc = IOSvc() +iosvc.CollectionNames = ["EventHeader", "MCParticles"] +if not args.use_functional_checker: + iosvc.Output = "global_converter_maps_iosvc.root" else: - podioInput = PodioInput("InputReader") - podioInput.collections = ["EventHeader", "MCParticles"] - podioInput.OutputLevel = INFO - podioOutput = PodioOutput("OutputWriter") - podioOutput.filename = "global_converter_maps.root" + iosvc.Output = "global_converter_maps_iosvc_functional.root" if args.use_gaudi_algorithm: PseudoRecoAlg = PseudoRecoAlgorithm( @@ -125,7 +106,4 @@ mcLinkChecker, ] -if args.no_iosvc: - algList = [podioInput] + algList + [podioOutput] - ApplicationMgr(TopAlg=algList, EvtSel="NONE", EvtMax=1, ExtSvc=[evtsvc], OutputLevel=DEBUG) diff --git a/tests/gaudi_opts/test_link_conversion_edm4hep.py b/tests/gaudi_opts/test_link_conversion_edm4hep.py index a95b0aae..7acae7a2 100644 --- a/tests/gaudi_opts/test_link_conversion_edm4hep.py +++ b/tests/gaudi_opts/test_link_conversion_edm4hep.py @@ -21,8 +21,6 @@ from Gaudi.Configuration import INFO, DEBUG from Configurables import ( - PodioInput, - k4DataSvc, PseudoRecoAlgorithm, PseudoRecoFunctional, TrivialMCRecoLinker, @@ -36,12 +34,6 @@ from k4FWCore.parseArgs import parser parser.add_argument("--inputfile", help="Input file") -parser.add_argument( - "--no-iosvc", - action="store_true", - default=False, - help="Use k4DataSvc instead of IOSvc", -) parser.add_argument( "--use-gaudi-algorithm", action="store_true", @@ -50,17 +42,10 @@ ) args = parser.parse_known_args()[0] -if not args.no_iosvc: - evtsvc = EventDataSvc("EventDataSvc") - iosvc = IOSvc() - iosvc.Input = args.inputfile - iosvc.CollectionNames = ["EventHeader", "MCParticles"] -else: - evtsvc = k4DataSvc("EventDataSvc") - evtsvc.input = args.inputfile - podioInput = PodioInput("InputReader") - podioInput.collections = ["EventHeader", "MCParticles"] - podioInput.OutputLevel = INFO +evtsvc = EventDataSvc("EventDataSvc") +iosvc = IOSvc() +iosvc.Input = args.inputfile +iosvc.CollectionNames = ["EventHeader", "MCParticles"] if args.use_gaudi_algorithm: @@ -124,9 +109,6 @@ algList = [PseudoRecoAlg, MCRecoLinker, MarlinMCLinkChecker, AnotherLinkChecker] -if args.no_iosvc: - algList = [podioInput] + algList - ApplicationMgr( TopAlg=algList, ExtSvc=[evtsvc], diff --git a/tests/scripts/clicRec_e4h_input.sh b/tests/scripts/clicRec_e4h_input.sh index 02b9c885..83293143 100755 --- a/tests/scripts/clicRec_e4h_input.sh +++ b/tests/scripts/clicRec_e4h_input.sh @@ -23,22 +23,14 @@ set -eu cd CLICPerformance/clicConfig -if [ "$2" = "--iosvc" ]; then - iosvc="_iosvc" - echo "Running with IO service" - file_arg="--IOSvc.Input=$1" -elif [ "$2" = "--no-iosvc" ]; then - iosvc="" - echo "Running without IO service" - file_arg="--no-iosvc --EventDataSvc.input=$1" -else - echo "Wrong argument $2" - return 1 -fi -k4run $EXAMPLE_DIR/clicRec_e4h_input.py ${file_arg} --rec-output Output_REC_e4h_input$iosvc.slcio --dst-output Output_DST_e4h_input$iosvc.slcio --gaudi-output my_output$iosvc.root +k4run $EXAMPLE_DIR/clicRec_e4h_input.py \ + --IOSvc.Input=${1} \ + --rec-output Output_REC_e4h_input.slcio \ + --dst-output Output_DST_e4h_input.slcio \ + --gaudi-output my_output.root input_num_events=$(python $TEST_DIR/python/root_num_events.py $1) -output_num_events=$(python $TEST_DIR/python/root_num_events.py my_output$iosvc.root) +output_num_events=$(python $TEST_DIR/python/root_num_events.py my_output.root) # First check do we have the same number of events in input and output if [ "$input_num_events" != "$output_num_events" ]; then @@ -48,14 +40,14 @@ fi # Second check: contents (at least superficially) # Exclude the file name since it is different when using the IOSvc -echo "Comparing contents of Output_REC_e4h_input$iosvc.slcio" -if ! diff -I "Output_REC_e4h_input.*\.slcio" <(anajob Output_REC_e4h_input$iosvc.slcio) $TEST_DIR/inputFiles/anajob_Output_REC.expected; then +echo "Comparing contents of Output_REC_e4h_input.slcio" +if ! diff <(anajob Output_REC_e4h_input.slcio) $TEST_DIR/inputFiles/anajob_Output_REC.expected; then echo "File contents of REC slcio file are not as expected" exit 1 fi -echo "Comparing contents of Output_DST_e4h_input$iosvc.slcio" -if ! diff -I "Output_DST_e4h_input.*\.slcio" <(anajob Output_DST_e4h_input$iosvc.slcio) $TEST_DIR/inputFiles/anajob_Output_DST.expected; then +echo "Comparing contents of Output_DST_e4h_input.slcio" +if ! diff <(anajob Output_DST_e4h_input.slcio) $TEST_DIR/inputFiles/anajob_Output_DST.expected; then echo "File contents of DST slcio file are not as expected" exit 1 fi diff --git a/tests/src/CellIDEncodingChecker.cc b/tests/src/CellIDEncodingChecker.cc new file mode 100644 index 00000000..3709a6d6 --- /dev/null +++ b/tests/src/CellIDEncodingChecker.cc @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019-2024 Key4hep-Project. + * + * This file is part of Key4hep. + * See https://key4hep.github.io/key4hep-doc/ for further info. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include +#include + +class CellIDEncodingChecker final : public Gaudi::Algorithm { +public: + CellIDEncodingChecker(const std::string& name, ISvcLocator* pSL) : Gaudi::Algorithm(name, pSL) {} + + StatusCode initialize() override { + if (Gaudi::Algorithm::initialize().isFailure()) { + return StatusCode::FAILURE; + } + for (const auto& [collName, expectedEncoding] : m_expectedEncodings) { + const auto encoding = k4FWCore::getCellIDEncoding(collName, this); + if (!encoding.has_value()) { + error() << "No CellID encoding found for collection '" << collName << "'" << endmsg; + return StatusCode::FAILURE; + } + if (encoding.value() != expectedEncoding) { + error() << "CellID encoding mismatch for collection '" << collName << "': expected '" << expectedEncoding + << "', got '" << encoding.value() << "'" << endmsg; + return StatusCode::FAILURE; + } + info() << "CellID encoding for '" << collName << "' is correct: '" << encoding.value() << "'" << endmsg; + } + return StatusCode::SUCCESS; + } + + StatusCode execute(const EventContext&) const override { return StatusCode::SUCCESS; } + +private: + Gaudi::Property> m_expectedEncodings{ + this, "ExpectedEncodings", {}, "Map of collection names to expected CellID encoding strings"}; +}; + +DECLARE_COMPONENT(CellIDEncodingChecker)