From 8e0eb80ea7289e6065a99b46482458ddc35d4f07 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Mon, 9 Sep 2024 10:14:29 +0200 Subject: [PATCH] Switch from association to link (#200) * Switch from assocation to link Accomodate for the new naming * Switch to non-deprecated function * Add tests for converting links from EDM4hep to LCIO * Remove leftover docstring * Make comparisons a bit easier to read --- .../src/components/EDM4hep2Lcio.cpp | 10 +-- .../src/components/Lcio2EDM4hep.cpp | 2 +- test/CMakeLists.txt | 12 ++- .../test_link_conversion_edm4hep.py | 84 ++++++++++++++++++ test/src/MarlinMCRecoLinkChecker.cc | 86 +++++++++++++++++++ test/src/TrivialMCRecoLinker.cc | 56 ++++++++++++ 6 files changed, 243 insertions(+), 7 deletions(-) create mode 100644 test/gaudi_opts/test_link_conversion_edm4hep.py create mode 100644 test/src/MarlinMCRecoLinkChecker.cc create mode 100644 test/src/TrivialMCRecoLinker.cc diff --git a/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp b/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp index 5a4d04ae..74c44517 100644 --- a/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp +++ b/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp @@ -381,13 +381,13 @@ StatusCode EDM4hep2LcioTool::convertCollections(lcio::LCEventImpl* lcio_event) { std::vector pidCollections{}; std::vector dQdxCollections{}; - std::vector> associations{}; + std::vector> linkCollections{}; for (const auto& [edm4hepName, lcioName] : collsToConvert) { const auto coll = getEDM4hepCollection(edm4hepName); - if (coll->getTypeName().find("Association") != std::string_view::npos) { - debug() << edm4hepName << " is an association collection, converting it later" << endmsg; - associations.emplace_back(lcioName, coll); + if (coll->getTypeName().find("LinkCollection") != std::string_view::npos) { + debug() << edm4hepName << " is a link collection, converting it later" << endmsg; + linkCollections.emplace_back(lcioName, coll); continue; } debug() << "Converting collection " << edm4hepName << " (storing it as " << lcioName << ")" << endmsg; @@ -435,7 +435,7 @@ StatusCode EDM4hep2LcioTool::convertCollections(lcio::LCEventImpl* lcio_event) { EDM4hep2LCIOConv::resolveRelations(collection_pairs, globalObjMap); // Now we can convert the assocations and add them to the event - for (auto& [name, coll] : EDM4hep2LCIOConv::createLCRelationCollections(associations, globalObjMap)) { + for (auto& [name, coll] : EDM4hep2LCIOConv::createLCRelationCollections(linkCollections, globalObjMap)) { lcio_event->addCollection(coll.release(), name); } diff --git a/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp b/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp index 8dd62944..3224394a 100644 --- a/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp +++ b/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp @@ -238,7 +238,7 @@ StatusCode Lcio2EDM4hepTool::convertCollections(lcio::LCEventImpl* the_event) { registerCollection(name, LCIO2EDM4hepConv::fillSubset(coll, globalObjMap, type), coll); } - for (auto&& assocColl : LCIO2EDM4hepConv::createAssociations(globalObjMap, lcRelationColls)) { + for (auto&& assocColl : LCIO2EDM4hepConv::createLinks(globalObjMap, lcRelationColls)) { registerCollection(std::move(assocColl)); // TODO: Potentially handle metadata here? } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cc559117..37061743 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,6 +21,7 @@ gaudi_add_module(GaudiTestAlgorithms SOURCES src/MCRecoLinkChecker.cc src/PseudoRecoAlgorithm.cc + src/TrivialMCRecoLinker.cc LINK Gaudi::GaudiKernel k4FWCore::k4FWCore @@ -37,7 +38,10 @@ set(ExternalData_URL_TEMPLATES # Compile the Marlin test processors into a shared library find_package(Marlin REQUIRED) -add_library(MarlinTestProcessors SHARED src/TrivialMCTruthLinkerProcessor.cc) +add_library(MarlinTestProcessors SHARED + src/TrivialMCTruthLinkerProcessor.cc + src/MarlinMCRecoLinkChecker.cc +) target_link_libraries(MarlinTestProcessors PUBLIC ${Marlin_LIBRARIES}) target_include_directories(MarlinTestProcessors PUBLIC ${Marlin_INCLUDE_DIRS}) @@ -85,6 +89,11 @@ 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 --EventDataSvc.input DATA{${PROJECT_SOURCE_DIR}/test/input_files/ttbar_20240223_edm4hep.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 --inputfile DATA{${PROJECT_SOURCE_DIR}/test/input_files/ttbar_20240223_edm4hep.root} +) + add_test( event_header_conversion bash -c "k4run ${CMAKE_CURRENT_SOURCE_DIR}/gaudi_opts/createEventHeader.py && anajob test.slcio | grep 'EVENT: 42'" ) ExternalData_Add_Target(marlinwrapper_tests) @@ -102,6 +111,7 @@ set_tests_properties ( clic_geo_test global_converter_maps event_header_conversion + link_conversion_edm4hep_to_lcio PROPERTIES ENVIRONMENT "TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR};LD_LIBRARY_PATH=${CMAKE_INSTALL_PREFIX}/lib:${CMAKE_INSTALL_PREFIX}/lib64:$ENV{LD_LIBRARY_PATH};PYTHONPATH=${CMAKE_INSTALL_PREFIX}/python:$ENV{PYTHONPATH};EXAMPLE_DIR=${PROJECT_SOURCE_DIR}/k4MarlinWrapper/examples;MARLIN_DLL=$ENV{MARLIN_DLL}:${CMAKE_CURRENT_BINARY_DIR}/libMarlinTestProcessors.so" ) diff --git a/test/gaudi_opts/test_link_conversion_edm4hep.py b/test/gaudi_opts/test_link_conversion_edm4hep.py new file mode 100644 index 00000000..92080f7e --- /dev/null +++ b/test/gaudi_opts/test_link_conversion_edm4hep.py @@ -0,0 +1,84 @@ +#!/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, DEBUG + +from Configurables import ( + PodioInput, + k4DataSvc, + ApplicationMgr, + PseudoRecoAlgorithm, + TrivialMCRecoLinker, + MarlinProcessorWrapper, + EDM4hep2LcioTool, +) + +from k4FWCore.parseArgs import parser + +parser.add_argument("--inputfile", help="Input file") +my_args = parser.parse_known_args()[0] + +evtsvc = k4DataSvc("EventDataSvc") +evtsvc.input = my_args.inputfile + +podioInput = PodioInput("InputReader") +podioInput.collections = ["MCParticles"] +podioInput.OutputLevel = INFO + + +PseudoRecoAlg = PseudoRecoAlgorithm( + "PseudoRecoAlgorithm", InputMCs=["MCParticles"], OutputRecos=["PseudoRecoParticles"] +) + +MCRecoLinker = TrivialMCRecoLinker( + InputMCs=["MCParticles"], + InputRecos=["PseudoRecoParticles"], + OutputLinks=["TrivialMCRecoLinks"], +) + + +MarlinMCLinkChecker = MarlinProcessorWrapper( + "MarlinMCRecoLinkChecker", + ProcessorType="MarlinMCRecoLinkChecker", + Parameters={ + "MCRecoLinks": ["TrivialMCRecoLinks"], + "InputMCs": ["MCParticles"], + "InputRecos": ["PseudoRecoParticles"], + }, +) + +mcLinkConverter = EDM4hep2LcioTool("MCLinkConverterToEDM4hep") +mcLinkConverter.convertAll = False +mcLinkConverter.collNameMapping = { + "TrivialMCRecoLinks": "TrivialMCRecoLinks", + "MCParticles": "MCParticles", + "PseudoRecoParticles": "PseudoRecoParticles", +} +mcLinkConverter.OutputLevel = DEBUG +MarlinMCLinkChecker.EDM4hep2LcioTool = mcLinkConverter + + +ApplicationMgr( + TopAlg=[podioInput, PseudoRecoAlg, MCRecoLinker, MarlinMCLinkChecker], + ExtSvc=[evtsvc], + EvtMax=-1, + EvtSel="NONE", + OutputLevel=INFO, +) diff --git a/test/src/MarlinMCRecoLinkChecker.cc b/test/src/MarlinMCRecoLinkChecker.cc new file mode 100644 index 00000000..a3a93069 --- /dev/null +++ b/test/src/MarlinMCRecoLinkChecker.cc @@ -0,0 +1,86 @@ +/* + * 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 "marlin/Processor.h" + +#include +#include +#include +#include +#include + +#include +#include + +class MarlinMCRecoLinkChecker : public marlin::Processor { +public: + MarlinMCRecoLinkChecker(); + + marlin::Processor* newProcessor() override { return new MarlinMCRecoLinkChecker; } + + void processEvent(LCEvent* evt) override; + +private: + std::string m_mcCollName{}; + std::string m_recoCollName{}; + std::string m_relCollName{}; +}; + +MarlinMCRecoLinkChecker::MarlinMCRecoLinkChecker() : marlin::Processor("MarlinMCRecoLinkChecker") { + registerInputCollection(LCIO::MCPARTICLE, "InputMCs", "Name of the input MCParticle collection", m_mcCollName, + std::string("MCParticles")); + + registerInputCollection(LCIO::RECONSTRUCTEDPARTICLE, "InputRecos", + "Name of the input ReconstructedParticle collection", m_recoCollName, + std::string("PseudoRecoParticles")); + registerInputCollection(LCIO::LCRELATION, "MCRecoLinks", "Name of the input Reco - MC Truth link collection", + m_relCollName, std::string("TrivialMCRecoLinks")); +} + +void MarlinMCRecoLinkChecker::processEvent(LCEvent* evt) { + const auto mcColl = evt->getCollection(m_mcCollName); + const auto recoColl = evt->getCollection(m_recoCollName); + const auto relColl = evt->getCollection(m_relCollName); + + if (relColl->getNumberOfElements() != mcColl->getNumberOfElements()) { + throw std::runtime_error("The LCRelation collection does not have the expected number of elements: (expected " + + std::to_string(mcColl->getNumberOfElements()) + ", actual " + + std::to_string(relColl->getNumberOfElements()) + ")"); + } + + for (size_t i = 0; i < mcColl->getNumberOfElements(); ++i) { + const auto mc = static_cast(mcColl->getElementAt(i)); + const auto reco = static_cast(recoColl->getElementAt(i)); + const auto rel = static_cast(relColl->getElementAt(i)); + + if (rel->getWeight() != i) { + throw std::runtime_error("Relation " + std::to_string(i) + " does not have the correct weight (expected: " + + std::to_string(i) + ", actual: " + std::to_string(rel->getWeight()) + ")"); + } + + if (rel->getTo() != mc) { + throw std::runtime_error("Relation " + std::to_string(i) + " does not point to the correct MCParticle"); + } + + if (rel->getFrom() != reco) { + throw std::runtime_error("Relation " + std::to_string(i) + " does not point to the correct MCParticle"); + } + } +} + +MarlinMCRecoLinkChecker aMarlinMCRecoLinkChecker{}; diff --git a/test/src/TrivialMCRecoLinker.cc b/test/src/TrivialMCRecoLinker.cc new file mode 100644 index 00000000..2ff5e738 --- /dev/null +++ b/test/src/TrivialMCRecoLinker.cc @@ -0,0 +1,56 @@ +/* + * 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 "edm4hep/MCParticleCollection.h" +#include "edm4hep/RecoMCParticleLinkCollection.h" +#include "edm4hep/ReconstructedParticleCollection.h" + +#include "k4FWCore/Transformer.h" + +#include + +struct TrivialMCRecoLinker final + : k4FWCore::Transformer { + TrivialMCRecoLinker(const std::string& name, ISvcLocator* svcLoc) + : Transformer(name, svcLoc, + {KeyValues("InputMCs", {"MCParticles"}), KeyValues("InputRecos", {"PseudoRecoParticles"})}, + KeyValues("OutputLinks", {"TrivialMCRecoLinks"})) {} + + edm4hep::RecoMCParticleLinkCollection operator()( + const edm4hep::MCParticleCollection& mcParticles, + const edm4hep::ReconstructedParticleCollection& recoParticles) const override { + auto links = edm4hep::RecoMCParticleLinkCollection{}; + + for (size_t i = 0; i < mcParticles.size(); ++i) { + const auto mc = mcParticles[i]; + const auto reco = recoParticles[i]; + + auto link = links.create(); + link.setFrom(reco); + link.setTo(mc); + link.setWeight(i); + } + + return links; + } +}; + +DECLARE_COMPONENT(TrivialMCRecoLinker)