From d29e3097c152bbb703ad4e3502eda0ea80dd71c2 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Thu, 5 Oct 2023 12:19:55 +0200 Subject: [PATCH] Unified converter maps (#147) * Make object map names consistent in both directions * Add a global map to keep state across several conversions * Use TES to move global map between tools instead of singleton * Pass the global maps to subset and association coll conversions * Add isolated test case for the global converter maps * Add brief description of new test case --- k4MarlinWrapper/examples/clicRec_e4h_input.py | 3 + .../k4MarlinWrapper/converters/EDM4hep2Lcio.h | 79 +++++------ .../src/components/EDM4hep2Lcio.cpp | 133 +++++++++++------- .../components/GlobalConvertedObjectsMap.h | 124 ++++++++++++++++ .../src/components/Lcio2EDM4hep.cpp | 56 +++++++- test/CMakeLists.txt | 25 +++- test/README.md | 57 ++++++++ test/gaudi_opts/test_global_converter_maps.py | 95 +++++++++++++ test/scripts/global_converter_maps.sh | 31 ++++ test/src/MCRecoLinkChecker.cc | 71 ++++++++++ test/src/MCRecoLinkChecker.h | 46 ++++++ test/src/PseudoRecoProcessor.cc | 52 +++++++ test/src/PseudoRecoProcessor.h | 37 +++++ test/src/TrivialMCTruthLinkerProcessor.cc | 58 ++++++++ test/src/TrivialMCTruthLinkerProcessor.h | 38 +++++ 15 files changed, 807 insertions(+), 98 deletions(-) create mode 100644 k4MarlinWrapper/src/components/GlobalConvertedObjectsMap.h create mode 100644 test/README.md create mode 100644 test/gaudi_opts/test_global_converter_maps.py create mode 100644 test/scripts/global_converter_maps.sh create mode 100644 test/src/MCRecoLinkChecker.cc create mode 100644 test/src/MCRecoLinkChecker.h create mode 100644 test/src/PseudoRecoProcessor.cc create mode 100644 test/src/PseudoRecoProcessor.h create mode 100644 test/src/TrivialMCTruthLinkerProcessor.cc create mode 100644 test/src/TrivialMCTruthLinkerProcessor.h diff --git a/k4MarlinWrapper/examples/clicRec_e4h_input.py b/k4MarlinWrapper/examples/clicRec_e4h_input.py index 94d6e4b0..f83664f9 100644 --- a/k4MarlinWrapper/examples/clicRec_e4h_input.py +++ b/k4MarlinWrapper/examples/clicRec_e4h_input.py @@ -1722,6 +1722,9 @@ "BuildUpVertices_V0": "BuildUpVertices_V0", "BuildUpVertices": "BuildUpVertices", "PrimaryVertices": "PrimaryVertices", + "BuildUpVertices_RP": "BuildUpVertices_RP", + "BuildUpVertices_V0_RP": "BuildUpVertices_V0_RP", + "PrimaryVertices_RP": "PrimaryVertices_RP", } VertexFinderLCIOConv.OutputLevel = DEBUG # Add it to VertexFinder Algorithm diff --git a/k4MarlinWrapper/k4MarlinWrapper/converters/EDM4hep2Lcio.h b/k4MarlinWrapper/k4MarlinWrapper/converters/EDM4hep2Lcio.h index b0ee251b..c3d3a05e 100644 --- a/k4MarlinWrapper/k4MarlinWrapper/converters/EDM4hep2Lcio.h +++ b/k4MarlinWrapper/k4MarlinWrapper/converters/EDM4hep2Lcio.h @@ -34,12 +34,24 @@ // std #include #include +#include #include -#ifdef EDM4HEP2LCIOCONV_NAMESPACE -using EDM4hep2LCIOConv::CollectionsPairVectors; -using EDM4hep2LCIOConv::vec_pair; -#endif +template using ObjMapT = k4EDM4hep2LcioConv::VecMapT; + +using TrackMap = ObjMapT; +using ClusterMap = ObjMapT; +using VertexMap = ObjMapT; +using TrackerHitMap = ObjMapT; +using SimTrackerHitMap = ObjMapT; +using CaloHitMap = ObjMapT; +using SimCaloHitMap = ObjMapT; +using RawCaloHitMap = ObjMapT; +using TPCHitMap = ObjMapT; +using RecoParticleMap = ObjMapT; +using MCParticleMap = ObjMapT; + +struct CollectionPairMappings; class EDM4hep2LcioTool : public GaudiTool, virtual public IEDMConverter { public: @@ -57,62 +69,47 @@ class EDM4hep2LcioTool : public GaudiTool, virtual public IEDMConverter { PodioDataSvc* m_podioDataSvc; ServiceHandle m_eventDataSvc; - void convertTracks(vec_pair& tracks_vec, - vec_pair& trackerhits_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, - lcio::LCEventImpl* lcio_event); + void convertTracks(TrackMap& tracks_vec, const TrackerHitMap& trackerhits_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); - void convertTrackerHits(vec_pair& trackerhits_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, - lcio::LCEventImpl* lcio_event); + void convertTrackerHits(TrackerHitMap& trackerhits_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); - void convertSimTrackerHits(vec_pair& simtrackerhits_vec, - const vec_pair& mcparticles_vec, + void convertSimTrackerHits(SimTrackerHitMap& simtrackerhits_vec, const MCParticleMap& mcparticles_vec, const std::string& e4h_coll_name, const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); - void convertCalorimeterHits(vec_pair& calo_hits_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, - lcio::LCEventImpl* lcio_event); + void convertCalorimeterHits(CaloHitMap& calo_hits_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); - void convertRawCalorimeterHits(vec_pair& raw_calo_hits_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, - lcio::LCEventImpl* lcio_event); + void convertRawCalorimeterHits(RawCaloHitMap& raw_calo_hits_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); - void convertSimCalorimeterHits(vec_pair& sim_calo_hits_vec, - const vec_pair& mcparticles, + void convertSimCalorimeterHits(SimCaloHitMap& sim_calo_hits_vec, const MCParticleMap& mcparticles, const std::string& e4h_coll_name, const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); - void convertTPCHits(vec_pair& tpc_hits_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, + void convertTPCHits(TPCHitMap& tpc_hits_vec, const std::string& e4h_coll_name, const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); - void convertClusters(vec_pair& cluster_vec, - const vec_pair& calohits_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, - lcio::LCEventImpl* lcio_event); + void convertClusters(ClusterMap& cluster_vec, const CaloHitMap& calohits_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); - void convertVertices( - vec_pair& vertex_vec, - const vec_pair& recoparticles_vec, - const std::string& e4h_name, const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); + void convertVertices(VertexMap& vertex_vec, const RecoParticleMap& recoparticles_vec, const std::string& e4h_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); - void convertReconstructedParticles( - vec_pair& recoparticles_vec, - const vec_pair& tracks_vec, - const vec_pair& vertex_vec, - const vec_pair& clusters_vec, const std::string& e4h_coll_name, - const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); + void convertReconstructedParticles(RecoParticleMap& recoparticles_vec, const TrackMap& tracks_vec, + const VertexMap& vertex_vec, const ClusterMap& clusters_vec, + const std::string& e4h_coll_name, const std::string& lcio_coll_name, + lcio::LCEventImpl* lcio_event); - void convertMCParticles(vec_pair& mc_particles_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, - lcio::LCEventImpl* lcio_event); + void convertMCParticles(MCParticleMap& mc_particles_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event); void convertEventHeader(const std::string& e4h_coll_name, lcio::LCEventImpl* lcio_event); void convertAdd(const std::string& e4h_coll_name, const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event, - CollectionsPairVectors& collection_pairs); + CollectionPairMappings& collection_pairs); }; #endif diff --git a/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp b/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp index 3083e266..6d16d05f 100644 --- a/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp +++ b/k4MarlinWrapper/src/components/EDM4hep2Lcio.cpp @@ -17,16 +17,39 @@ * limitations under the License. */ #include "k4MarlinWrapper/converters/EDM4hep2Lcio.h" +#include "GlobalConvertedObjectsMap.h" #include "k4FWCore/DataHandle.h" #include "k4FWCore/MetaDataHandle.h" +#include "GaudiKernel/AnyDataWrapper.h" + +#include + DECLARE_COMPONENT(EDM4hep2LcioTool); #ifdef EDM4HEP2LCIOCONV_NAMESPACE using namespace EDM4hep2LCIOConv; #endif +using namespace k4MarlinWrapper; + +using GlobalMapWrapper = AnyDataWrapper; + +struct CollectionPairMappings { + TrackMap tracks{}; + TrackerHitMap trackerHits{}; + SimTrackerHitMap simTrackerHits{}; + CaloHitMap caloHits{}; + RawCaloHitMap rawCaloHits{}; + SimCaloHitMap simCaloHits{}; + TPCHitMap tpcHits{}; + ClusterMap clusters{}; + VertexMap vertices{}; + RecoParticleMap recoParticles{}; + MCParticleMap mcParticles{}; +}; + EDM4hep2LcioTool::EDM4hep2LcioTool(const std::string& type, const std::string& name, const IInterface* parent) : GaudiTool(type, name, parent), m_eventDataSvc("EventDataSvc", "EDM4hep2LcioTool") { declareInterface(this); @@ -51,8 +74,7 @@ StatusCode EDM4hep2LcioTool::finalize() { return GaudiTool::finalize(); } // Convert EDM4hep Tracks to LCIO // Add converted LCIO ptr and original EDM4hep collection to vector of pairs // Add LCIO Collection Vector to LCIO event -void EDM4hep2LcioTool::convertTracks(vec_pair& tracks_vec, - vec_pair& trackerhits_vec, +void EDM4hep2LcioTool::convertTracks(TrackMap& tracks_vec, const TrackerHitMap& trackerhits_vec, const std::string& e4h_coll_name, const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { DataHandle tracks_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; @@ -67,9 +89,8 @@ void EDM4hep2LcioTool::convertTracks(vec_pair& // Convert EDM4hep TrackerHits to LCIO // Add converted LCIO ptr and original EDM4hep collection to vector of pairs // Add LCIO Collection Vector to LCIO event -void EDM4hep2LcioTool::convertTrackerHits(vec_pair& trackerhits_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, - lcio::LCEventImpl* lcio_event) { +void EDM4hep2LcioTool::convertTrackerHits(TrackerHitMap& trackerhits_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { DataHandle trackerhits_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; const auto trackerhits_coll = trackerhits_handle.get(); @@ -84,10 +105,9 @@ void EDM4hep2LcioTool::convertTrackerHits(vec_pair& simtrackerhits_vec, - const vec_pair& mcparticles_vec, const std::string& e4h_coll_name, - const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { +void EDM4hep2LcioTool::convertSimTrackerHits(SimTrackerHitMap& simtrackerhits_vec, const MCParticleMap& mcparticles_vec, + const std::string& e4h_coll_name, const std::string& lcio_coll_name, + lcio::LCEventImpl* lcio_event) { DataHandle simtrackerhits_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; const auto simtrackerhits_coll = simtrackerhits_handle.get(); @@ -103,9 +123,8 @@ void EDM4hep2LcioTool::convertSimTrackerHits( // Convert EDM4hep Calorimeter Hits to LCIO // Add converted LCIO ptr and original EDM4hep collection to vector of pairs // Add converted LCIO Collection Vector to LCIO event -void EDM4hep2LcioTool::convertCalorimeterHits( - vec_pair& calo_hits_vec, const std::string& e4h_coll_name, - const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { +void EDM4hep2LcioTool::convertCalorimeterHits(CaloHitMap& calo_hits_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { DataHandle calohit_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; const auto calohit_coll = calohit_handle.get(); @@ -121,9 +140,8 @@ void EDM4hep2LcioTool::convertCalorimeterHits( // Convert EDM4hep RAW Calorimeter Hits to LCIO // Add converted LCIO ptr and original EDM4hep collection to vector of pairs // Add converted LCIO Collection Vector to LCIO event -void EDM4hep2LcioTool::convertRawCalorimeterHits( - vec_pair& raw_calo_hits_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { +void EDM4hep2LcioTool::convertRawCalorimeterHits(RawCaloHitMap& raw_calo_hits_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { DataHandle raw_calohit_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; const auto rawcalohit_coll = raw_calohit_handle.get(); @@ -136,10 +154,9 @@ void EDM4hep2LcioTool::convertRawCalorimeterHits( // Convert EDM4hep Sim Calorimeter Hits to LCIO // Add converted LCIO ptr and original EDM4hep collection to vector of pairs // Add converted LCIO Collection Vector to LCIO event -void EDM4hep2LcioTool::convertSimCalorimeterHits( - vec_pair& sim_calo_hits_vec, - const vec_pair& mcparticles, const std::string& e4h_coll_name, - const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { +void EDM4hep2LcioTool::convertSimCalorimeterHits(SimCaloHitMap& sim_calo_hits_vec, const MCParticleMap& mcparticles, + const std::string& e4h_coll_name, const std::string& lcio_coll_name, + lcio::LCEventImpl* lcio_event) { DataHandle sim_calohit_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; const auto simcalohit_coll = sim_calohit_handle.get(); @@ -156,9 +173,8 @@ void EDM4hep2LcioTool::convertSimCalorimeterHits( // Convert EDM4hep TPC Hits to LCIO // Add converted LCIO ptr and original EDM4hep collection to vector of pairs // Add converted LCIO Collection Vector to LCIO event -void EDM4hep2LcioTool::convertTPCHits(vec_pair& tpc_hits_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, - lcio::LCEventImpl* lcio_event) { +void EDM4hep2LcioTool::convertTPCHits(TPCHitMap& tpc_hits_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { DataHandle tpchit_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; const auto tpchit_coll = tpchit_handle.get(); @@ -171,8 +187,7 @@ void EDM4hep2LcioTool::convertTPCHits(vec_pair& cluster_vec, - const vec_pair& calohits_vec, +void EDM4hep2LcioTool::convertClusters(ClusterMap& cluster_vec, const CaloHitMap& calohits_vec, const std::string& e4h_coll_name, const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { DataHandle cluster_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; @@ -187,10 +202,9 @@ void EDM4hep2LcioTool::convertClusters(vec_pair& vertex_vec, - const vec_pair& recoparticles_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { +void EDM4hep2LcioTool::convertVertices(VertexMap& vertex_vec, const RecoParticleMap& recoparticles_vec, + const std::string& e4h_coll_name, const std::string& lcio_coll_name, + lcio::LCEventImpl* lcio_event) { DataHandle vertex_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; const auto vertex_coll = vertex_handle.get(); @@ -203,9 +217,8 @@ void EDM4hep2LcioTool::convertVertices( // Convert MC Particles to LCIO // Add converted LCIO ptr and original EDM4hep collection to vector of pairs // Add converted LCIO Collection Vector to LCIO event -void EDM4hep2LcioTool::convertMCParticles(vec_pair& mc_particles_vec, - const std::string& e4h_coll_name, const std::string& lcio_coll_name, - lcio::LCEventImpl* lcio_event) { +void EDM4hep2LcioTool::convertMCParticles(MCParticleMap& mc_particles_vec, const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { // MCParticles handle DataHandle mcparticle_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; const auto mcparticle_coll = mcparticle_handle.get(); @@ -219,12 +232,10 @@ void EDM4hep2LcioTool::convertMCParticles(vec_pair& recoparticles_vec, - const vec_pair& tracks_vec, - const vec_pair& vertex_vec, - const vec_pair& clusters_vec, const std::string& e4h_coll_name, - const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { +void EDM4hep2LcioTool::convertReconstructedParticles(RecoParticleMap& recoparticles_vec, const TrackMap& tracks_vec, + const VertexMap& vertex_vec, const ClusterMap& clusters_vec, + const std::string& e4h_coll_name, + const std::string& lcio_coll_name, lcio::LCEventImpl* lcio_event) { // ReconstructedParticles handle DataHandle recos_handle{e4h_coll_name, Gaudi::DataHandle::Reader, this}; const auto recos_coll = recos_handle.get(); @@ -249,7 +260,7 @@ void EDM4hep2LcioTool::convertEventHeader(const std::string& e4h_coll_name, lcio // Select the appropiate method to convert a collection given its type void EDM4hep2LcioTool::convertAdd(const std::string& e4h_coll_name, const std::string& lcio_coll_name, - lcio::LCEventImpl* lcio_event, CollectionsPairVectors& collection_pairs) { + lcio::LCEventImpl* lcio_event, CollectionPairMappings& collection_pairs) { const auto& evtFrame = m_podioDataSvc->getEventFrame(); const auto collPtr = evtFrame.get(e4h_coll_name); if (!collPtr) { @@ -257,31 +268,33 @@ void EDM4hep2LcioTool::convertAdd(const std::string& e4h_coll_name, const std::s } const auto fulltype = collPtr->getValueTypeName(); + debug() << "Converting type " << fulltype << " from input " << e4h_coll_name << endmsg; + if (fulltype == "edm4hep::Track") { - convertTracks(collection_pairs.tracks, collection_pairs.trackerhits, e4h_coll_name, lcio_coll_name, lcio_event); + convertTracks(collection_pairs.tracks, collection_pairs.trackerHits, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::TrackerHit") { - convertTrackerHits(collection_pairs.trackerhits, e4h_coll_name, lcio_coll_name, lcio_event); + convertTrackerHits(collection_pairs.trackerHits, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::SimTrackerHit") { - convertSimTrackerHits(collection_pairs.simtrackerhits, collection_pairs.mcparticles, e4h_coll_name, lcio_coll_name, + convertSimTrackerHits(collection_pairs.simTrackerHits, collection_pairs.mcParticles, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::CalorimeterHit") { - convertCalorimeterHits(collection_pairs.calohits, e4h_coll_name, lcio_coll_name, lcio_event); + convertCalorimeterHits(collection_pairs.caloHits, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::RawCalorimeterHit") { - convertRawCalorimeterHits(collection_pairs.rawcalohits, e4h_coll_name, lcio_coll_name, lcio_event); + convertRawCalorimeterHits(collection_pairs.rawCaloHits, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::SimCalorimeterHit") { - convertSimCalorimeterHits(collection_pairs.simcalohits, collection_pairs.mcparticles, e4h_coll_name, lcio_coll_name, + convertSimCalorimeterHits(collection_pairs.simCaloHits, collection_pairs.mcParticles, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::RawTimeSeries") { - convertTPCHits(collection_pairs.tpchits, e4h_coll_name, lcio_coll_name, lcio_event); + convertTPCHits(collection_pairs.tpcHits, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::Cluster") { - convertClusters(collection_pairs.clusters, collection_pairs.calohits, e4h_coll_name, lcio_coll_name, lcio_event); + convertClusters(collection_pairs.clusters, collection_pairs.caloHits, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::Vertex") { - convertVertices(collection_pairs.vertices, collection_pairs.recoparticles, e4h_coll_name, lcio_coll_name, + convertVertices(collection_pairs.vertices, collection_pairs.recoParticles, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::MCParticle") { - convertMCParticles(collection_pairs.mcparticles, e4h_coll_name, lcio_coll_name, lcio_event); + convertMCParticles(collection_pairs.mcParticles, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::ReconstructedParticle") { - convertReconstructedParticles(collection_pairs.recoparticles, collection_pairs.tracks, collection_pairs.vertices, + convertReconstructedParticles(collection_pairs.recoParticles, collection_pairs.tracks, collection_pairs.vertices, collection_pairs.clusters, e4h_coll_name, lcio_coll_name, lcio_event); } else if (fulltype == "edm4hep::EventHeader") { convertEventHeader(e4h_coll_name, lcio_event); @@ -313,8 +326,9 @@ StatusCode EDM4hep2LcioTool::convertCollections(lcio::LCEventImpl* lcio_event) { } } - CollectionsPairVectors collection_pairs{}; + CollectionPairMappings collection_pairs{}; for (const auto& [edm4hepName, lcioName] : collsToConvert) { + debug() << "Converting collection " << edm4hepName << " (storing it as " << lcioName << ")" << endmsg; if (!collectionExist(lcioName, lcio_event)) { convertAdd(edm4hepName, lcioName, lcio_event, collection_pairs); } else { @@ -324,7 +338,24 @@ StatusCode EDM4hep2LcioTool::convertCollections(lcio::LCEventImpl* lcio_event) { debug() << "Event: " << lcio_event->getEventNumber() << " Run: " << lcio_event->getRunNumber() << endmsg; - FillMissingCollections(collection_pairs); + // We want one "global" map that is created the first time it is use in the + // event. + // + // Technically getOrCreate is a thing in GaudiTool but that doesn't seem to + // easily work with the AnyDataWrapper we want to use here. So doing the two + // step process here + if (!exist(GlobalConvertedObjectsMap::TESpath.data())) { + debug() << "Creating GlobalconvertedObjectsMap for this event since it is not already in the EventStore" << endmsg; + auto globalObjMapWrapper = std::make_unique(GlobalConvertedObjectsMap{}); + put(std::move(globalObjMapWrapper), GlobalConvertedObjectsMap::TESpath.data()); + } + + auto globalObjMapWrapper = get(GlobalConvertedObjectsMap::TESpath.data()); + auto& globalObjMap = globalObjMapWrapper->getData(); + + globalObjMap.update(collection_pairs); + + FillMissingCollections(collection_pairs, globalObjMap); return StatusCode::SUCCESS; } diff --git a/k4MarlinWrapper/src/components/GlobalConvertedObjectsMap.h b/k4MarlinWrapper/src/components/GlobalConvertedObjectsMap.h new file mode 100644 index 00000000..3e75f8f0 --- /dev/null +++ b/k4MarlinWrapper/src/components/GlobalConvertedObjectsMap.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2019-2023 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. + */ +#ifndef K4MARLINWRAPPER_CONVEREROBJECT_MAP_H +#define K4MARLINWRAPPER_CONVEREROBJECT_MAP_H + +#include "k4EDM4hep2LcioConv/MappingUtils.h" + +#include + +namespace EVENT { + class Track; + class TrackerHit; + class TrackerHitPlane; + class SimTrackerHit; + class CalorimeterHit; + class RawCalorimeterHit; + class SimCalorimeterHit; + class TPCHit; + class Cluster; + class Vertex; + class ReconstructedParticle; + class MCParticle; + class ParticleID; +} // namespace EVENT + +namespace edm4hep { + class Track; + class TrackerHit; + class TrackerHitPlane; + class SimTrackerHit; + class CalorimeterHit; + class RawCalorimeterHit; + class SimCalorimeterHit; + class RawTimeSeries; + class Cluster; + class Vertex; + class ReconstructedParticle; + class MCParticle; + class ParticleID; +} // namespace edm4hep + +namespace k4MarlinWrapper { + + /** + * Fill all key value pairs from updates into map + */ + template void updateMap(Map& map, const UpdateMap& updates) { + for (const auto& [k, v] : updates) { + k4EDM4hep2LcioConv::detail::mapInsert(k, v, map); + } + } + + namespace detail { + /// Detectors for checking whether T has a trackerHitPlanes and a particleIDs map + template using has_trkhit_plane = decltype(std::declval().trackerHitPlanes); + template using has_particle_id = decltype(std::declval().particleIDs); + } // namespace detail + + /** + * The LCIO <-> EDM4hep object mapping that holds the relations between all + * converted objects from all converters that are running. + */ + struct GlobalConvertedObjectsMap { + template using ObjectMapT = k4EDM4hep2LcioConv::VecMapT; + + ObjectMapT tracks{}; + ObjectMapT trackerHits{}; + ObjectMapT simTrackerHits{}; + ObjectMapT caloHits{}; + ObjectMapT rawCaloHits{}; + ObjectMapT simCaloHits{}; + ObjectMapT tpcHits{}; + ObjectMapT clusters{}; + ObjectMapT vertices{}; + ObjectMapT recoParticles{}; + ObjectMapT mcParticles{}; + ObjectMapT trackerHitPlanes{}; + ObjectMapT particleIDs{}; + + constexpr static auto TESpath = std::string_view{"/Event/EDMConvGlobalObjMap"}; + + /** + * Update the map with contents from one converter run + */ + template void update(const ObjectMap& localMap) { + updateMap(tracks, localMap.tracks); + updateMap(trackerHits, localMap.trackerHits); + updateMap(simTrackerHits, localMap.simTrackerHits); + updateMap(caloHits, localMap.caloHits); + updateMap(rawCaloHits, localMap.rawCaloHits); + updateMap(simCaloHits, localMap.simCaloHits); + updateMap(tpcHits, localMap.tpcHits); + updateMap(clusters, localMap.clusters); + updateMap(vertices, localMap.vertices); + updateMap(recoParticles, localMap.recoParticles); + updateMap(mcParticles, localMap.mcParticles); + + if constexpr (det::is_detected_v) { + updateMap(trackerHitPlanes, localMap.trackerHitPlanes); + } + if constexpr (det::is_detected_v) { + updateMap(particleIDs, localMap.particleIDs); + } + } + }; +} // namespace k4MarlinWrapper + +#endif diff --git a/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp b/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp index b7a8b390..6c892b8b 100644 --- a/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp +++ b/k4MarlinWrapper/src/components/Lcio2EDM4hep.cpp @@ -17,6 +17,7 @@ * limitations under the License. */ #include "k4MarlinWrapper/converters/Lcio2EDM4hep.h" +#include "GlobalConvertedObjectsMap.h" #include #include @@ -39,8 +40,16 @@ #include #include +#include "GaudiKernel/AnyDataWrapper.h" + +#include + DECLARE_COMPONENT(Lcio2EDM4hepTool); +using namespace k4MarlinWrapper; + +using GlobalMapWrapper = AnyDataWrapper; + Lcio2EDM4hepTool::Lcio2EDM4hepTool(const std::string& type, const std::string& name, const IInterface* parent) : GaudiTool(type, name, parent), m_eds("EventDataSvc", "Lcio2EDM4hepTool") { declareInterface(this); @@ -111,6 +120,26 @@ void Lcio2EDM4hepTool::registerCollection( } } +namespace { + template using ObjMapT = k4EDM4hep2LcioConv::VecMapT; + + struct ObjectMappings { + ObjMapT tracks{}; + ObjMapT trackerHits{}; + ObjMapT simTrackerHits{}; + ObjMapT caloHits{}; + ObjMapT rawCaloHits{}; + ObjMapT simCaloHits{}; + ObjMapT tpcHits{}; + ObjMapT clusters{}; + ObjMapT vertices{}; + ObjMapT recoParticles{}; + ObjMapT mcParticles{}; + ObjMapT trackerHitPlanes{}; + ObjMapT particleIDs{}; + }; +} // namespace + StatusCode Lcio2EDM4hepTool::convertCollections(lcio::LCEventImpl* the_event) { // Convert Event Header outside the collections loop if (!collectionExist("EventHeader")) { @@ -128,7 +157,7 @@ StatusCode Lcio2EDM4hepTool::convertCollections(lcio::LCEventImpl* the_event) { } } - auto lcio2edm4hepMaps = LCIO2EDM4hepConv::LcioEdmTypeMapping{}; + auto lcio2edm4hepMaps = ::ObjectMappings{}; std::vector> lcRelationColls{}; std::vector> subsetColls{}; @@ -142,7 +171,7 @@ StatusCode Lcio2EDM4hepTool::convertCollections(lcio::LCEventImpl* the_event) { continue; // No need to convert again } const auto& lcio_coll_type_str = lcio_coll->getTypeName(); - debug() << "LCIO type of the relation is " << lcio_coll_type_str << endmsg; + debug() << "LCIO type of the collection is " << lcio_coll_type_str << endmsg; // We deal with subset collections and LCRelations once we have all data // converted @@ -168,14 +197,31 @@ StatusCode Lcio2EDM4hepTool::convertCollections(lcio::LCEventImpl* the_event) { } } + // We want one "global" map that is created the first time it is use in the + // event. + // + // Technically getOrCreate is a thing in GaudiTool but that doesn't seem to + // easily work with the AnyDataWrapper we want to use here. So doing the two + // step process here + if (!exist(GlobalConvertedObjectsMap::TESpath.data())) { + debug() << "Creating GlobalconvertedObjectsMap for this event since it is not already in the EventStore" << endmsg; + auto globalObjMapWrapper = std::make_unique(GlobalConvertedObjectsMap{}); + put(std::move(globalObjMapWrapper), GlobalConvertedObjectsMap::TESpath.data()); + } + + auto globalObjMapWrapper = get(GlobalConvertedObjectsMap::TESpath.data()); + auto& globalObjMap = globalObjMapWrapper->getData(); + + globalObjMap.update(lcio2edm4hepMaps); + // Now we can resolve relations, subset collections and LCRelations - LCIO2EDM4hepConv::resolveRelations(lcio2edm4hepMaps); + LCIO2EDM4hepConv::resolveRelations(lcio2edm4hepMaps, globalObjMap); for (const auto& [name, coll, type] : subsetColls) { - registerCollection(name, LCIO2EDM4hepConv::fillSubset(coll, lcio2edm4hepMaps, type), coll); + registerCollection(name, LCIO2EDM4hepConv::fillSubset(coll, globalObjMap, type), coll); } - for (auto&& assocColl : LCIO2EDM4hepConv::createAssociations(lcio2edm4hepMaps, lcRelationColls)) { + for (auto&& assocColl : LCIO2EDM4hepConv::createAssociations(globalObjMap, lcRelationColls)) { registerCollection(std::move(assocColl)); // TODO: Potentially handle metadata here? } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 17576afd..77569e4b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,6 +17,24 @@ See the License for the specific language governing permissions and limitations under the License. ]] +gaudi_add_module(GaudiTestAlgorithms + SOURCES + src/MCRecoLinkChecker.cc + LINK + Gaudi::GaudiAlgLib + Gaudi::GaudiKernel + k4FWCore::k4FWCore + EDM4HEP::edm4hep +) + + +# Compile the Marlin test processors into a shared library +find_package(Marlin REQUIRED) + +add_library(MarlinTestProcessors SHARED src/PseudoRecoProcessor.cc src/TrivialMCTruthLinkerProcessor.cc) +target_link_libraries(MarlinTestProcessors PUBLIC ${Marlin_LIBRARIES}) +target_include_directories(MarlinTestProcessors PUBLIC ${Marlin_INCLUDE_DIRS}) + # Add test scripts find_program(BASH_PROGRAM bash) @@ -66,6 +84,10 @@ if (BASH_PROGRAM) # Test the GeoSvc and TrackingCellIDEncodingSvc add_test( clic_geo_test ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/clicGeoTest.sh ) + # Test for checking whether the converters can resolve relations accross + # multiple processors + add_test( global_converter_maps ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/global_converter_maps.sh ) + set_tests_properties ( simple_processors simple_processors2 @@ -77,8 +99,9 @@ if (BASH_PROGRAM) clicRec_lcio_mt clicRec_edm4hep_input clic_geo_test + global_converter_maps 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" + 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" ) set_tests_properties( diff --git a/test/README.md b/test/README.md new file mode 100644 index 00000000..0b6f6e1a --- /dev/null +++ b/test/README.md @@ -0,0 +1,57 @@ + +# k4MarlinWrapper tests + +The test cases for the k4MarlinWrapper are somewhat involved in some cases. +Hence, we try to describe their intent and their high level layout a bit here. +We will be refering to the test cases by name as they are defined in the +[`CMakeLists.txt`](./CMakeLists.txt) file in here. + +## `global_converter_maps` + +The main purpose of this test is to make sure that the EDM conversions work as +expected, even if the event is converted piece-by-piece. In order to make that +work the individual converter tool instances have to share a mapping of all +corresponding LCIO and EDM4hep objects that have been converted (in either +direction). This map is referred to as the *global object map*. + +### Setup + +The test is using the +[`global_converter_maps.sh`](./scripts/global_converter_maps.sh) script which +effectively simply runs the +[`test_global_converter_maps.py`](./gaudi_opts/test_global_converter_maps.py) +options file after downloading some input data. This options file uses two +wrapped MarlinProcessors and one GaudiAlgorithm plus some converters inbetween +them: +- `PodioInput` to read the *MCParticles* collection from the input file (in + EDM4hep format) +- [`PseudoRecoProcessor`](./src/PseudoRecoProcessor.cc) creates a reco particle + for every MC particle in the input collection + - An EDM4hep to LCIO converter converts the input MC particles up front + - An LCIO to EDM4hep converter converts the output reco particles afterwards +- [`TrivalMCTruthLinkerProcessor`](./src/TrivialMCTruthLinkerProcessor.cc) + creates trivial links from the MC particles to the reco particles. + - An LCIO to EDM4hep converter converts the output collction to EDM4hep +- [`MCRecoLinkChecker`](./src/MCRecoLinkChecker.cc) is a Gaudi algorithm that + simply checks whether the MC-reco links are as expected. + +Without the global converter map, the second LCIO to EDM4hep converter that is +run after the MC - reco linker will not produce valid MC - reco links, as it +does not have any knowledge about the input MCs and recos. diff --git a/test/gaudi_opts/test_global_converter_maps.py b/test/gaudi_opts/test_global_converter_maps.py new file mode 100644 index 00000000..4d1758f5 --- /dev/null +++ b/test/gaudi_opts/test_global_converter_maps.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2019-2023 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. +# + +import os + +from Gaudi.Configuration import * + +from Configurables import ( + PodioInput, + MarlinProcessorWrapper, + k4DataSvc, + Lcio2EDM4hepTool, + EDM4hep2LcioTool, + MCRecoLinkChecker, + ApplicationMgr, +) + +evtsvc = k4DataSvc("EventDataSvc") +evtsvc.input = os.path.join( + "$TEST_DIR/inputFiles/", "ttbar_podio230830_edm4hep_frame.root" +) + +podioInput = PodioInput("InputReader") +podioInput.collections = ["MCParticles"] +podioInput.OutputLevel = INFO + +PseudoRecoProc = MarlinProcessorWrapper("PseudoReco") +PseudoRecoProc.ProcessorType = "PseudoRecoProcessor" +PseudoRecoProc.Parameters = { + "InputMCs": ["MCParticles"], + "OutputRecos": ["PseudoRecoParticles"], +} + +inputConverter = EDM4hep2LcioTool("InputConverter") +inputConverter.convertAll = False +inputConverter.collNameMapping = {"MCParticles": "MCParticles"} +inputConverter.OutputLevel = DEBUG + +PseudoRecoProc.EDM4hep2LcioTool = inputConverter + +pseudoRecConverter = Lcio2EDM4hepTool("PseudoRecoConverter") +pseudoRecConverter.convertAll = False +pseudoRecConverter.collNameMapping = {"PseudoRecoParticles": "PseudoRecoParticles"} +pseudoRecConverter.OutputLevel = DEBUG + +PseudoRecoProc.Lcio2EDM4hepTool = pseudoRecConverter + +TrivialMCTruthLinkerProc = MarlinProcessorWrapper("TvivialMCTruthLinker") +TrivialMCTruthLinkerProc.ProcessorType = "TrivialMCTruthLinkerProcessor" +TrivialMCTruthLinkerProc.Parameters = { + "InputMCs": ["MCParticles"], + "InputRecos": ["PseudoRecoParticles"], + "OutputMCRecoLinks": ["TrivialMCRecoLinks"], +} + +mcTruthConverter = Lcio2EDM4hepTool("TrivialMCTruthLinkerConverter") +mcTruthConverter.convertAll = False +mcTruthConverter.collNameMapping = {"TrivialMCRecoLinks": "TrivialMCRecoLinks"} +mcTruthConverter.OutputLevel = DEBUG + +TrivialMCTruthLinkerProc.Lcio2EDM4hepTool = mcTruthConverter + +mcLinkChecker = MCRecoLinkChecker("MCRecoLinkChecker") +mcLinkChecker.InputMCRecoLinks = "TrivialMCRecoLinks" +mcLinkChecker.InputMCs = "MCParticles" +mcLinkChecker.InputRecos = "PseudoRecoParticles" +mcLinkChecker.OutputLevel = DEBUG + +algList = [ + podioInput, + PseudoRecoProc, + TrivialMCTruthLinkerProc, + mcLinkChecker, +] + +ApplicationMgr( + TopAlg=algList, EvtSel="NONE", EvtMax=3, ExtSvc=[evtsvc], OutputLevel=INFO +) diff --git a/test/scripts/global_converter_maps.sh b/test/scripts/global_converter_maps.sh new file mode 100644 index 00000000..5f8045ab --- /dev/null +++ b/test/scripts/global_converter_maps.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env sh +## +## Copyright (c) 2019-2023 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. +## + +set -eu + +if [ ! -d $TEST_DIR/inputFiles/ ]; then + mkdir $TEST_DIR/inputFiles +fi + +if [ ! -f $TEST_DIR/inputFiles/ttbar_podio230830_edm4hep_frame.root ]; then + wget https://github.com/AIDASoft/DD4hep/raw/master/DDTest/inputFiles/ttbar_podio230830_edm4hep_frame.root -P $TEST_DIR/inputFiles/ +fi + +k4run $TEST_DIR/gaudi_opts/test_global_converter_maps.py diff --git a/test/src/MCRecoLinkChecker.cc b/test/src/MCRecoLinkChecker.cc new file mode 100644 index 00000000..7a2310e3 --- /dev/null +++ b/test/src/MCRecoLinkChecker.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019-2023 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 "MCRecoLinkChecker.h" + +DECLARE_COMPONENT(MCRecoLinkChecker) + +MCRecoLinkChecker::MCRecoLinkChecker(const std::string& name, ISvcLocator* pSL) : GaudiAlgorithm(name, pSL) { + declareProperty("InputMCRecoLinks", m_relationCollHandle, "Name of the input MC Reco link collection"); + declareProperty("InputMCs", m_mcCollHandle, "Name of the input MC collection"); + declareProperty("InputRecos", m_recoCollHandle, "Name of the input Reco collection"); +} + +StatusCode MCRecoLinkChecker::execute() { + const auto relationColl = m_relationCollHandle.get(); + const auto mcColl = m_mcCollHandle.get(); + const auto recoColl = m_recoCollHandle.get(); + + if (relationColl->size() != mcColl->size()) { + error() << "The MCReco relation collection does not have the expected size (expected: " << relationColl->size() + << ", actual: " << mcColl->size() << ")" << endmsg; + return StatusCode::FAILURE; + } + + for (size_t i = 0; i < mcColl->size(); ++i) { + const auto mc = (*mcColl)[i]; + const auto reco = (*recoColl)[i]; + const auto relation = (*relationColl)[i]; + + if (relation.getWeight() != i) { + error() << "Relation " << i << " dost not have the correct weight (expected: " << i + << ", actual: " << relation.getWeight() << ")" << endmsg; + return StatusCode::FAILURE; + } + + if (!(relation.getSim() == mc)) { + auto relMC = relation.getSim(); + error() << "Relation " << i + << " does not point to the correct MCParticle (expected: " << mc.getObjectID().collectionID << "|" + << mc.getObjectID().index << ", actual: " << relMC.getObjectID().collectionID << "|" + << relMC.getObjectID().index << ")" << endmsg; + return StatusCode::FAILURE; + } + + if (!(relation.getRec() == reco)) { + auto relRec = relation.getRec(); + error() << "Relation " << i + << " does not point to the correct RecoParticle (expected: " << reco.getObjectID().collectionID << "|" + << reco.getObjectID().index << ", actual: " << relRec.getObjectID().collectionID << "|" + << relRec.getObjectID().index << ")" << endmsg; + return StatusCode::FAILURE; + } + } + + return StatusCode::SUCCESS; +} diff --git a/test/src/MCRecoLinkChecker.h b/test/src/MCRecoLinkChecker.h new file mode 100644 index 00000000..b416f113 --- /dev/null +++ b/test/src/MCRecoLinkChecker.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2023 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. + */ +#ifndef K4MARLINWRAPPER_TEST_MCRECOLINKCHECKER_H +#define K4MARLINWRAPPER_TEST_MCRECOLINKCHECKER_H + +#include "edm4hep/MCParticleCollection.h" +#include "edm4hep/MCRecoParticleAssociationCollection.h" +#include "edm4hep/ReconstructedParticleCollection.h" + +#include "k4FWCore/DataHandle.h" + +#include +#include + +#include + +class MCRecoLinkChecker : public GaudiAlgorithm { +public: + explicit MCRecoLinkChecker(const std::string& name, ISvcLocator* pSL); + StatusCode execute() final; + +private: + DataHandle m_relationCollHandle{"MCRecoTruthLinks", + Gaudi::DataHandle::Reader, this}; + DataHandle m_mcCollHandle{"MCParticles", Gaudi::DataHandle::Reader, this}; + DataHandle m_recoCollHandle{"RecoParticles", Gaudi::DataHandle::Reader, + this}; +}; + +#endif // K4MARLINWRAPPER_TEST_MCRECOLINKCHECKER_H diff --git a/test/src/PseudoRecoProcessor.cc b/test/src/PseudoRecoProcessor.cc new file mode 100644 index 00000000..f2a15349 --- /dev/null +++ b/test/src/PseudoRecoProcessor.cc @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019-2023 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 "PseudoRecoProcessor.h" + +#include "EVENT/MCParticle.h" +#include "IMPL/LCCollectionVec.h" +#include "IMPL/ReconstructedParticleImpl.h" +#include "UTIL/LCIterator.h" + +PseudoRecoProcessor aPseudoRecoProcessor; + +PseudoRecoProcessor::PseudoRecoProcessor() : marlin::Processor("PseudoRecoProcessor") { + registerInputCollection(LCIO::MCPARTICLE, "InputMCs", "Name of the input MCParticle collection", m_mcCollName, + std::string("MCParticles")); + + registerOutputCollection(LCIO::RECONSTRUCTEDPARTICLE, "OutputRecos", + "Name of the output ReconstructedParticle collection", m_recoCollName, + std::string("PseudoRecoParticles")); +} + +void PseudoRecoProcessor::processEvent(LCEvent* evt) { + auto mcParticleIter = UTIL::LCIterator(evt, m_mcCollName); + auto* recoColl = new IMPL::LCCollectionVec(LCIO::RECONSTRUCTEDPARTICLE); + + while (auto* mcParticle = mcParticleIter.next()) { + auto recoParticle = new IMPL::ReconstructedParticleImpl(); + recoParticle->setCharge(mcParticle->getCharge()); + recoParticle->setMomentum(mcParticle->getMomentum()); + recoParticle->setEnergy(mcParticle->getEnergy()); + recoParticle->setType(mcParticle->getPDG()); + + recoColl->addElement(recoParticle); + } + + evt->addCollection(recoColl, m_recoCollName); +} diff --git a/test/src/PseudoRecoProcessor.h b/test/src/PseudoRecoProcessor.h new file mode 100644 index 00000000..6258dc8a --- /dev/null +++ b/test/src/PseudoRecoProcessor.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019-2023 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 + +class PseudoRecoProcessor : public marlin::Processor { +public: + PseudoRecoProcessor(); + + marlin::Processor* newProcessor() override { return new PseudoRecoProcessor; } + + /** process the event - In this case simply create one ReconstructedParticle + * per input MCParticle (copying the kinematics over) + */ + void processEvent(LCEvent* evt) override; + +private: + std::string m_mcCollName{}; + std::string m_recoCollName{}; +}; diff --git a/test/src/TrivialMCTruthLinkerProcessor.cc b/test/src/TrivialMCTruthLinkerProcessor.cc new file mode 100644 index 00000000..e036285a --- /dev/null +++ b/test/src/TrivialMCTruthLinkerProcessor.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019-2023 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 "TrivialMCTruthLinkerProcessor.h" + +#include "EVENT/MCParticle.h" +#include "EVENT/ReconstructedParticle.h" +#include "IMPL/LCCollectionVec.h" +#include "IMPL/LCRelationImpl.h" + +TrivialMCTruthLinkerProcessor aTrivialMCTruthLinkerProcessor; + +TrivialMCTruthLinkerProcessor::TrivialMCTruthLinkerProcessor() : marlin::Processor("TrivialMCTruthLinkerProcessor") { + 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")); + registerOutputCollection(LCIO::LCRELATION, "OutputMCRecoLinks", "Name of the output Reco - MC Truth link collection", + m_relCollName, std::string("TrivialMCRecoLinks")); +} + +void TrivialMCTruthLinkerProcessor::processEvent(LCEvent* evt) { + const auto mcColl = evt->getCollection(m_mcCollName); + const auto recoColl = evt->getCollection(m_recoCollName); + + // NOTE: Not using LCRelationNavigator here because the internal map might + // screw up the order and we want an easy check afterwards + auto relationColl = new IMPL::LCCollectionVec(LCIO::LCRELATION); + relationColl->parameters().setValue("FromType", LCIO::MCPARTICLE); + relationColl->parameters().setValue("ToType", LCIO::RECONSTRUCTEDPARTICLE); + + for (int i = 0; i < mcColl->getNumberOfElements(); ++i) { + auto relation = new IMPL::LCRelationImpl(); + relation->setFrom(mcColl->getElementAt(i)); + relation->setTo(recoColl->getElementAt(i)); + relation->setWeight(i); + relationColl->addElement(relation); + } + + evt->addCollection(relationColl, m_relCollName); +} diff --git a/test/src/TrivialMCTruthLinkerProcessor.h b/test/src/TrivialMCTruthLinkerProcessor.h new file mode 100644 index 00000000..5eaee996 --- /dev/null +++ b/test/src/TrivialMCTruthLinkerProcessor.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2023 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 + +class TrivialMCTruthLinkerProcessor : public marlin::Processor { +public: + TrivialMCTruthLinkerProcessor(); + + marlin::Processor* newProcessor() override { return new TrivialMCTruthLinkerProcessor; } + + /** process the event - In this case simply link MCparticle[i] with + * ReconstructedParticle[i] + */ + void processEvent(LCEvent* evt) override; + +private: + std::string m_mcCollName{}; + std::string m_recoCollName{}; + std::string m_relCollName{}; +};