From 74a14564652d84300b031b107fc1ea86727f2277 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Thu, 19 Dec 2024 20:35:14 +0100 Subject: [PATCH 01/14] Add overloads for handling ParticleIDMeta --- k4FWCore/CMakeLists.txt | 2 +- k4FWCore/include/k4FWCore/IMetadataSvc.h | 34 +++++++++++++++++++----- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/k4FWCore/CMakeLists.txt b/k4FWCore/CMakeLists.txt index e9b8bc03..6797bb6a 100644 --- a/k4FWCore/CMakeLists.txt +++ b/k4FWCore/CMakeLists.txt @@ -31,7 +31,7 @@ gaudi_install(PYTHON) gaudi_add_library(k4FWCore SOURCES src/PodioDataSvc.cpp src/KeepDropSwitch.cpp - LINK Gaudi::GaudiKernel podio::podioIO ROOT::Core ROOT::RIO ROOT::Tree + LINK Gaudi::GaudiKernel podio::podioIO ROOT::Core ROOT::RIO ROOT::Tree EDM4HEP::utils ) target_include_directories(k4FWCore PUBLIC $ diff --git a/k4FWCore/include/k4FWCore/IMetadataSvc.h b/k4FWCore/include/k4FWCore/IMetadataSvc.h index 65748d6e..897581eb 100644 --- a/k4FWCore/include/k4FWCore/IMetadataSvc.h +++ b/k4FWCore/include/k4FWCore/IMetadataSvc.h @@ -21,6 +21,8 @@ #include "GaudiKernel/IInterface.h" +#include "edm4hep/utils/ParticleIDUtils.h" + #include "podio/Frame.h" class IMetadataSvc : virtual public IInterface { @@ -31,12 +33,7 @@ class IMetadataSvc : virtual public IInterface { virtual void setFrame(podio::Frame frame) = 0; - template void put(const std::string& name, const T& obj) { - if (!getFrame()) { - setFrame(podio::Frame{}); - } - getFrame()->putParameter(name, obj); - } + template void put(const std::string& name, const T& obj) { getFrameForWrite()->putParameter(name, obj); } template std::optional get(const std::string& name) const { const auto* frame = getFrame(); @@ -49,6 +46,31 @@ class IMetadataSvc : virtual public IInterface { protected: virtual podio::Frame* getFrame() = 0; virtual const podio::Frame* getFrame() const = 0; + +private: + podio::Frame* getFrameForWrite() { + if (!getFrame()) { + setFrame(podio::Frame()); + } + return getFrame(); + } }; +template <> +inline void IMetadataSvc::put(const std::string& collName, + const edm4hep::utils::ParticleIDMeta& pidMetaInfo) { + edm4hep::utils::PIDHandler::setAlgoInfo(*getFrameForWrite(), collName, pidMetaInfo); +} + +template <> +inline std::optional IMetadataSvc::get( + const std::string& collName) const { + const auto* frame = getFrame(); + if (!frame) { + return std::nullopt; + } + + return edm4hep::utils::PIDHandler::getAlgoInfo(*frame, collName); +} + #endif From 255c581bf3f8e777bcc9fbe0a9913d6ddea066f3 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Thu, 19 Dec 2024 20:35:38 +0100 Subject: [PATCH 02/14] Add a producer and a consumer for PID with metadata --- .../components/ExampleParticleIDConsumer.cpp | 154 ++++++++++++++++++ .../components/ExampleParticleIDProducer.cpp | 71 ++++++++ 2 files changed, 225 insertions(+) create mode 100644 test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp create mode 100644 test/k4FWCoreTest/src/components/ExampleParticleIDProducer.cpp diff --git a/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp b/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp new file mode 100644 index 00000000..712741f8 --- /dev/null +++ b/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp @@ -0,0 +1,154 @@ +/* + * 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. + */ + +#include +#include "k4FWCore/Consumer.h" +#include "k4FWCore/MetadataUtils.h" + +#include "edm4hep/ParticleIDCollection.h" +#include "edm4hep/utils/ParticleIDUtils.h" + +#include + +#include "fmt/format.h" +#include "fmt/ranges.h" + +#include +#include +#include + +struct ExampleParticleIDConsumer final + : k4FWCore::Consumer { + ExampleParticleIDConsumer(const std::string& name, ISvcLocator* svcLoc) + : Consumer(name, svcLoc, + {KeyValues("ParticleIDCollection1", {"PIDs1"}), KeyValues("ParticleIDCollection2", {"PIDs2"}), + KeyValues("RecoParticleCollection", {"recos"})}) {} + + bool checkAlgoMetadata(const edm4hep::utils::ParticleIDMeta& pidMeta, const Gaudi::Property& algoName, + const Gaudi::Property>& paramNames) const { + if (pidMeta.algoName != algoName) { + fatal() << fmt::format( + "The PID algorithm name from metadata does not match the expected one from the properties: " + "(expected {}, actual {})", + algoName.value(), pidMeta.algoName) + << endmsg; + return false; + } + + if (!std::ranges::equal(pidMeta.paramNames, paramNames)) { + fatal() << fmt::format( + "The PID parameter names retrieved from metadata does not match the expected ones from the " + "properties: (expected {}, actual {})", + paramNames.value(), pidMeta.paramNames) + << endmsg; + return false; + } + + return true; + } + + void checkPIDForAlgo(const edm4hep::utils::PIDHandler& pidHandler, const edm4hep::ReconstructedParticle& reco, + const edm4hep::utils::ParticleIDMeta& pidMeta, const int paramIndex) const { + auto maybePID = pidHandler.getPID(reco, pidMeta.algoType()); + if (!maybePID) { + throw std::runtime_error( + std::format("Could net retrieve the {} PID object for reco particle {}", pidMeta.algoName, reco.id().index)); + } + auto pid = maybePID.value(); + auto paramVal = pid.getParameters()[paramIndex]; + + // As set in the producer + if (paramVal != paramIndex * 0.5f) { + throw std::runtime_error( + fmt::format("Could not retrieve the correct parameter value for param {} (expected {}, actual {})", + pidMeta.paramNames[paramIndex], paramIndex * 0.5f, paramVal)); + } + } + + StatusCode initialize() final { + m_pidMeta1 = + k4FWCore::getParameter(inputLocations("ParticleIDCollection1")[0]).value(); + + m_pidMeta2 = + k4FWCore::getParameter(inputLocations("ParticleIDCollection2")[0]).value(); + + if (!checkAlgoMetadata(m_pidMeta1, m_pidAlgoName1, m_pidParamNames1) || + !checkAlgoMetadata(m_pidMeta2, m_pidAlgoName2, m_pidParamNames2)) { + return StatusCode::FAILURE; + } + + m_paramIndex1 = edm4hep::utils::getParamIndex(m_pidMeta1, m_paramOfInterest1.value()).value_or(-1); + m_paramIndex2 = edm4hep::utils::getParamIndex(m_pidMeta2, m_paramOfInterest2.value()).value_or(-1); + if (m_paramIndex1 < 0 || m_paramIndex2 < 0) { + error() << fmt::format("Could not get a parameter index for {} (got {}) or {} (got {})", + m_paramOfInterest1.value(), m_paramIndex1, m_paramOfInterest2.value(), m_paramIndex2) + << std::endl; + } + + return StatusCode::SUCCESS; + } + + void operator()(const edm4hep::ParticleIDCollection& pidColl1, const edm4hep::ParticleIDCollection& pidColl2, + const edm4hep::ReconstructedParticleCollection& recos) const { + auto pidHandler = edm4hep::utils::PIDHandler::from(pidColl1, pidColl2); + pidHandler.addMetaInfos(m_pidMeta1, m_pidMeta2); + + for (const auto r : recos) { + auto pids = pidHandler.getPIDs(r); + if (pids.size() != 2) { + throw std::runtime_error( + std::format("Could not get 2 ParticleID objects related to reco particle {}", r.id().index)); + } + + checkPIDForAlgo(pidHandler, r, m_pidMeta1, m_paramIndex1); + checkPIDForAlgo(pidHandler, r, m_pidMeta2, m_paramIndex2); + } + } + +private: + edm4hep::utils::ParticleIDMeta m_pidMeta1{}; + edm4hep::utils::ParticleIDMeta m_pidMeta2{}; + + int m_paramIndex1{}; + int m_paramIndex2{}; + + Gaudi::Property m_pidAlgoName1{ + this, "PIDAlgoName1", "fancyPID", + "The name of the first ParticleID algorithm that should be used for the metadata"}; + Gaudi::Property> m_pidParamNames1{ + this, + "PIDParamNames1", + {"p1", "p2", "p3"}, + "The names of the parameters of the first PID algorithm that will be stored into metadata"}; + Gaudi::Property m_paramOfInterest1{this, "ParamName1", "p1", + "The name of the parameter that should be checked"}; + Gaudi::Property m_pidAlgoName2{ + this, "PIDAlgoName2", "fancyPID", + "The name of the second ParticleID algorithm that should be used for the metadata"}; + Gaudi::Property> m_pidParamNames2{ + this, + "PIDParamNames2", + {"p1", "p2", "p3"}, + "The names of the parameters of the second PID algorithm that will be stored into metadata"}; + Gaudi::Property m_paramOfInterest2{this, "ParamName2", "p2", + "The name of the parameter that should be checked"}; +}; + +DECLARE_COMPONENT(ExampleParticleIDConsumer); diff --git a/test/k4FWCoreTest/src/components/ExampleParticleIDProducer.cpp b/test/k4FWCoreTest/src/components/ExampleParticleIDProducer.cpp new file mode 100644 index 00000000..fc102349 --- /dev/null +++ b/test/k4FWCoreTest/src/components/ExampleParticleIDProducer.cpp @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#include "k4FWCore/MetadataUtils.h" +#include "k4FWCore/Transformer.h" + +#include "edm4hep/ParticleIDCollection.h" +#include "edm4hep/ReconstructedParticleCollection.h" +#include "edm4hep/utils/ParticleIDUtils.h" + +#include "Gaudi/Property.h" + +#include + +struct ExampleParticleIDProducer final + : k4FWCore::Transformer { + ExampleParticleIDProducer(const std::string& name, ISvcLocator* svcLoc) + : Transformer(name, svcLoc, {KeyValues("InputCollection", {"RecoParticles"})}, + KeyValues("ParticleIDCollection", {"reco_PIDs"})) {} + + StatusCode initialize() final { + m_pidMeta = {m_pidAlgoName, m_pidParamNames}; + std::string collname = outputLocations("ParticleIDCollection")[0]; + k4FWCore::putParameter(collname, m_pidMeta); + return StatusCode::SUCCESS; + } + + edm4hep::ParticleIDCollection operator()(const edm4hep::ReconstructedParticleCollection& recos) const { + auto pidColl = edm4hep::ParticleIDCollection{}; + for (const auto r : recos) { + auto pid = pidColl.create(); + pid.setAlgorithmType(m_pidMeta.algoType()); + pid.setPDG(r.getPDG() - 10); + pid.setParticle(r); + for (size_t i = 0; i < m_pidMeta.paramNames.size(); ++i) { + pid.addToParameters(i * 0.5f); + } + } + + return pidColl; + } + +private: + Gaudi::Property m_pidAlgoName{ + this, "PIDAlgoName", "fancyPID", "The name of the ParticleID algorithm that should be used for the metadata"}; + Gaudi::Property> m_pidParamNames{ + this, + "PIDParamNames", + {"p1", "p2", "p3"}, + "The names of the parameters of the PID algorithm that will be stored into metadata"}; + + edm4hep::utils::ParticleIDMeta m_pidMeta{}; +}; + +DECLARE_COMPONENT(ExampleParticleIDProducer); From 0f660eb70eef2ddcacbfe513c83041d5a9a4a4d0 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Fri, 20 Dec 2024 15:05:44 +0100 Subject: [PATCH 03/14] Add a test sequence for PID with metadata --- test/k4FWCoreTest/CMakeLists.txt | 2 + .../options/ExampleParticleIDMetadata.py | 80 +++++++++++++++++++ .../ExampleFunctionalProducerMultiple.cpp | 27 ++++--- 3 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 test/k4FWCoreTest/options/ExampleParticleIDMetadata.py diff --git a/test/k4FWCoreTest/CMakeLists.txt b/test/k4FWCoreTest/CMakeLists.txt index 4302c583..7fccc596 100644 --- a/test/k4FWCoreTest/CMakeLists.txt +++ b/test/k4FWCoreTest/CMakeLists.txt @@ -195,6 +195,8 @@ add_test_with_env(FunctionalProducerRNTuple options/ExampleFunctionalProducerRNT add_test_with_env(FunctionalTTreeToRNTuple options/ExampleFunctionalTTreeToRNTuple.py PROPERTIES FIXTURES_REQUIRED ProducerFile ADD_TO_CHECK_FILES) add_test_with_env(GaudiFunctional options/ExampleGaudiFunctional.py PROPERTIES FIXTURES_REQUIRED ProducerFile ADD_TO_CHECK_FILES) +add_test_with_env(ParticleIDMetadataFramework options/ExampleParticleIDMetadata.py) + # The following is done to make the tests work without installing the files in # the installation directory. The k4FWCore in the build directory is populated by diff --git a/test/k4FWCoreTest/options/ExampleParticleIDMetadata.py b/test/k4FWCoreTest/options/ExampleParticleIDMetadata.py new file mode 100644 index 00000000..a7a22ffb --- /dev/null +++ b/test/k4FWCoreTest/options/ExampleParticleIDMetadata.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# +# 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. +# + +"""Example showcasing how to use ParticleID related metadata""" + +from Gaudi.Configuration import INFO +from Configurables import ( + ExampleParticleIDProducer, + ExampleParticleIDConsumer, + ExampleFunctionalProducerMultiple, + EventDataSvc, +) +from k4FWCore import ApplicationMgr, IOSvc + +# NOTE: If you are not using the IOSvc (e.g. because you don't need I/O), make +# sure to add the MetadataSvc to the ExtSvc as that is necessary to store / +# retrieve the metadata for ParticleIDs +iosvc = IOSvc() +iosvc.Output = "example_with_particleids.root" +iosvc.outputCommands = ["drop *", "keep RecoParticles*"] + +reco_producer = ExampleFunctionalProducerMultiple( + "RecoProducer", OutputCollectionRecoParticles=["RecoParticles"] +) + +pid_producer1 = ExampleParticleIDProducer( + "PIDProducer1", + InputCollection=["RecoParticles"], + ParticleIDCollection=["RecoParticlesPIDs_1"], + PIDAlgoName="PIDAlgo1", + PIDParamNames=["single_param"], +) + +pid_producer2 = ExampleParticleIDProducer( + "PIDProducer2", + InputCollection=["RecoParticles"], + ParticleIDCollection=["RecoParticlesPIDs_2"], + PIDAlgoName="PIDAlgo2", + PIDParamNames=["param_1", "param_2", "param_3"], +) + +pid_consumer = ExampleParticleIDConsumer( + "PIDConsumer", + RecoParticleCollection=reco_producer.OutputCollectionRecoParticles, + # From first producer + ParticleIDCollection1=pid_producer1.ParticleIDCollection, + PIDAlgoName1=pid_producer1.PIDAlgoName, + PIDParamNames1=pid_producer1.PIDParamNames, + ParamName1="single_param", + # From second producer + ParticleIDCollection2=pid_producer2.ParticleIDCollection, + PIDAlgoName2=pid_producer2.PIDAlgoName, + PIDParamNames2=pid_producer2.PIDParamNames, + ParamName2="param_2", +) + +ApplicationMgr( + TopAlg=[reco_producer, pid_producer1, pid_producer2, pid_consumer], + EvtSel="NONE", + EvtMax=10, + ExtSvc=[EventDataSvc("EventDataSvc")], + OutputLevel=INFO, +) diff --git a/test/k4FWCoreTest/src/components/ExampleFunctionalProducerMultiple.cpp b/test/k4FWCoreTest/src/components/ExampleFunctionalProducerMultiple.cpp index 96a6dcb2..a56ec7bc 100644 --- a/test/k4FWCoreTest/src/components/ExampleFunctionalProducerMultiple.cpp +++ b/test/k4FWCoreTest/src/components/ExampleFunctionalProducerMultiple.cpp @@ -22,6 +22,7 @@ #include "k4FWCore/Producer.h" #include "edm4hep/MCParticleCollection.h" +#include "edm4hep/ReconstructedParticleCollection.h" #include "edm4hep/SimTrackerHitCollection.h" #include "edm4hep/TrackCollection.h" #include "edm4hep/TrackerHit3DCollection.h" @@ -33,19 +34,21 @@ using retType = std::tuple, edm4hep::MCParticleCollection, edm4hep::MCParticleCollection, - edm4hep::SimTrackerHitCollection, edm4hep::TrackerHit3DCollection, edm4hep::TrackCollection>; + edm4hep::SimTrackerHitCollection, edm4hep::TrackerHit3DCollection, edm4hep::TrackCollection, + edm4hep::ReconstructedParticleCollection>; struct ExampleFunctionalProducerMultiple final : k4FWCore::Producer { // The pairs in KeyValue can be changed from python and they correspond // to the names of the output collections ExampleFunctionalProducerMultiple(const std::string& name, ISvcLocator* svcLoc) - : Producer(name, svcLoc, {}, - {KeyValues("OutputCollectionFloat", {"VectorFloat"}), - KeyValues("OutputCollectionParticles1", {"MCParticles1"}), - KeyValues("OutputCollectionParticles2", {"MCParticles2"}), - KeyValues("OutputCollectionSimTrackerHits", {"SimTrackerHits"}), - KeyValues("OutputCollectionTrackerHits", {"TrackerHits"}), - KeyValues("OutputCollectionTracks", {"Tracks"})}) {} + : Producer( + name, svcLoc, {}, + {KeyValues("OutputCollectionFloat", {"VectorFloat"}), + KeyValues("OutputCollectionParticles1", {"MCParticles1"}), + KeyValues("OutputCollectionParticles2", {"MCParticles2"}), + KeyValues("OutputCollectionSimTrackerHits", {"SimTrackerHits"}), + KeyValues("OutputCollectionTrackerHits", {"TrackerHits"}), KeyValues("OutputCollectionTracks", {"Tracks"}), + KeyValues("OutputCollectionRecoParticles", {"RecoParticles"})}) {} // This is the function that will be called to produce the data retType operator()() const override { @@ -84,8 +87,14 @@ struct ExampleFunctionalProducerMultiple final : k4FWCore::Producer { track.addToTrackerHits(trackerHit); track.addToTracks(track2); + auto recos = edm4hep::ReconstructedParticleCollection(); + for (int i = 1; i < 5; ++i) { + auto reco = recos.create(); + reco.setPDG(i); + } + return std::make_tuple(std::move(floatVector), std::move(particles), edm4hep::MCParticleCollection(), - std::move(simTrackerHits), std::move(trackerHits), std::move(tracks)); + std::move(simTrackerHits), std::move(trackerHits), std::move(tracks), std::move(recos)); } private: From 8b45d8677e9ea2c2887afe6b61ff52deee3811d4 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Thu, 16 Jan 2025 14:07:01 +0100 Subject: [PATCH 04/14] Fix a few minor slips --- .../src/components/ExampleParticleIDConsumer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp b/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp index 712741f8..665f256e 100644 --- a/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp +++ b/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp @@ -69,7 +69,7 @@ struct ExampleParticleIDConsumer final auto maybePID = pidHandler.getPID(reco, pidMeta.algoType()); if (!maybePID) { throw std::runtime_error( - std::format("Could net retrieve the {} PID object for reco particle {}", pidMeta.algoName, reco.id().index)); + fmt::format("Could net retrieve the {} PID object for reco particle {}", pidMeta.algoName, reco.id().index)); } auto pid = maybePID.value(); auto paramVal = pid.getParameters()[paramIndex]; @@ -99,7 +99,7 @@ struct ExampleParticleIDConsumer final if (m_paramIndex1 < 0 || m_paramIndex2 < 0) { error() << fmt::format("Could not get a parameter index for {} (got {}) or {} (got {})", m_paramOfInterest1.value(), m_paramIndex1, m_paramOfInterest2.value(), m_paramIndex2) - << std::endl; + << endmsg; } return StatusCode::SUCCESS; @@ -114,7 +114,7 @@ struct ExampleParticleIDConsumer final auto pids = pidHandler.getPIDs(r); if (pids.size() != 2) { throw std::runtime_error( - std::format("Could not get 2 ParticleID objects related to reco particle {}", r.id().index)); + fmt::format("Could not get 2 ParticleID objects related to reco particle {}", r.id().index)); } checkPIDForAlgo(pidHandler, r, m_pidMeta1, m_paramIndex1); From c3cb331dc547b3e9edd8e163c29c877f4ad34314 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Thu, 16 Jan 2025 14:07:45 +0100 Subject: [PATCH 05/14] Add a check for checking the standalone output --- test/k4FWCoreTest/CMakeLists.txt | 7 ++ .../src/check_ParticleIDOutputs.cpp | 85 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp diff --git a/test/k4FWCoreTest/CMakeLists.txt b/test/k4FWCoreTest/CMakeLists.txt index 7fccc596..f2ad1d14 100644 --- a/test/k4FWCoreTest/CMakeLists.txt +++ b/test/k4FWCoreTest/CMakeLists.txt @@ -206,3 +206,10 @@ add_test_with_env(ParticleIDMetadataFramework options/ExampleParticleIDMetadata. add_custom_command(TARGET k4FWCoreTestPlugins POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/python/k4FWCore/ ${PROJECT_BINARY_DIR}/k4FWCore/genConfDir/k4FWCore) + + +add_executable(check_ParticleIDOutputs src/check_ParticleIDOutputs.cpp) +target_link_libraries(check_ParticleIDOutputs PRIVATE podio::podioIO EDM4HEP::edm4hep EDM4HEP::utils fmt::fmt) +add_test(NAME check_ParticleIDOutputs COMMAND check_ParticleIDOutputs example_with_particleids.root) +set_test_env(check_ParticleIDOutputs) +set_tests_properties(check_ParticleIDOutputs PROPERTIES DEPENDS ParticleIDMetadataFramework) diff --git a/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp b/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp new file mode 100644 index 00000000..7392bf63 --- /dev/null +++ b/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp @@ -0,0 +1,85 @@ +#include +#include + +#include + +#include +#include + +#include + +void checkPIDForAlgo(const edm4hep::utils::PIDHandler& pidHandler, const edm4hep::ReconstructedParticle& reco, + const edm4hep::utils::ParticleIDMeta& pidMeta, const int paramIndex) { + auto maybePID = pidHandler.getPID(reco, pidMeta.algoType()); + if (!maybePID) { + throw std::runtime_error( + fmt::format("Could net retrieve the {} PID object for reco particle {}", pidMeta.algoName, reco.id().index)); + } + auto pid = maybePID.value(); + auto paramVal = pid.getParameters()[paramIndex]; + + // As set in the producer + if (paramVal != paramIndex * 0.5f) { + throw std::runtime_error( + fmt::format("Could not retrieve the correct parameter value for param {} (expected {}, actual {})", + pidMeta.paramNames[paramIndex], paramIndex * 0.5f, paramVal)); + } +} + +bool checkAlgoMetadata(const edm4hep::utils::ParticleIDMeta& pidMeta, const std::string& algoName, + const std::vector& paramNames) { + if (pidMeta.algoName != algoName) { + fmt::print( + "The PID algorithm name from metadata does not match the expected one from the properties: (expected {}, " + "actual {})\n", + algoName, pidMeta.algoName); + return false; + } + + if (!std::ranges::equal(pidMeta.paramNames, paramNames)) { + fmt::print( + "The PID parameter names retrieved from metadata does not match the expected ones from the properties: " + "(expected {}, actual {})\n", + paramNames, pidMeta.paramNames); + return false; + } + + return true; +} + +int main(int, char* argv[]) { + auto reader = podio::makeReader(argv[1]); + const auto metadata = reader.readFrame(podio::Category::Metadata, 0); + + const auto pidMeta1 = edm4hep::utils::PIDHandler::getAlgoInfo(metadata, "RecoParticlesPIDs_1").value(); + const auto pidMeta2 = edm4hep::utils::PIDHandler::getAlgoInfo(metadata, "RecoParticlesPIDs_2").value(); + + if (!checkAlgoMetadata(pidMeta1, "PIDAlgo1", {"single_param"}) || + !checkAlgoMetadata(pidMeta2, "PIDAlgo2", {"param_1", "param_2", "param_3"})) { + return 1; + } + + const auto paramIndex1 = edm4hep::utils::getParamIndex(pidMeta1, "single_param").value_or(-1); + const auto paramIndex2 = edm4hep::utils::getParamIndex(pidMeta2, "param_2").value_or(-1); + if (paramIndex1 < 0 || paramIndex2 < 0) { + fmt::print("Could not get a parameter index for 'single_param' (got {}) or 'param_2' (got {})\n", paramIndex1, + paramIndex2); + } + + const auto event = reader.readEvent(0); + const auto pidHandler = edm4hep::utils::PIDHandler::from(event, metadata); + + const auto& recos = event.get("RecoParticles"); + for (const auto r : recos) { + auto pids = pidHandler.getPIDs(r); + if (pids.size() != 2) { + throw std::runtime_error(fmt::format( + "Failed to retrieve the two expected ParticlID objects related to reco particle {}", r.id().index)); + + checkPIDForAlgo(pidHandler, r, pidMeta1, paramIndex1); + checkPIDForAlgo(pidHandler, r, pidMeta2, paramIndex2); + } + } + + return 0; +} From 60c885aab8a4bdd6d7fb61306cf9cad12c1368c4 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Thu, 16 Jan 2025 14:14:59 +0100 Subject: [PATCH 06/14] Move configuration into global variables --- .../src/check_ParticleIDOutputs.cpp | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp b/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp index 7392bf63..671323b3 100644 --- a/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp +++ b/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp @@ -47,23 +47,33 @@ bool checkAlgoMetadata(const edm4hep::utils::ParticleIDMeta& pidMeta, const std: return true; } +// Test configuration (this needs to match the settings in +// options/ExampleParticleIDMetadata.py) +constexpr auto pidCollectionName1 = "RecoParticlesPIDs_1"; +constexpr auto pidCollectionName2 = "RecoParticlesPIDs_2"; +constexpr auto pidAlgo1 = "PIDAlgo1"; +constexpr auto pidAlgo2 = "PIDAlgo2"; +constexpr auto pidParam1 = "single_param"; +constexpr auto pidParam2 = "param_2"; +const std::vector paramNames1 = {"single_param"}; +const std::vector paramNames2 = {"param_1", "param_2", "param_3"}; + int main(int, char* argv[]) { auto reader = podio::makeReader(argv[1]); const auto metadata = reader.readFrame(podio::Category::Metadata, 0); - const auto pidMeta1 = edm4hep::utils::PIDHandler::getAlgoInfo(metadata, "RecoParticlesPIDs_1").value(); - const auto pidMeta2 = edm4hep::utils::PIDHandler::getAlgoInfo(metadata, "RecoParticlesPIDs_2").value(); + const auto pidMeta1 = edm4hep::utils::PIDHandler::getAlgoInfo(metadata, pidCollectionName1).value(); + const auto pidMeta2 = edm4hep::utils::PIDHandler::getAlgoInfo(metadata, pidCollectionName2).value(); - if (!checkAlgoMetadata(pidMeta1, "PIDAlgo1", {"single_param"}) || - !checkAlgoMetadata(pidMeta2, "PIDAlgo2", {"param_1", "param_2", "param_3"})) { + if (!checkAlgoMetadata(pidMeta1, pidAlgo1, paramNames1) || !checkAlgoMetadata(pidMeta2, pidAlgo2, paramNames2)) { return 1; } - const auto paramIndex1 = edm4hep::utils::getParamIndex(pidMeta1, "single_param").value_or(-1); - const auto paramIndex2 = edm4hep::utils::getParamIndex(pidMeta2, "param_2").value_or(-1); + const auto paramIndex1 = edm4hep::utils::getParamIndex(pidMeta1, pidParam1).value_or(-1); + const auto paramIndex2 = edm4hep::utils::getParamIndex(pidMeta2, pidParam2).value_or(-1); if (paramIndex1 < 0 || paramIndex2 < 0) { - fmt::print("Could not get a parameter index for 'single_param' (got {}) or 'param_2' (got {})\n", paramIndex1, - paramIndex2); + fmt::print("Could not get a parameter index for '{}' (got {}) or '{}' (got {})\n", pidParam1, paramIndex1, + pidParam2, paramIndex2); } const auto event = reader.readEvent(0); From 3803077e047cdde82533c2e35e7897be7ac890d3 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Fri, 17 Jan 2025 10:59:58 +0100 Subject: [PATCH 07/14] Make test functions consistent and check specific values --- .../src/check_ParticleIDOutputs.cpp | 26 +++++++++++-------- .../components/ExampleParticleIDConsumer.cpp | 2 +- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp b/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp index 671323b3..c80b4041 100644 --- a/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp +++ b/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp @@ -8,22 +8,24 @@ #include -void checkPIDForAlgo(const edm4hep::utils::PIDHandler& pidHandler, const edm4hep::ReconstructedParticle& reco, +bool checkPIDForAlgo(const edm4hep::utils::PIDHandler& pidHandler, const edm4hep::ReconstructedParticle& reco, const edm4hep::utils::ParticleIDMeta& pidMeta, const int paramIndex) { auto maybePID = pidHandler.getPID(reco, pidMeta.algoType()); if (!maybePID) { - throw std::runtime_error( - fmt::format("Could net retrieve the {} PID object for reco particle {}", pidMeta.algoName, reco.id().index)); + fmt::print("Could not retrieve the {} PID object for reco particle {}", pidMeta.algoName, reco.id().index); + return false; } auto pid = maybePID.value(); auto paramVal = pid.getParameters()[paramIndex]; // As set in the producer if (paramVal != paramIndex * 0.5f) { - throw std::runtime_error( - fmt::format("Could not retrieve the correct parameter value for param {} (expected {}, actual {})", - pidMeta.paramNames[paramIndex], paramIndex * 0.5f, paramVal)); + fmt::print("Could not retrieve the correct parameter value for param {} (expected {}, actual {})", + pidMeta.paramNames[paramIndex], paramIndex * 0.5f, paramVal); + return false; } + + return true; } bool checkAlgoMetadata(const edm4hep::utils::ParticleIDMeta& pidMeta, const std::string& algoName, @@ -71,7 +73,7 @@ int main(int, char* argv[]) { const auto paramIndex1 = edm4hep::utils::getParamIndex(pidMeta1, pidParam1).value_or(-1); const auto paramIndex2 = edm4hep::utils::getParamIndex(pidMeta2, pidParam2).value_or(-1); - if (paramIndex1 < 0 || paramIndex2 < 0) { + if (paramIndex1 == -1 || paramIndex2 == -1) { fmt::print("Could not get a parameter index for '{}' (got {}) or '{}' (got {})\n", pidParam1, paramIndex1, pidParam2, paramIndex2); } @@ -83,11 +85,13 @@ int main(int, char* argv[]) { for (const auto r : recos) { auto pids = pidHandler.getPIDs(r); if (pids.size() != 2) { - throw std::runtime_error(fmt::format( - "Failed to retrieve the two expected ParticlID objects related to reco particle {}", r.id().index)); + fmt::print("Failed to retrieve the two expected ParticlID objects related to reco particle {}", r.id().index); + return 1; + } - checkPIDForAlgo(pidHandler, r, pidMeta1, paramIndex1); - checkPIDForAlgo(pidHandler, r, pidMeta2, paramIndex2); + if (!checkPIDForAlgo(pidHandler, r, pidMeta1, paramIndex1) || + !checkPIDForAlgo(pidHandler, r, pidMeta2, paramIndex2)) { + return 1; } } diff --git a/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp b/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp index 665f256e..c5bb93c3 100644 --- a/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp +++ b/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp @@ -96,7 +96,7 @@ struct ExampleParticleIDConsumer final m_paramIndex1 = edm4hep::utils::getParamIndex(m_pidMeta1, m_paramOfInterest1.value()).value_or(-1); m_paramIndex2 = edm4hep::utils::getParamIndex(m_pidMeta2, m_paramOfInterest2.value()).value_or(-1); - if (m_paramIndex1 < 0 || m_paramIndex2 < 0) { + if (m_paramIndex1 == -1 || m_paramIndex2 == -1) { error() << fmt::format("Could not get a parameter index for {} (got {}) or {} (got {})", m_paramOfInterest1.value(), m_paramIndex1, m_paramOfInterest2.value(), m_paramIndex2) << endmsg; From e4a1ff4625d02eafe37706f93e6c2a997341781b Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Fri, 17 Jan 2025 11:10:09 +0100 Subject: [PATCH 08/14] Add license header --- .../src/check_ParticleIDOutputs.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp b/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp index c80b4041..b3c66a5c 100644 --- a/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp +++ b/test/k4FWCoreTest/src/check_ParticleIDOutputs.cpp @@ -1,3 +1,22 @@ +/* + * 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. + */ + #include #include From cc8a2af459ce618317bade9b623c5bdd0e954802 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Fri, 17 Jan 2025 13:12:38 +0100 Subject: [PATCH 09/14] Fix unrelated test failures Necessary because there is a new output collection in the functional producer that is used in several places --- ...eFunctionalConsumerRuntimeCollectionsMultiple.py | 3 +++ ...nctionalTransformerRuntimeCollectionsMultiple.py | 3 +++ test/k4FWCoreTest/options/runFunctionalMix.py | 1 + test/k4FWCoreTest/scripts/CheckOutputFiles.py | 13 ++++++++++++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/test/k4FWCoreTest/options/ExampleFunctionalConsumerRuntimeCollectionsMultiple.py b/test/k4FWCoreTest/options/ExampleFunctionalConsumerRuntimeCollectionsMultiple.py index 684d93c5..ef494441 100644 --- a/test/k4FWCoreTest/options/ExampleFunctionalConsumerRuntimeCollectionsMultiple.py +++ b/test/k4FWCoreTest/options/ExampleFunctionalConsumerRuntimeCollectionsMultiple.py @@ -37,6 +37,7 @@ OutputCollectionSimTrackerHits=["SimTrackerHits0"], OutputCollectionTrackerHits=["TrackerHits0"], OutputCollectionTracks=["Tracks0"], + OutputCollectionRecoParticles=["Recos0"], ExampleInt=5, ) producer1 = ExampleFunctionalProducerMultiple( @@ -47,6 +48,7 @@ OutputCollectionSimTrackerHits=["SimTrackerHits1"], OutputCollectionTrackerHits=["TrackerHits1"], OutputCollectionTracks=["Tracks1"], + OutputCollectionRecoParticles=["Recos1"], ExampleInt=5, ) producer2 = ExampleFunctionalProducerMultiple( @@ -57,6 +59,7 @@ OutputCollectionSimTrackerHits=["SimTrackerHits2"], OutputCollectionTrackerHits=["TrackerHits2"], OutputCollectionTracks=["Tracks2"], + OutputCollectionRecoParticles=["Recos2"], ExampleInt=5, ) diff --git a/test/k4FWCoreTest/options/ExampleFunctionalTransformerRuntimeCollectionsMultiple.py b/test/k4FWCoreTest/options/ExampleFunctionalTransformerRuntimeCollectionsMultiple.py index 2103e250..f12dab24 100644 --- a/test/k4FWCoreTest/options/ExampleFunctionalTransformerRuntimeCollectionsMultiple.py +++ b/test/k4FWCoreTest/options/ExampleFunctionalTransformerRuntimeCollectionsMultiple.py @@ -38,6 +38,7 @@ OutputCollectionSimTrackerHits=["SimTrackerHits0"], OutputCollectionTrackerHits=["TrackerHits0"], OutputCollectionTracks=["Tracks0"], + OutputCollectionRecoParticles=["Recos0"], ExampleInt=5, ) producer1 = ExampleFunctionalProducerMultiple( @@ -48,6 +49,7 @@ OutputCollectionSimTrackerHits=["SimTrackerHits1"], OutputCollectionTrackerHits=["TrackerHits1"], OutputCollectionTracks=["Tracks1"], + OutputCollectionRecoParticles=["Recos1"], ExampleInt=5, ) producer2 = ExampleFunctionalProducerMultiple( @@ -58,6 +60,7 @@ OutputCollectionSimTrackerHits=["SimTrackerHits2"], OutputCollectionTrackerHits=["TrackerHits2"], OutputCollectionTracks=["Tracks2"], + OutputCollectionRecoParticles=["Recos2"], ExampleInt=5, ) diff --git a/test/k4FWCoreTest/options/runFunctionalMix.py b/test/k4FWCoreTest/options/runFunctionalMix.py index 4daa5b6a..298bbd71 100644 --- a/test/k4FWCoreTest/options/runFunctionalMix.py +++ b/test/k4FWCoreTest/options/runFunctionalMix.py @@ -90,6 +90,7 @@ OutputCollectionSimTrackerHits=["FunctionalSimTrackerHits"], OutputCollectionTrackerHits=["FunctionalTrackerHits"], OutputCollectionTracks=["FunctionalTracks"], + OutputCollectionRecoParticles=["FunctionalRecos"], ExampleInt=5, ) diff --git a/test/k4FWCoreTest/scripts/CheckOutputFiles.py b/test/k4FWCoreTest/scripts/CheckOutputFiles.py index 518eb087..95fc2167 100644 --- a/test/k4FWCoreTest/scripts/CheckOutputFiles.py +++ b/test/k4FWCoreTest/scripts/CheckOutputFiles.py @@ -83,11 +83,19 @@ def check_metadata(filename, expected_metadata): "Tracks", "Counter", "NewMCParticles", + "RecoParticles", ], ) check_collections( "functional_transformer_multiple_output_commands.root", - ["VectorFloat", "MCParticles1", "MCParticles2", "SimTrackerHits", "TrackerHits"], + [ + "VectorFloat", + "MCParticles1", + "MCParticles2", + "SimTrackerHits", + "TrackerHits", + "RecoParticles", + ], ) check_collections("/tmp/a/b/c/functional_producer.root", ["MCParticles"]) check_collections( @@ -104,6 +112,7 @@ def check_metadata(filename, expected_metadata): "TrackerHits", "Tracks", "NewMCParticles", + "RecoParticles", ], ) @@ -116,6 +125,7 @@ def check_metadata(filename, expected_metadata): "SimTrackerHits", "TrackerHits", "Tracks", + "RecoParticles", # Produced by functional "FunctionalVectorFloat", "FunctionalMCParticles", @@ -123,6 +133,7 @@ def check_metadata(filename, expected_metadata): "FunctionalSimTrackerHits", "FunctionalTrackerHits", "FunctionalTracks", + "FunctionalRecos", # Produced by an old algorithm "OldAlgorithmMCParticles", "OldAlgorithmSimTrackerHits", From 50d288aacf139279143b0578ee6c83616a8d5ced Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Fri, 17 Jan 2025 13:16:14 +0100 Subject: [PATCH 10/14] Find fmtlib in cmake if we build the tests Technically already covered via Gaudi, but this makes it explicit --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c55ba9b..30658623 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ add_subdirectory(k4FWCore) add_subdirectory(k4Interface) add_subdirectory(python) if(BUILD_TESTING) + find_package(fmt REQUIRED) add_subdirectory(test/k4FWCoreTest) endif() From 842a5d54aa7404f987cdfd298e22daffdaa4edd7 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Mon, 20 Jan 2025 08:43:44 +0100 Subject: [PATCH 11/14] Find fmtlib unconditionally --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 30658623..a5baecb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ find_package(ROOT COMPONENTS RIO Tree REQUIRED) find_package(Gaudi REQUIRED) find_package(podio 1.0.1 REQUIRED) find_package(EDM4HEP 0.99 REQUIRED) +find_package(fmt REQUIRED) include(cmake/Key4hepConfig.cmake) @@ -45,7 +46,6 @@ add_subdirectory(k4FWCore) add_subdirectory(k4Interface) add_subdirectory(python) if(BUILD_TESTING) - find_package(fmt REQUIRED) add_subdirectory(test/k4FWCoreTest) endif() From 2f9f701f388c3086b562f5dd79be25d4a0856716 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Fri, 24 Jan 2025 17:25:20 +0100 Subject: [PATCH 12/14] Add missing override specifiers Co-authored-by: Juan Miguel Carceller <22276694+jmcarcell@users.noreply.github.com> --- .../k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp | 2 +- .../k4FWCoreTest/src/components/ExampleParticleIDProducer.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp b/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp index c5bb93c3..a5240635 100644 --- a/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp +++ b/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp @@ -106,7 +106,7 @@ struct ExampleParticleIDConsumer final } void operator()(const edm4hep::ParticleIDCollection& pidColl1, const edm4hep::ParticleIDCollection& pidColl2, - const edm4hep::ReconstructedParticleCollection& recos) const { + const edm4hep::ReconstructedParticleCollection& recos) const override { auto pidHandler = edm4hep::utils::PIDHandler::from(pidColl1, pidColl2); pidHandler.addMetaInfos(m_pidMeta1, m_pidMeta2); diff --git a/test/k4FWCoreTest/src/components/ExampleParticleIDProducer.cpp b/test/k4FWCoreTest/src/components/ExampleParticleIDProducer.cpp index fc102349..4171da98 100644 --- a/test/k4FWCoreTest/src/components/ExampleParticleIDProducer.cpp +++ b/test/k4FWCoreTest/src/components/ExampleParticleIDProducer.cpp @@ -41,9 +41,9 @@ struct ExampleParticleIDProducer final return StatusCode::SUCCESS; } - edm4hep::ParticleIDCollection operator()(const edm4hep::ReconstructedParticleCollection& recos) const { + edm4hep::ParticleIDCollection operator()(const edm4hep::ReconstructedParticleCollection& recos) const override { auto pidColl = edm4hep::ParticleIDCollection{}; - for (const auto r : recos) { + for (const auto& r : recos) { auto pid = pidColl.create(); pid.setAlgorithmType(m_pidMeta.algoType()); pid.setPDG(r.getPDG() - 10); From 8c7de7375751ce8410d4fcc22ef46edfb9b62550 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Fri, 24 Jan 2025 17:27:34 +0100 Subject: [PATCH 13/14] Properly declare the fmt dependency to downstream --- README.md | 2 ++ cmake/k4FWCoreConfig.cmake.in | 1 + 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index 0f98ddaf..5768efa5 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,8 @@ print(my_opts[0].foo) * EDM4HEP +* fmt + ## Installation and downstream usage. k4FWCore is a CMake project. After setting up the dependencies (use for example `source /cvmfs/sw.hsf.org/key4hep/setup.sh`) diff --git a/cmake/k4FWCoreConfig.cmake.in b/cmake/k4FWCoreConfig.cmake.in index 3478680f..02a13c49 100644 --- a/cmake/k4FWCoreConfig.cmake.in +++ b/cmake/k4FWCoreConfig.cmake.in @@ -22,6 +22,7 @@ find_dependency(podio @podio_VERSION@) find_dependency(Gaudi @Gaudi_VERSION@) find_dependency(EDM4HEP @EDM4HEP_VERSION@) find_dependency(ROOT @ROOT_VERSION@ COMPONENTS RIO Tree) +find_dependency(fmt @fmt_VERSION@) if(NOT TARGET k4FWCore::k4FWCore) include("${CMAKE_CURRENT_LIST_DIR}/k4FWCoreTargets.cmake") From 3bcec8b7b99a2389d1fcde35be225a266a87adfa Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Fri, 24 Jan 2025 17:31:49 +0100 Subject: [PATCH 14/14] Make tests compile on older versions of EDM4hep --- test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp b/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp index a5240635..cd3f5485 100644 --- a/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp +++ b/test/k4FWCoreTest/src/components/ExampleParticleIDConsumer.cpp @@ -108,7 +108,8 @@ struct ExampleParticleIDConsumer final void operator()(const edm4hep::ParticleIDCollection& pidColl1, const edm4hep::ParticleIDCollection& pidColl2, const edm4hep::ReconstructedParticleCollection& recos) const override { auto pidHandler = edm4hep::utils::PIDHandler::from(pidColl1, pidColl2); - pidHandler.addMetaInfos(m_pidMeta1, m_pidMeta2); + pidHandler.addMetaInfo(m_pidMeta1); + pidHandler.addMetaInfo(m_pidMeta2); for (const auto r : recos) { auto pids = pidHandler.getPIDs(r);