diff --git a/.gitignore b/.gitignore index 656d0058..b3a93033 100644 --- a/.gitignore +++ b/.gitignore @@ -246,4 +246,3 @@ test/k4FWCoreTest/**/*.root ## k4MarlinWrapper test/inputFiles/*.slcio test/gaudi_opts/testConverterConstants.py - diff --git a/CMakeLists.txt b/CMakeLists.txt index 10f465c1..b8067293 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,22 @@ set( ${PROJECT_NAME}_VERSION_MINOR 5 ) set( ${PROJECT_NAME}_VERSION_PATCH 0 ) set( ${PROJECT_NAME}_VERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}" ) +# Define a default build type can be overriden by passing +# ``-DCMAKE_BUILD_TYPE=`` when invoking CMake +if(NOT CMAKE_CONFIGURATION_TYPES) + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo + CACHE STRING "Choose the type of build, options are: None Release MinSizeRel Debug RelWithDebInfo" + FORCE + ) + else() + set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" + CACHE STRING "Choose the type of build, options are: None Release MinSizeRel Debug RelWithDebInfo" + FORCE + ) + endif() +endif() + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") diff --git a/k4EDM4hep2LcioConv/src/k4Lcio2EDM4hepConv.cpp b/k4EDM4hep2LcioConv/src/k4Lcio2EDM4hepConv.cpp index 481e24b2..19e411e9 100644 --- a/k4EDM4hep2LcioConv/src/k4Lcio2EDM4hepConv.cpp +++ b/k4EDM4hep2LcioConv/src/k4Lcio2EDM4hepConv.cpp @@ -747,20 +747,19 @@ namespace LCIO2EDM4hepConv { for (auto& [lcio, edm] : recoparticlesMap) { edmnum++; - auto vertex = lcio->getStartVertex(); - if (vertex == nullptr) { - continue; - } - if (const auto it = vertexMap.find(vertex); it != vertexMap.end()) { - edm.setStartVertex(it->second); - } - else { - std::cerr << "Cannot find corresponding EDM4hep Vertex for a LCIO Vertex, " - "while trying to resolve the ReconstructedParticle Relations " - << std::endl; + const auto vertex = lcio->getStartVertex(); + if (vertex) { + if (const auto it = vertexMap.find(vertex); it != vertexMap.end()) { + edm.setStartVertex(it->second); + } + else { + std::cerr << "Cannot find corresponding EDM4hep Vertex for a LCIO Vertex, " + "while trying to resolve the ReconstructedParticle Relations " + << std::endl; + } } - auto clusters = lcio->getClusters(); + const auto& clusters = lcio->getClusters(); for (auto c : clusters) { if (c == nullptr) { continue; @@ -776,7 +775,7 @@ namespace LCIO2EDM4hepConv { } } - auto tracks = lcio->getTracks(); + const auto& tracks = lcio->getTracks(); for (auto t : tracks) { if (t == nullptr) { continue; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d1f7ed7e..7f5ba239 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(edmCompare SHARED src/CompareEDM4hepLCIO.cc) +add_library(edmCompare SHARED src/CompareEDM4hepLCIO.cc src/ObjectMapping.cc) target_link_libraries(edmCompare PUBLIC EDM4HEP::edm4hep ${LCIO_LIBRARIES}) target_include_directories(edmCompare PUBLIC ${LCIO_INCLUDE_DIRS}) @@ -6,3 +6,26 @@ add_executable(compare-contents compare_contents.cpp) target_link_libraries(compare-contents PRIVATE edmCompare podio::podioRootIO) target_include_directories(compare-contents PRIVATE $) + +find_program(BASH_PROGRAM bash) + +add_test(fetch_test_inputs ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/get_test_data.sh) + +add_test(standalone_ild_rec_file ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/run_standalone_converter.sh ild_higgs_rec.slcio) + +add_test(standalone_ild_dst_file ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/run_standalone_converter.sh ild_higgs_dst.slcio) + +set_tests_properties( + fetch_test_inputs + standalone_ild_rec_file + standalone_ild_dst_file + PROPERTIES + ENVIRONMENT "TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR};PATH=${CMAKE_CURRENT_BINARY_DIR}:${PROJECT_BINARY_DIR}/standalone:$ENV{PATH}" +) + +set_tests_properties( + standalone_ild_rec_file + standalone_ild_dst_file + PROPERTIES + DEPENDS fetch_test_inputs +) diff --git a/tests/compare_contents.cpp b/tests/compare_contents.cpp index 94d68fe6..754d3eab 100644 --- a/tests/compare_contents.cpp +++ b/tests/compare_contents.cpp @@ -1,4 +1,5 @@ #include "CompareEDM4hepLCIO.h" +#include "ObjectMapping.h" #include "podio/ROOTFrameReader.h" #include "podio/Frame.h" @@ -11,7 +12,7 @@ #define ASSERT_COMPARE_OR_EXIT(collType) \ if (type == #collType) { \ auto& edmcoll = edmEvent.get(name); \ - if (!compare(lcioColl, edmcoll)) { \ + if (!compare(lcioColl, edmcoll, objectMapping)) { \ std::cerr << "in collection: " << name << std::endl; \ return 1; \ } \ @@ -60,6 +61,23 @@ int main(int argc, char* argv[]) continue; } } + const auto coll = edmEvent.get(name); + if (!coll) { + std::cerr << "Collection " << name << " not present in edm4hep file" << std::endl; + return 1; + } + + if (edmEvent.get(name)->size() != lcioColl->getNumberOfElements()) { + std::cerr << "Collection " << name << " has different sizes. LCIO: " << lcioColl->getNumberOfElements() + << ", EDM4hep: " << coll->size() << std::endl; + return 1; + } + } + + const auto objectMapping = ObjectMappings::fromEvent(lcEvent, edmEvent); + + for (const auto& name : *(lcEvent->getCollectionNames())) { + const auto lcioColl = lcEvent->getCollection(name); const auto type = [&edmEvent, &name]() { const auto coll = edmEvent.get(name); if (coll) { @@ -68,10 +86,6 @@ int main(int argc, char* argv[]) static const decltype(coll->getTypeName()) empty = ""; return empty; }(); - if (type.empty()) { - std::cerr << "Collection " << name << " not present in edm4hep file" << std::endl; - return 1; - } ASSERT_COMPARE_OR_EXIT(edm4hep::MCParticleCollection) ASSERT_COMPARE_OR_EXIT(edm4hep::ReconstructedParticleCollection) diff --git a/tests/scripts/get_test_data.sh b/tests/scripts/get_test_data.sh new file mode 100644 index 00000000..003d25ae --- /dev/null +++ b/tests/scripts/get_test_data.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -eu + +TEST_INPUT_DIR=${TEST_DIR}/inputFiles +mkdir -p ${TEST_INPUT_DIR} + +TEST_FILES=("ild_higgs_rec.slcio" "ild_higgs_dst.slcio") + +for input_file in ${TEST_FILES[@]}; do + if [ ! -f ${TEST_INPUT_DIR}/${input_file} ]; then + echo "${input_file} test input file not yet present. Fetching it" + wget https://key4hep.web.cern.ch/testFiles/k4EDM4hep2LcioConv/ILD/${input_file} -P ${TEST_INPUT_DIR} + fi +done diff --git a/tests/scripts/run_standalone_converter.sh b/tests/scripts/run_standalone_converter.sh new file mode 100644 index 00000000..67663ce5 --- /dev/null +++ b/tests/scripts/run_standalone_converter.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +set -eu + +input_file_base=${1} + +TEST_INPUT_DIR=${TEST_DIR}/inputFiles +TEST_OUTPUT_DIR=testOutputs +mkdir -p ${TEST_OUTPUT_DIR} + +input_file=${TEST_INPUT_DIR}/${input_file_base} +output_file=${TEST_OUTPUT_DIR}/${input_file_base/.slcio/.edm4hep.root} +patch_file=${TEST_OUTPUT_DIR}/${input_file_base/.slcio/_colls.txt} + +echo "Creating the patch file for the standalone converter" +check_missing_cols --minimal ${input_file} > ${patch_file} + +echo "Running the standalone converter" +lcio2edm4hep ${input_file} ${output_file} ${patch_file} + +echo "Comparing the converted and original contents" +compare-contents ${input_file} ${output_file} diff --git a/tests/src/CompareEDM4hepLCIO.cc b/tests/src/CompareEDM4hepLCIO.cc index e9490548..5ec11710 100644 --- a/tests/src/CompareEDM4hepLCIO.cc +++ b/tests/src/CompareEDM4hepLCIO.cc @@ -1,6 +1,10 @@ #include "CompareEDM4hepLCIO.h" #include "ComparisonUtils.h" +#include "IMPL/TrackerHitImpl.h" + +#include + /** * The basic implementation of the functionality has been generated via modified * podio templates, employing some handwritten macros to facilitate the task. @@ -18,13 +22,27 @@ * TODO: Also compare relations */ +/// Convert the two 32 bit cellIDs into one 64 bit value +template +auto to64BitCellID(LcioT* obj) +{ + const auto cellID0 = obj->getCellID0(); + const auto cellID1 = obj->getCellID1(); + uint64_t cellID = cellID1; + cellID = (cellID << 32) | cellID0; + return cellID; +} + // ================= CalorimeterHit ================ -bool compare(const EVENT::CalorimeterHit* lcioElem, const edm4hep::CalorimeterHit& edm4hepElem) +bool compare( + const EVENT::CalorimeterHit* lcioElem, + const edm4hep::CalorimeterHit& edm4hepElem, + const ObjectMappings& objectMaps) { - // TODO: cellID vs. cellID0 and cellID1 in LCIO - // ASSERT_COMPARE(lcioElem, edm4hepElem, getCellID, "cellID in - // CalorimeterHit"); + const auto lcioCellID = to64BitCellID(lcioElem); + ASSERT_COMPARE_VALS(lcioCellID, edm4hepElem.getCellID(), "cellID in CalorimeterHit"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getEnergy, "energy in CalorimeterHit"); ASSERT_COMPARE(lcioElem, edm4hepElem, getEnergyError, "energyError in CalorimeterHit"); ASSERT_COMPARE(lcioElem, edm4hepElem, getTime, "time in CalorimeterHit"); @@ -33,14 +51,17 @@ bool compare(const EVENT::CalorimeterHit* lcioElem, const edm4hep::CalorimeterHi return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::CalorimeterHitCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::CalorimeterHitCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } // ================= Cluster ================ -bool compare(const EVENT::Cluster* lcioElem, const edm4hep::Cluster& edm4hepElem) +bool compare(const EVENT::Cluster* lcioElem, const edm4hep::Cluster& edm4hepElem, const ObjectMappings& objectMaps) { ASSERT_COMPARE(lcioElem, edm4hepElem, getType, "type in Cluster"); ASSERT_COMPARE(lcioElem, edm4hepElem, getEnergy, "energy in Cluster"); @@ -48,20 +69,26 @@ bool compare(const EVENT::Cluster* lcioElem, const edm4hep::Cluster& edm4hepElem ASSERT_COMPARE(lcioElem, edm4hepElem, getPosition, "position in Cluster"); ASSERT_COMPARE(lcioElem, edm4hepElem, getPositionError, "positionError in Cluster"); ASSERT_COMPARE(lcioElem, edm4hepElem, getITheta, "iTheta in Cluster"); - // TODO: LCIO has getIPhi not get Phi - // ASSERT_COMPARE(lcioElem, edm4hepElem, getPhi, "phi in Cluster"); + // LCIO has getIPhi and EDM4hep has getPhi + ASSERT_COMPARE_VALS(lcioElem->getIPhi(), edm4hepElem.getPhi(), "phi in Cluster"); ASSERT_COMPARE(lcioElem, edm4hepElem, getDirectionError, "directionError in Cluster"); return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::ClusterCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::ClusterCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } // ================= MCParticle ================ -bool compare(const EVENT::MCParticle* lcioElem, const edm4hep::MCParticle& edm4hepElem) +bool compare( + const EVENT::MCParticle* lcioElem, + const edm4hep::MCParticle& edm4hepElem, + const ObjectMappings& objectMaps) { ASSERT_COMPARE(lcioElem, edm4hepElem, getPDG, "PDG in MCParticle"); ASSERT_COMPARE(lcioElem, edm4hepElem, getGeneratorStatus, "generatorStatus in MCParticle"); @@ -85,51 +112,61 @@ bool compare(const EVENT::MCParticle* lcioElem, const edm4hep::MCParticle& edm4h ASSERT_COMPARE(lcioElem, edm4hepElem, getMomentumAtEndpoint, "momentumAtEndpoint in MCParticle"); ASSERT_COMPARE(lcioElem, edm4hepElem, getSpin, "spin in MCParticle"); ASSERT_COMPARE(lcioElem, edm4hepElem, getColorFlow, "colorFlow in MCParticle"); + + ASSERT_COMPARE_RELATION(lcioElem, edm4hepElem, getDaughters, objectMaps.mcParticles, "daughters in MCParticle"); + ASSERT_COMPARE_RELATION(lcioElem, edm4hepElem, getParents, objectMaps.mcParticles, "parents in MCParticle"); + return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::MCParticleCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::MCParticleCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } // ================= ParticleID ================ -// bool compare(const EVENT::ParticleID * lcioElem, const edm4hep::ParticleID & -// edm4hepElem) { -// ASSERT_COMPARE(lcioElem, edm4hepElem, getType, "type in ParticleID"); -// ASSERT_COMPARE(lcioElem, edm4hepElem, getPDG, "PDG in ParticleID"); -// ASSERT_COMPARE(lcioElem, edm4hepElem, getAlgorithmType, "algorithmType in -// ParticleID"); ASSERT_COMPARE(lcioElem, edm4hepElem, getLikelihood, -// "likelihood in ParticleID"); return true; -// } -// -// bool compare(const lcio::LCCollection* lcioCollection, const -// edm4hep::ParticleIDCollection& edm4hepCollection) { -// return compareCollection(lcioCollection, -// edm4hepCollection); -// } +bool compare(const EVENT::ParticleID* lcioElem, const edm4hep::ParticleID& edm4hepElem) +{ + ASSERT_COMPARE(lcioElem, edm4hepElem, getType, "type in ParticleID"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getPDG, "PDG in ParticleID"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getAlgorithmType, "algorithmType in ParticleID"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getLikelihood, "likelihood in ParticleID"); + return true; +} // ================= RawCalorimeterHit ================ -bool compare(const EVENT::RawCalorimeterHit* lcioElem, const edm4hep::RawCalorimeterHit& edm4hepElem) +bool compare( + const EVENT::RawCalorimeterHit* lcioElem, + const edm4hep::RawCalorimeterHit& edm4hepElem, + const ObjectMappings& objectMaps) { - // TODO: LCIO has getCellID0 and getCellID1 - // ASSERT_COMPARE(lcioElem, edm4hepElem, getCellID, - // "cellID in RawCalorimeterHit"); + const auto lcioCellID = to64BitCellID(lcioElem); + ASSERT_COMPARE_VALS(lcioCellID, edm4hepElem.getCellID(), "cellID in RawCalorimeterHit"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getAmplitude, "amplitude in RawCalorimeterHit"); ASSERT_COMPARE(lcioElem, edm4hepElem, getTimeStamp, "timeStamp in RawCalorimeterHit"); return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::RawCalorimeterHitCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::RawCalorimeterHitCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } // ================= ReconstructedParticle ================ -bool compare(const EVENT::ReconstructedParticle* lcioElem, const edm4hep::ReconstructedParticle& edm4hepElem) +bool compare( + const EVENT::ReconstructedParticle* lcioElem, + const edm4hep::ReconstructedParticle& edm4hepElem, + const ObjectMappings& objectMaps) { ASSERT_COMPARE(lcioElem, edm4hepElem, getType, "type in ReconstructedParticle"); ASSERT_COMPARE(lcioElem, edm4hepElem, getEnergy, "energy in ReconstructedParticle"); @@ -139,36 +176,104 @@ bool compare(const EVENT::ReconstructedParticle* lcioElem, const edm4hep::Recons ASSERT_COMPARE(lcioElem, edm4hepElem, getMass, "mass in ReconstructedParticle"); ASSERT_COMPARE(lcioElem, edm4hepElem, getGoodnessOfPID, "goodnessOfPID in ReconstructedParticle"); ASSERT_COMPARE(lcioElem, edm4hepElem, getCovMatrix, "covMatrix in ReconstructedParticle"); + + ASSERT_COMPARE_RELATION(lcioElem, edm4hepElem, getClusters, objectMaps.clusters, "clusters in ReonstructedParticle"); + ASSERT_COMPARE_RELATION(lcioElem, edm4hepElem, getTracks, objectMaps.tracks, "tracks in ReonstructedParticle"); + ASSERT_COMPARE_RELATION( + lcioElem, edm4hepElem, getParticles, objectMaps.recoParticles, "particles in ReonstructedParticle"); + ASSERT_COMPARE_RELATION( + lcioElem, edm4hepElem, getStartVertex, objectMaps.vertices, "startVertex in ReconstructedParticle"); + + const auto& lcioPIDs = lcioElem->getParticleIDs(); + const auto edmPIDs = edm4hepElem.getParticleIDs(); + ASSERT_COMPARE_VALS(lcioPIDs.size(), edmPIDs.size(), "particleIDs with different sizes in ReconstructedParticle"); + + for (size_t i = 0; i < lcioPIDs.size(); ++i) { + if (!compare(lcioPIDs[i], edmPIDs[i])) { + std::cerr << "particle ID " << i << " differs in ReconstructedParticle (LCIO: " << lcioPIDs[i] + << ", EDM4hep: " << edmPIDs[i] << ")" << std::endl; + return false; + } + } + + const auto lcioPIDUsed = lcioElem->getParticleIDUsed(); + const auto edmPIDUsed = edm4hepElem.getParticleIDUsed(); + if (lcioPIDUsed == nullptr) { + if (edmPIDUsed.isAvailable()) { + std::cerr << "particleIDUsed is not available in LCIO, but points to " << edmPIDUsed.getObjectID() + << " in EDM4hep for ReconstructedParticle" << std::endl; + return false; + } + } + else { + if (!compare(lcioPIDUsed, edmPIDUsed)) { + std::cerr << "particleIDUsed differs in ReconstructedParticle (LCIO: " << lcioPIDUsed + << ", EDM4hep: " << edmPIDUsed << ")" << std::endl; + return false; + } + } return true; } bool compare( const lcio::LCCollection* lcioCollection, - const edm4hep::ReconstructedParticleCollection& edm4hepCollection) + const edm4hep::ReconstructedParticleCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } // ================= SimCalorimeterHit ================ -bool compare(const EVENT::SimCalorimeterHit* lcioElem, const edm4hep::SimCalorimeterHit& edm4hepElem) +bool compare( + const EVENT::SimCalorimeterHit* lcioElem, + const edm4hep::SimCalorimeterHit& edm4hepElem, + const ObjectMappings& objectMaps) { - // TODO: LCIO has getCellID0 and getCellID1 - // ASSERT_COMPARE(lcioElem, edm4hepElem, getCellID, - // "cellID in SimCalorimeterHit"); + const auto lcioCellID = to64BitCellID(lcioElem); + ASSERT_COMPARE_VALS(lcioCellID, edm4hepElem.getCellID(), "cellID in SimCalorimeterHit"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getEnergy, "energy in SimCalorimeterHit"); ASSERT_COMPARE(lcioElem, edm4hepElem, getPosition, "position in SimCalorimeterHit"); + + // Contributions are not part of the "proper LCIO" + const auto edmContributions = edm4hepElem.getContributions(); + ASSERT_COMPARE_VALS(lcioElem->getNMCContributions(), edmContributions.size(), "number of CaloHitContributions"); + + for (int iCont = 0; iCont < lcioElem->getNMCContributions(); ++iCont) { + const auto& edmContrib = edmContributions[iCont]; + ASSERT_COMPARE_VALS( + lcioElem->getEnergyCont(iCont), edmContrib.getEnergy(), "energy in CaloHitContribution " << iCont); + ASSERT_COMPARE_VALS( + lcioElem->getStepPosition(iCont), edmContrib.getStepPosition(), "stepPosition in CaloHitContribution " << iCont); + ASSERT_COMPARE_VALS(lcioElem->getTimeCont(iCont), edmContrib.getTime(), "time in CaloHitContribution " << iCont); + + if (!compareRelation( + lcioElem->getParticleCont(iCont), + edmContrib.getParticle(), + objectMaps.mcParticles, + " MCParticle in CaloHitContribution " + std::to_string(iCont))) { + return false; + } + } + return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::SimCalorimeterHitCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::SimCalorimeterHitCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } // ================= SimTrackerHit ================ -bool compare(const EVENT::SimTrackerHit* lcioElem, const edm4hep::SimTrackerHit& edm4hepElem) +bool compare( + const EVENT::SimTrackerHit* lcioElem, + const edm4hep::SimTrackerHit& edm4hepElem, + const ObjectMappings& objectMaps) { ASSERT_COMPARE(lcioElem, edm4hepElem, getCellID, "cellID in SimTrackerHit"); ASSERT_COMPARE(lcioElem, edm4hepElem, getEDep, "EDep in SimTrackerHit"); @@ -177,17 +282,23 @@ bool compare(const EVENT::SimTrackerHit* lcioElem, const edm4hep::SimTrackerHit& ASSERT_COMPARE(lcioElem, edm4hepElem, getQuality, "quality in SimTrackerHit"); ASSERT_COMPARE(lcioElem, edm4hepElem, getPosition, "position in SimTrackerHit"); ASSERT_COMPARE(lcioElem, edm4hepElem, getMomentum, "momentum in SimTrackerHit"); + + ASSERT_COMPARE_RELATION(lcioElem, edm4hepElem, getMCParticle, objectMaps.mcParticles, "MCParticle in SimTrackerHit"); + return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::SimTrackerHitCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::SimTrackerHitCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } // ================= TPCHit ================ -bool compare(const EVENT::TPCHit* lcioElem, const edm4hep::RawTimeSeries& edm4hepElem) +bool compare(const EVENT::TPCHit* lcioElem, const edm4hep::RawTimeSeries& edm4hepElem, const ObjectMappings& objectMaps) { ASSERT_COMPARE(lcioElem, edm4hepElem, getCellID, "cellID in TPCHit"); ASSERT_COMPARE(lcioElem, edm4hepElem, getQuality, "quality in TPCHit"); @@ -196,36 +307,104 @@ bool compare(const EVENT::TPCHit* lcioElem, const edm4hep::RawTimeSeries& edm4he return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::RawTimeSeriesCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::RawTimeSeriesCollection& edm4hepCollection, + const ObjectMappings& objectMaps) +{ + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); +} + +// ================= TrackState ================ + +bool compare(const EVENT::TrackState* lcio, const edm4hep::TrackState& edm4hep) { - return compareCollection(lcioCollection, edm4hepCollection); + ASSERT_COMPARE_VALS(lcio->getLocation(), edm4hep.location, "location in TrackState"); + ASSERT_COMPARE_VALS(lcio->getD0(), edm4hep.D0, "D0 in TrackState"); + ASSERT_COMPARE_VALS(lcio->getZ0(), edm4hep.Z0, "Z0 in TrackState"); + ASSERT_COMPARE_VALS(lcio->getPhi(), edm4hep.phi, "phi in TrackState"); + ASSERT_COMPARE_VALS(lcio->getOmega(), edm4hep.omega, "omega in TrackState"); + ASSERT_COMPARE_VALS(lcio->getTanLambda(), edm4hep.tanLambda, "tanLambda in TrackState"); + ASSERT_COMPARE_VALS(lcio->getReferencePoint(), edm4hep.referencePoint, "referencePoint in TrackState"); + + // Need to make sure to only compare the part of the covariance matrix that is + // actually available in LCIO + const auto& lcioCov = lcio->getCovMatrix(); + const auto& edmCov = edm4hep.covMatrix; + ASSERT_COMPARE_VALS(lcioCov, std::vector(edmCov.begin(), edmCov.begin() + 15), "covMatrix in TrackState"); + + return true; } // ================= Track ================ -bool compare(const EVENT::Track* lcioElem, const edm4hep::Track& edm4hepElem) +bool compare(const EVENT::Track* lcioElem, const edm4hep::Track& edm4hepElem, const ObjectMappings& objectMaps) { ASSERT_COMPARE(lcioElem, edm4hepElem, getType, "type in Track"); ASSERT_COMPARE(lcioElem, edm4hepElem, getChi2, "chi2 in Track"); ASSERT_COMPARE(lcioElem, edm4hepElem, getNdf, "ndf in Track"); - // TODO: LCIO has getdEdx instead of getDEdx - // ASSERT_COMPARE(lcioElem, edm4hepElem, getDEdx, "dEdx in Track"); - // ASSERT_COMPARE(lcioElem, edm4hepElem, getDEdxError, "dEdxError in Track"); + // LCIO has getdEdx instead of getDEdx + ASSERT_COMPARE_VALS(lcioElem->getdEdx(), edm4hepElem.getDEdx(), "dEdx in Track"); + ASSERT_COMPARE_VALS(lcioElem->getdEdxError(), edm4hepElem.getDEdxError(), "dEdxError in Track"); + // Also check whether these have been corretly put into the dQQuantities + const auto dxQuantities = edm4hepElem.getDxQuantities(); + if (dxQuantities.size() != 1) { + std::cerr << "DxQuantities have not been filled correctly, expected exactly 1, got " << dxQuantities.size() + << " in Track" << std::endl; + return false; + } + ASSERT_COMPARE_VALS(lcioElem->getdEdx(), dxQuantities[0].value, "dEdx in DxQuantities in Track"); + ASSERT_COMPARE_VALS(lcioElem->getdEdxError(), dxQuantities[0].error, "dEdxError in DxQuantities in Track"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getRadiusOfInnermostHit, "radiusOfInnermostHit in Track"); + + ASSERT_COMPARE_RELATION(lcioElem, edm4hepElem, getTracks, objectMaps.tracks, "Tracks in Track"); + + const auto& lcioTrackStates = lcioElem->getTrackStates(); + const auto& edm4hepTrackStates = edm4hepElem.getTrackStates(); + ASSERT_COMPARE_VALS(lcioTrackStates.size(), edm4hepTrackStates.size(), "number of TrackStates in Track"); + for (size_t i = 0; i < lcioTrackStates.size(); ++i) { + if (!compare(lcioTrackStates[i], edm4hepTrackStates[i])) { + std::cerr << " " << i << " in Track" << std::endl; + return false; + } + } + + const auto edmHits = edm4hepElem.getTrackerHits(); + int iHit = 0; + for (const auto* lcioHit : lcioElem->getTrackerHits()) { + // In EDM4hep only TrackerHits can be used in Tracks, so here we also only + // compare those + if (dynamic_cast(lcioHit)) { + if (!compareRelation( + lcioHit, edmHits[iHit], objectMaps.trackerHits, "TrackerHit " + std::to_string(iHit) + " in Track")) { + return false; + } + iHit++; + } + } + return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::TrackCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::TrackCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } // ================= TrackerHit ================ -bool compare(const EVENT::TrackerHit* lcioElem, const edm4hep::TrackerHit& edm4hepElem) +bool compare( + const EVENT::TrackerHit* lcioElem, + const edm4hep::TrackerHit& edm4hepElem, + const ObjectMappings& objectMaps) { - // TODO: LCIO has getCellID0 and getCellID1 - // ASSERT_COMPARE(lcioElem, edm4hepElem, getCellID, "cellID in TrackerHit"); + const auto lcioCellID = to64BitCellID(lcioElem); + ASSERT_COMPARE_VALS(lcioCellID, edm4hepElem.getCellID(), "cellID in TrackerHit"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getType, "type in TrackerHit"); ASSERT_COMPARE(lcioElem, edm4hepElem, getQuality, "quality in TrackerHit"); ASSERT_COMPARE(lcioElem, edm4hepElem, getTime, "time in TrackerHit"); @@ -236,18 +415,24 @@ bool compare(const EVENT::TrackerHit* lcioElem, const edm4hep::TrackerHit& edm4h return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::TrackerHitCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::TrackerHitCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } // ================= TrackerHitPlane ================ -bool compare(const EVENT::TrackerHitPlane* lcioElem, const edm4hep::TrackerHitPlane& edm4hepElem) +bool compare( + const EVENT::TrackerHitPlane* lcioElem, + const edm4hep::TrackerHitPlane& edm4hepElem, + const ObjectMappings& objectMaps) { - // TODO: LCIO has getCellID0 and getCellID1 - // ASSERT_COMPARE(lcioElem, edm4hepElem, getCellID, "cellID in - // TrackerHitPlane"); + const auto lcioCellID = to64BitCellID(lcioElem); + ASSERT_COMPARE_VALS(lcioCellID, edm4hepElem.getCellID(), "cellID in TrackerHitPlane"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getType, "type in TrackerHitPlane"); ASSERT_COMPARE(lcioElem, edm4hepElem, getQuality, "quality in TrackerHitPlane"); ASSERT_COMPARE(lcioElem, edm4hepElem, getTime, "time in TrackerHitPlane"); @@ -255,38 +440,50 @@ bool compare(const EVENT::TrackerHitPlane* lcioElem, const edm4hep::TrackerHitPl ASSERT_COMPARE(lcioElem, edm4hepElem, getEDepError, "eDepError in TrackerHitPlane"); ASSERT_COMPARE(lcioElem, edm4hepElem, getU, "u in TrackerHitPlane"); ASSERT_COMPARE(lcioElem, edm4hepElem, getV, "v in TrackerHitPlane"); - // TODO: LCIO has getdU and getdV instead of getDu and getDv - // ASSERT_COMPARE(lcioElem, edm4hepElem, getDu, "du in TrackerHitPlane"); - // ASSERT_COMPARE(lcioElem, edm4hepElem, getDv, "dv in TrackerHitPlane"); + // LCIO has getdU and getdV instead of getDu and getDv + ASSERT_COMPARE_VALS(lcioElem->getdV(), edm4hepElem.getDv(), "dv in TrackerHitPlane"); + ASSERT_COMPARE_VALS(lcioElem->getdU(), edm4hepElem.getDu(), "du in TrackerHitPlane"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getPosition, "position in TrackerHitPlane"); ASSERT_COMPARE(lcioElem, edm4hepElem, getCovMatrix, "covMatrix in TrackerHitPlane"); return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::TrackerHitPlaneCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::TrackerHitPlaneCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } // ================= Vertex ================ -bool compare(const EVENT::Vertex* lcioElem, const edm4hep::Vertex& edm4hepElem) +bool compare(const EVENT::Vertex* lcioElem, const edm4hep::Vertex& edm4hepElem, const ObjectMappings& objectMaps) { - // TODO: LCIO has isPrimary - // ASSERT_COMPARE(lcioElem, edm4hepElem, getPrimary, "primary in Vertex"); + // LCIO has isPrimary (bool), EDM4hep has getPrimary (int32_t) + ASSERT_COMPARE_VALS(lcioElem->isPrimary(), edm4hepElem.getPrimary(), "primary in Vertex"); ASSERT_COMPARE(lcioElem, edm4hepElem, getChi2, "chi2 in Vertex"); ASSERT_COMPARE(lcioElem, edm4hepElem, getProbability, "probability in Vertex"); ASSERT_COMPARE(lcioElem, edm4hepElem, getPosition, "position in Vertex"); ASSERT_COMPARE(lcioElem, edm4hepElem, getCovMatrix, "covMatrix in Vertex"); + ASSERT_COMPARE(lcioElem, edm4hepElem, getParameters, "parameters in Vertex"); // TODO: LCIO with std::string vs. EDM4hep with int // ASSERT_COMPARE(lcioElem, edm4hepElem, getAlgorithmType, // "algorithmType in Vertex"); + + ASSERT_COMPARE_RELATION( + lcioElem, edm4hepElem, getAssociatedParticle, objectMaps.recoParticles, "associatedParticle in Vertex"); + return true; } -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::VertexCollection& edm4hepCollection) +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::VertexCollection& edm4hepCollection, + const ObjectMappings& objectMaps) { - return compareCollection(lcioCollection, edm4hepCollection); + return compareCollection(lcioCollection, edm4hepCollection, objectMaps); } bool compareEventHeader(const EVENT::LCEvent* lcevt, const podio::Frame* edmEvent) diff --git a/tests/src/CompareEDM4hepLCIO.h b/tests/src/CompareEDM4hepLCIO.h index 19f5c809..3703499d 100644 --- a/tests/src/CompareEDM4hepLCIO.h +++ b/tests/src/CompareEDM4hepLCIO.h @@ -1,6 +1,8 @@ #ifndef K4EDM4HEP2LCIOCONV_TEST_COMPAREEDM4HEPLCIO_H #define K4EDM4HEP2LCIOCONV_TEST_COMPAREEDM4HEPLCIO_H +#include "ObjectMapping.h" + #include "edm4hep/CaloHitContributionCollection.h" #include "edm4hep/CalorimeterHitCollection.h" #include "edm4hep/ClusterCollection.h" @@ -45,53 +47,96 @@ #include #include -// bool compare(const EVENT::CaloHitContribution *lcio, -// const edm4hep::CaloHitContribution &edm4hep); -// bool compare(const lcio::LCCollection *lcioCollection, -// const edm4hep::CaloHitContributionCollection &edm4hepCollection); +bool compare( + const EVENT::CalorimeterHit* lcio, + const edm4hep::CalorimeterHit& edm4hep, + const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::CalorimeterHitCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::CalorimeterHit* lcio, const edm4hep::CalorimeterHit& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::CalorimeterHitCollection& edm4hepCollection); +bool compare(const EVENT::Cluster* lcio, const edm4hep::Cluster& edm4hep, const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::ClusterCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::Cluster* lcio, const edm4hep::Cluster& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::ClusterCollection& edm4hepCollection); +bool compare(const EVENT::MCParticle* lcio, const edm4hep::MCParticle& edm4hep, const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::MCParticleCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -// bool compare(const EVENT::EventHeader *lcio, -// const edm4hep::EventHeader &edm4hep); -// bool compare(const lcio::LCCollection *lcioCollection, -// const edm4hep::EventHeaderCollection &edm4hepCollection); +bool compare( + const EVENT::RawCalorimeterHit* lcio, + const edm4hep::RawCalorimeterHit& edm4hep, + const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::RawCalorimeterHitCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::MCParticle* lcio, const edm4hep::MCParticle& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::MCParticleCollection& edm4hepCollection); +bool compare( + const EVENT::ReconstructedParticle* lcio, + const edm4hep::ReconstructedParticle& edm4hep, + const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::ReconstructedParticleCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::RawCalorimeterHit* lcio, const edm4hep::RawCalorimeterHit& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::RawCalorimeterHitCollection& edm4hepCollection); +bool compare( + const EVENT::SimCalorimeterHit* lcio, + const edm4hep::SimCalorimeterHit& edm4hep, + const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::SimCalorimeterHitCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::ReconstructedParticle* lcio, const edm4hep::ReconstructedParticle& edm4hep); +bool compare(const EVENT::SimTrackerHit* lcio, const edm4hep::SimTrackerHit& edm4hep, const ObjectMappings& objectMaps); bool compare( const lcio::LCCollection* lcioCollection, - const edm4hep::ReconstructedParticleCollection& edm4hepCollection); + const edm4hep::SimTrackerHitCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::SimCalorimeterHit* lcio, const edm4hep::SimCalorimeterHit& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::SimCalorimeterHitCollection& edm4hepCollection); +bool compare(const EVENT::TPCHit* lcio, const edm4hep::RawTimeSeries& edm4hep, const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::RawTimeSeriesCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::SimTrackerHit* lcio, const edm4hep::SimTrackerHit& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::SimTrackerHitCollection& edm4hepCollection); +bool compare(const EVENT::TrackerHit* lcio, const edm4hep::TrackerHit& edm4hep, const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::TrackerHitCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::TPCHit* lcio, const edm4hep::RawTimeSeries& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::RawTimeSeriesCollection& edm4hepCollection); +bool compare( + const EVENT::TrackerHitPlane* lcio, + const edm4hep::TrackerHitPlane& edm4hep, + const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::TrackerHitPlaneCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::TrackerHit* lcio, const edm4hep::TrackerHit& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::TrackerHitCollection& edm4hepCollection); +bool compare(const EVENT::TrackState* lcio, const edm4hep::TrackState& edm4hep); -bool compare(const EVENT::TrackerHitPlane* lcio, const edm4hep::TrackerHitPlane& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::TrackerHitPlaneCollection& edm4hepCollection); +bool compare(const EVENT::Track* lcio, const edm4hep::Track& edm4hep, const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::TrackCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::Track* lcio, const edm4hep::Track& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::TrackCollection& edm4hepCollection); +bool compare(const EVENT::Vertex* lcio, const edm4hep::Vertex& edm4hep, const ObjectMappings& objectMaps); +bool compare( + const lcio::LCCollection* lcioCollection, + const edm4hep::VertexCollection& edm4hepCollection, + const ObjectMappings& objectMaps); -bool compare(const EVENT::Vertex* lcio, const edm4hep::Vertex& edm4hep); -bool compare(const lcio::LCCollection* lcioCollection, const edm4hep::VertexCollection& edm4hepCollection); +bool compare(const EVENT::ParticleID* lcio, const edm4hep::ParticleID& edm4hep); bool compareEventHeader(const EVENT::LCEvent* lcevt, const podio::Frame* edmEvent); #endif // K4EDM4HEP2LCIOCONV_TEST_COMPAREEDM4HEPLCIO_H diff --git a/tests/src/ComparisonUtils.h b/tests/src/ComparisonUtils.h index 8525ae9a..046c1f63 100644 --- a/tests/src/ComparisonUtils.h +++ b/tests/src/ComparisonUtils.h @@ -1,6 +1,8 @@ #ifndef K4EDM4HEP2LCIOCONV_TEST_COMPARISONUTILS_H #define K4EDM4HEP2LCIOCONV_TEST_COMPARISONUTILS_H +#include "ObjectMapping.h" + #include "edm4hep/Vector2f.h" #include "edm4hep/Vector2i.h" #include "edm4hep/Vector3d.h" @@ -9,10 +11,14 @@ #include "UTIL/LCIterator.h" #include "EVENT/LCCollection.h" +#include "podio/RelationRange.h" +#include "podio/ObjectID.h" + #include #include #include #include +#include template std::ostream& printContainer(std::ostream& os, const T& cont) @@ -40,6 +46,12 @@ std::ostream& operator<<(std::ostream& os, const std::array& arr) return printContainer(os, arr); } +template +std::ostream& operator<<(std::ostream& os, const podio::RelationRange& range) +{ + return printContainer(os, range); +} + template bool operator==(const std::vector& vec, const std::array& arr) { @@ -60,6 +72,26 @@ bool operator!=(const std::vector& vec, const std::array& arr) return !(vec == arr); } +template +bool operator==(const std::vector& vec, const podio::RelationRange& range) +{ + if (vec.size() != range.size()) { + return false; + } + for (size_t i = 0; i < vec.size(); ++i) { + if (vec[i] != range[i]) { + return false; + } + } + return true; +} + +template +bool operator!=(const std::vector& vec, const podio::RelationRange& range) +{ + return !(vec == range); +} + template bool nanSafeComp(T x, U y) { @@ -122,19 +154,87 @@ VECTOR2_COMPARE(float, edm4hep::Vector2f) ASSERT_COMPARE_VALS(lcioV, edm4hepV, msg) \ } -// Compare an LCIO collection and an EDM4hep collection. Assumes that a compare -// function working with the element types is available -template -bool compareCollection(const lcio::LCCollection* lcioCollection, const EDM4hepCollT& edm4hepCollection) +/** + * Compare a single relation by checking whether the LCIO object points to the + * correct EDM4hep element (using the ObjectIDs) + */ +template +bool compareRelation(const LcioT* lcioElem, const EDM4hepT& edm4hepElem, const MapT& objectMap, const std::string& msg) { - if (lcioCollection->getNumberOfElements() != edm4hepCollection.size()) { + if (lcioElem == nullptr && edm4hepElem.isAvailable()) { + std::cerr << msg << " LCIO element is empty but edm4hep element is not" << std::endl; + } + if (const auto it = objectMap.find(lcioElem); it != objectMap.end()) { + if (!(it->second == edm4hepElem.getObjectID())) { + std::cerr << msg << " LCIO element " << lcioElem << " points to " << it->second << " but should point to " + << edm4hepElem.getObjectID() << std::endl; + return false; + } + } + else { + std::cerr << msg << " cannot find LCIO object " << lcioElem << " in object map for relation checking" << std::endl; return false; } + return true; +} + +/** + * Compare the relations in the form of a range of LCIO objects to the + * corresponding range of EDM4hep objects. This uses the LCIO object for lookup + * in the object map and then compares the object ID of the EDM4hep object. + * + * Naming is using the singular form to have an overload set in the macro below + * that dispatches this. + */ +template +bool compareRelation( + const std::vector& lcioRange, + const podio::RelationRange& edm4hepRange, + const MapT& objectMap, + const std::string& msg) +{ + if (lcioRange.size() != edm4hepRange.size()) { + // Make sure to take into account that the LCIO -> EDM4hep conversion does + // not fill relations if the original relations in LCIO were empty + const auto nonNullLcio = + std::count_if(lcioRange.begin(), lcioRange.end(), [](const auto e) { return e != nullptr; }); + if (nonNullLcio != edm4hepRange.size()) { + std::cerr << msg << " different sizes (even after taking null values into account)" << std::endl; + return false; + } + } + + for (size_t i = 0; i < edm4hepRange.size(); ++i) { + const auto lcioElem = lcioRange[i]; + const auto edm4hepElem = edm4hepRange[i]; + if (!compareRelation(lcioElem, edm4hepElem, objectMap, msg)) { + return false; + } + } + + return true; +} + +#define ASSERT_COMPARE_RELATION(lcioE, edm4hepE, func, map, msg) \ + { \ + const auto& lcioRel = lcioE->func(); \ + const auto edm4hepRel = edm4hepE.func(); \ + return compareRelation(lcioRel, edm4hepRel, map, msg); \ + } + +// Compare an LCIO collection and an EDM4hep collection. Assumes that a compare +// function working with the element types is available +template +bool compareCollection( + const lcio::LCCollection* lcioCollection, + const EDM4hepCollT& edm4hepCollection, + const ObjectMappings& objectMaps) +{ UTIL::LCIterator lcioIt(lcioCollection); int counter = 0; for (const auto edm4hepElem : edm4hepCollection) { - if (!compare(lcioIt.next(), edm4hepElem)) { + if (!compare(lcioIt.next(), edm4hepElem, objectMaps)) { std::cerr << "in Element " << counter << std::endl; return false; } diff --git a/tests/src/ObjectMapping.cc b/tests/src/ObjectMapping.cc new file mode 100644 index 00000000..ca8616ff --- /dev/null +++ b/tests/src/ObjectMapping.cc @@ -0,0 +1,89 @@ +#include "ObjectMapping.h" + +#include "EVENT/LCEvent.h" +#include "EVENT/Track.h" +#include "EVENT/TrackerHit.h" +#include "EVENT/TrackerHitPlane.h" +#include "EVENT/SimTrackerHit.h" +#include "EVENT/CalorimeterHit.h" +#include "EVENT/RawCalorimeterHit.h" +#include "EVENT/SimCalorimeterHit.h" +#include "EVENT/TPCHit.h" +#include "EVENT/Cluster.h" +#include "EVENT/Vertex.h" +#include "EVENT/ReconstructedParticle.h" +#include "EVENT/MCParticle.h" +#include "EVENT/LCEvent.h" +#include "EVENT/LCCollection.h" +#include "UTIL/LCIterator.h" + +#include "edm4hep/TrackCollection.h" +#include "edm4hep/TrackerHitCollection.h" +#include "edm4hep/TrackerHitPlaneCollection.h" +#include "edm4hep/SimTrackerHitCollection.h" +#include "edm4hep/ClusterCollection.h" +#include "edm4hep/CalorimeterHitCollection.h" +#include "edm4hep/RawCalorimeterHitCollection.h" +#include "edm4hep/SimCalorimeterHitCollection.h" +#include "edm4hep/MCParticleCollection.h" +#include "edm4hep/ReconstructedParticleCollection.h" +#include "edm4hep/RawTimeSeriesCollection.h" +#include "edm4hep/VertexCollection.h" + +#include "podio/ObjectID.h" +#include "podio/Frame.h" + +template +void fillMap(MapT& map, EVENT::LCCollection* lcioColl, const EDM4hepT& edmColl) +{ + // Simply assume that the collections have the same size here + UTIL::LCIterator lcioIt(lcioColl); + + for (const auto edmElem : edmColl) { + const auto* lcioElem = lcioIt.next(); + map.emplace(lcioElem, edmElem.getObjectID()); + } +} + +#define FILL_MAP(Type, mapName) \ + if (type == #Type) { \ + using namespace edm4hep; \ + auto& edm4hepColl = edmEvt.get(name); \ + fillMap(mapName, lcioColl, edm4hepColl); \ + } + +ObjectMappings ObjectMappings::fromEvent(EVENT::LCEvent* lcEvt, const podio::Frame& edmEvt) +{ + ObjectMappings mapping {}; + + for (const auto& name : *(lcEvt->getCollectionNames())) { + // We only use non subset collections here, because we want the "real" + // objects + const auto lcioColl = lcEvt->getCollection(name); + if (lcioColl->isSubset()) { + continue; + } + const auto type = lcioColl->getTypeName(); + if (type == "LCRelation") { + continue; + } + FILL_MAP(Track, mapping.tracks); + FILL_MAP(TrackerHit, mapping.trackerHits); + FILL_MAP(TrackerHitPlane, mapping.trackerHitPlanes); + FILL_MAP(SimTrackerHit, mapping.simTrackerHits); + FILL_MAP(Cluster, mapping.clusters); + FILL_MAP(CalorimeterHit, mapping.caloHits); + FILL_MAP(RawCalorimeterHit, mapping.rawCaloHits); + FILL_MAP(SimCalorimeterHit, mapping.simCaloHits); + FILL_MAP(MCParticle, mapping.mcParticles); + FILL_MAP(ReconstructedParticle, mapping.recoParticles); + FILL_MAP(Vertex, mapping.vertices); + // Need special treatment for TPCHit type mismatch + if (type == "TPCHit") { + auto& edm4hepColl = edmEvt.get(name); + fillMap(mapping.tpcHits, lcioColl, edm4hepColl); + } + } + + return mapping; +} diff --git a/tests/src/ObjectMapping.h b/tests/src/ObjectMapping.h new file mode 100644 index 00000000..ff382d67 --- /dev/null +++ b/tests/src/ObjectMapping.h @@ -0,0 +1,47 @@ +#ifndef K4EDM4HEP2LCIOCONV_TEST_OBJECTMAPPINGS_H +#define K4EDM4HEP2LCIOCONV_TEST_OBJECTMAPPINGS_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 LCEvent; +} // namespace EVENT + +namespace podio { + class ObjectID; + class Frame; +} // namespace podio + +struct ObjectMappings { + template + using Map = std::unordered_map; + + Map tracks {}; + Map trackerHits {}; + Map trackerHitPlanes {}; + Map simTrackerHits {}; + Map clusters {}; + Map caloHits {}; + Map rawCaloHits {}; + Map simCaloHits {}; + Map mcParticles {}; + Map recoParticles {}; + Map tpcHits {}; + Map vertices {}; + + static ObjectMappings fromEvent(EVENT::LCEvent* lcEvt, const podio::Frame& edmEvt); +}; + +#endif