From 9b6949492a52fd8db97ba043499359d504d78485 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila <37295697+m-fila@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:42:09 +0200 Subject: [PATCH] Fix accessing input file metadata in MetadataSvc (#223) --- k4FWCore/components/MetadataSvc.cpp | 7 +- k4FWCore/components/MetadataSvc.h | 6 +- k4FWCore/components/Writer.cpp | 5 +- k4FWCore/include/k4FWCore/IMetadataSvc.h | 26 ++++--- test/k4FWCoreTest/CMakeLists.txt | 5 +- test/k4FWCoreTest/options/CheckOutputFiles.py | 71 ++++++++++++------- .../options/ExampleFunctionalMetadataRead.py | 39 ++++++++++ ...ampleFunctionalMetadataReadOldAlgorithm.py | 39 ++++++++++ 8 files changed, 156 insertions(+), 42 deletions(-) create mode 100644 test/k4FWCoreTest/options/ExampleFunctionalMetadataRead.py create mode 100644 test/k4FWCoreTest/options/ExampleFunctionalMetadataReadOldAlgorithm.py diff --git a/k4FWCore/components/MetadataSvc.cpp b/k4FWCore/components/MetadataSvc.cpp index a0da7928..d87f0845 100644 --- a/k4FWCore/components/MetadataSvc.cpp +++ b/k4FWCore/components/MetadataSvc.cpp @@ -38,14 +38,13 @@ StatusCode MetadataSvc::initialize() { error() << "Unable to locate the EventDataSvc" << endmsg; return StatusCode::FAILURE; } - - m_frame = std::make_unique(); - return StatusCode::SUCCESS; } StatusCode MetadataSvc::finalize() { return Service::finalize(); } -void MetadataSvc::setFrame(podio::Frame&& fr) { m_frame = std::make_unique(std::move(fr)); } +const podio::Frame* MetadataSvc::getFrame() const { return m_frame.get(); } +podio::Frame* MetadataSvc::getFrame() { return m_frame.get(); } +void MetadataSvc::setFrame(podio::Frame&& frame) { m_frame = std::make_unique(std::move(frame)); } DECLARE_COMPONENT(MetadataSvc) diff --git a/k4FWCore/components/MetadataSvc.h b/k4FWCore/components/MetadataSvc.h index 42cc281b..13a8703f 100644 --- a/k4FWCore/components/MetadataSvc.h +++ b/k4FWCore/components/MetadataSvc.h @@ -26,6 +26,8 @@ #include "k4FWCore/IMetadataSvc.h" +#include + class MetadataSvc : public extends { using extends::extends; @@ -38,7 +40,9 @@ class MetadataSvc : public extends { std::unique_ptr m_frame; - void setFrame(podio::Frame&& frame) override; + const podio::Frame* getFrame() const override; + podio::Frame* getFrame() override; + void setFrame(podio::Frame&& frame) override; }; #endif diff --git a/k4FWCore/components/Writer.cpp b/k4FWCore/components/Writer.cpp index f4c9fb29..a613be8e 100644 --- a/k4FWCore/components/Writer.cpp +++ b/k4FWCore/components/Writer.cpp @@ -34,6 +34,7 @@ #include #include +#include class Writer final : public Gaudi::Functional::Consumer { public: @@ -121,8 +122,8 @@ class Writer final : public Gaudi::Functional::ConsumergetWriter()->writeFrame(config_metadata_frame, "configuration_metadata"); - if (m_metadataSvc->m_frame) { - iosvc->getWriter()->writeFrame(*std::move(m_metadataSvc->m_frame), podio::Category::Metadata); + if (const auto* metadata_frame = m_metadataSvc->getFrame(); metadata_frame) { + iosvc->getWriter()->writeFrame(*metadata_frame, podio::Category::Metadata); } iosvc->deleteWriter(); diff --git a/k4FWCore/include/k4FWCore/IMetadataSvc.h b/k4FWCore/include/k4FWCore/IMetadataSvc.h index 0144608e..6066a301 100644 --- a/k4FWCore/include/k4FWCore/IMetadataSvc.h +++ b/k4FWCore/include/k4FWCore/IMetadataSvc.h @@ -19,26 +19,36 @@ #ifndef FWCORE_IMETADATASERVICE_H #define FWCORE_IMETADATASERVICE_H -#include - #include "GaudiKernel/IInterface.h" #include "podio/Frame.h" class IMetadataSvc : virtual public IInterface { + friend class Writer; + public: DeclareInterfaceID(IMetadataSvc, 1, 0); - std::unique_ptr m_frame; + virtual void setFrame(podio::Frame&& frame) = 0; - virtual void setFrame(podio::Frame&& fr) = 0; template void put(const std::string& name, const T& obj) { - if (!m_frame) { - m_frame = std::make_unique(); + if (!getFrame()) { + setFrame(podio::Frame{}); + } + getFrame()->putParameter(name, obj); + } + + template std::optional get(const std::string& name) const { + const auto* frame = getFrame(); + if (!frame) { + return std::nullopt; } - m_frame->putParameter(name, obj); + return frame->getParameter(name); } - template std::optional get(const std::string& name) { return m_frame->getParameter(name); } + +protected: + virtual podio::Frame* getFrame() = 0; + virtual const podio::Frame* getFrame() const = 0; }; #endif diff --git a/test/k4FWCoreTest/CMakeLists.txt b/test/k4FWCoreTest/CMakeLists.txt index 972fafcc..a884dfa5 100644 --- a/test/k4FWCoreTest/CMakeLists.txt +++ b/test/k4FWCoreTest/CMakeLists.txt @@ -136,15 +136,18 @@ add_test_with_env(FunctionalTransformerHist options/ExampleFunctionalTransformer add_test_with_env(FunctionalCollectionMerger options/ExampleFunctionalCollectionMerger.py) add_test_with_env(FunctionalFilterFile options/ExampleFunctionalFilterFile.py) add_test_with_env(FunctionalMetadata options/ExampleFunctionalMetadata.py) +add_test_with_env(FunctionalMetadataRead options/ExampleFunctionalMetadataRead.py PROPERTIES DEPENDS FunctionalMetadata) add_test_with_env(FunctionalMetadataOldAlgorithm options/ExampleFunctionalMetadataOldAlgorithm.py) add_test_with_env(createEventHeaderConcurrent options/createEventHeaderConcurrent.py) +add_test_with_env(FunctionalMetadataReadOldAlgorithm options/ExampleFunctionalMetadataReadOldAlgorithm.py PROPERTIES DEPENDS ExampleFunctionalMetadataOldAlgorithm) add_test_with_env(FunctionalWrongImport options/ExampleFunctionalWrongImport.py) set_tests_properties(FunctionalWrongImport PROPERTIES PASS_REGULAR_EXPRESSION "ImportError: Importing ApplicationMgr or IOSvc from Configurables is not allowed.") add_test_with_env(FunctionalReadNthEvent options/ExampleFunctionalReadNthEvent.py) add_test(NAME FunctionalCheckFiles COMMAND python3 ${CMAKE_CURRENT_LIST_DIR}/options/CheckOutputFiles.py) -set_tests_properties(FunctionalCheckFiles PROPERTIES DEPENDS "FunctionalFile;FunctionalMTFile;FunctionalMultipleFile;FunctionalOutputCommands;FunctionalProducerAbsolutePath;FunctionalTransformerRuntimeEmpty;FunctionalMix;FunctionalMixIOSvc;FunctionalTransformerHist;FunctionalCollectionMerger;FunctionalFilterFile;FunctionalMetadata;FunctionalMetadataOldAlgorithm;createEventHeaderConcurrent;FunctionalReadNthEvent") + +set_tests_properties(FunctionalCheckFiles PROPERTIES DEPENDS "FunctionalFile;FunctionalMTFile;FunctionalMultipleFile;FunctionalOutputCommands;FunctionalProducerAbsolutePath;FunctionalTransformerRuntimeEmpty;FunctionalMix;FunctionalMixIOSvc;FunctionalTransformerHist;FunctionalCollectionMerger;FunctionalFilterFile;FunctionalMetadata;FunctionalMetadataRead;FunctionalMetadataOldAlgorithm;FunctionalMetadataReadOldAlgorithm;createEventHeaderConcurrent;FunctionalReadNthEvent") # Do this after checking the files not to overwrite them add_test_with_env(FunctionalFile_toolong options/ExampleFunctionalFile.py -n 999 PROPERTIES DEPENDS FunctionalCheckFiles PASS_REGULAR_EXPRESSION diff --git a/test/k4FWCoreTest/options/CheckOutputFiles.py b/test/k4FWCoreTest/options/CheckOutputFiles.py index 45b3b0a0..227ac3f0 100644 --- a/test/k4FWCoreTest/options/CheckOutputFiles.py +++ b/test/k4FWCoreTest/options/CheckOutputFiles.py @@ -58,6 +58,17 @@ def check_events(filename, number): raise RuntimeError("Number of events does not match expected number") +def check_metadata(filename, expected_metadata): + print(f'Checking file "{filename}" for metadata') + podio_reader = podio.root_io.Reader(filename) + metadata = podio_reader.get("metadata")[0] + for key, value in expected_metadata.items(): + if (metaval := metadata.get_parameter(key)) != value: + raise RuntimeError( + f"Metadata parameter {key} does not match the expected value, got {metaval} but expected {value}" + ) + + check_collections("functional_transformer.root", ["MCParticles", "NewMCParticles"]) check_collections( "functional_transformer_multiple.root", @@ -161,33 +172,41 @@ def check_events(filename, number): check_collections("functional_metadata.root", ["MCParticles"]) -reader = podio.root_io.Reader("functional_metadata.root") -metadata = reader.get("metadata")[0] -for key, value in zip( - [ - "NumberOfParticles", - "ParticleTime", - "PDGValues", - "MetadataString", - "FinalizeMetadataInt", - ], - [3, 1.5, [1, 2, 3, 4], "hello", 10], -): - if metadata.get_parameter(key) != value: - raise RuntimeError( - f"Metadata parameter {key} does not match the expected value, got {metadata.get_parameter(key)} but expected {value}" - ) +check_metadata( + "functional_metadata.root", + { + "NumberOfParticles": 3, + "ParticleTime": 1.5, + "PDGValues": [1, 2, 3, 4], + "MetadataString": "hello", + "FinalizeMetadataInt": 10, + }, +) -reader = podio.root_io.Reader("functional_metadata_old_algorithm.root") -metadata = reader.get("metadata")[0] -for key, value in zip( - ["SimTrackerHits__CellIDEncoding"], - ["M:3,S-1:3,I:9,J:9,K-1:6"], -): - if metadata.get_parameter(key) != value: - raise RuntimeError( - f"Metadata parameter {key} does not match the expected value, got {metadata.get_parameter(key)} but expected {value}" - ) +check_metadata( + "functional_metadata_propagate.root", + { + "NumberOfParticles": 3, + "ParticleTime": 1.5, + "PDGValues": [1, 2, 3, 4], + "MetadataString": "hello", + "FinalizeMetadataInt": 10, + }, +) + +check_metadata( + "functional_metadata_old_algorithm.root", + { + "SimTrackerHits__CellIDEncoding": "M:3,S-1:3,I:9,J:9,K-1:6", + }, +) + +check_metadata( + "functional_metadata_old_algorithm_propagate.root", + { + "SimTrackerHits__CellIDEncoding": "M:3,S-1:3,I:9,J:9,K-1:6", + }, +) reader = podio.root_io.Reader("eventHeaderConcurrent.root") events = reader.get("events") diff --git a/test/k4FWCoreTest/options/ExampleFunctionalMetadataRead.py b/test/k4FWCoreTest/options/ExampleFunctionalMetadataRead.py new file mode 100644 index 00000000..a5c34f93 --- /dev/null +++ b/test/k4FWCoreTest/options/ExampleFunctionalMetadataRead.py @@ -0,0 +1,39 @@ +# +# Copyright (c) 2014-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. +# + +# This is an example accessing matadata read from input file using MetadataSvc + +from Gaudi.Configuration import INFO +from Configurables import ExampleFunctionalMetadataConsumer +from k4FWCore import ApplicationMgr, IOSvc +from Configurables import EventDataSvc + +iosvc = IOSvc() +iosvc.Input = "functional_metadata.root" +iosvc.Output = "functional_metadata_propagate.root" + +consumer = ExampleFunctionalMetadataConsumer("Consumer", InputCollection=["MCParticles"]) + +ApplicationMgr( + TopAlg=[consumer], + EvtSel="NONE", + EvtMax=10, + ExtSvc=[EventDataSvc("EventDataSvc")], + OutputLevel=INFO, +) diff --git a/test/k4FWCoreTest/options/ExampleFunctionalMetadataReadOldAlgorithm.py b/test/k4FWCoreTest/options/ExampleFunctionalMetadataReadOldAlgorithm.py new file mode 100644 index 00000000..5bbcc418 --- /dev/null +++ b/test/k4FWCoreTest/options/ExampleFunctionalMetadataReadOldAlgorithm.py @@ -0,0 +1,39 @@ +# +# Copyright (c) 2014-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. +# + +# This is an example accessing matadata read from input file using MetaDataHandle + +from Gaudi.Configuration import INFO +from Configurables import k4FWCoreTest_cellID_reader +from k4FWCore import ApplicationMgr, IOSvc + +iosvc = IOSvc() +iosvc.Input = "functional_metadata_old_algorithm.root" +iosvc.Output = "functional_metadata_old_algorithm_propagate.root" + +consumer = k4FWCoreTest_cellID_reader() + +ApplicationMgr( + TopAlg=[consumer], + EvtSel="NONE", + EvtMax=10, + ExtSvc=[], + OutputLevel=INFO, + StopOnSignal=True, +)