Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 08:17:08

0001 
0002 #include "JEventProcessorPODIO.h"
0003 
0004 #include <JANA/JApplication.h>
0005 #include <JANA/JApplicationFwd.h>
0006 #include <JANA/Services/JParameterManager.h>
0007 #include <JANA/Utils/JTypeInfo.h>
0008 #include <edm4eic/EDM4eicVersion.h>
0009 #include <fmt/core.h>
0010 #include <fmt/format.h>
0011 #include <podio/CollectionBase.h>
0012 #include <podio/Frame.h>
0013 #include <podio/ROOTWriter.h>
0014 #include <algorithm>
0015 #include <exception>
0016 #include <iterator>
0017 #include <regex>
0018 #include <sstream>
0019 #include <stdexcept>
0020 
0021 #include "services/log/Log_service.h"
0022 
0023 JEventProcessorPODIO::JEventProcessorPODIO() {
0024   SetTypeName(NAME_OF_THIS); // Provide JANA with this class's name
0025 
0026   japp->SetDefaultParameter("podio:output_file", m_output_file,
0027                             "Name of EDM4hep/podio output file to write to. Setting this will "
0028                             "cause the output file to be created and written to.");
0029 
0030   // Allow user to set PODIO:OUTPUT_FILE to "1" to specify using the default name.
0031   if (m_output_file == "1") {
0032     auto* param = japp->GetJParameterManager()->FindParameter("podio:output_file");
0033     if (param != nullptr) {
0034       param->SetValue(param->GetDefault());
0035       m_output_file = param->GetDefault();
0036     }
0037   }
0038 
0039   // Get the output directory path for creating a second copy of the output file at the end of processing.
0040   // (this is duplicating similar functionality in Juggler/Gaudi so assume it is useful).
0041   japp->SetDefaultParameter("podio:output_file_copy_dir", m_output_file_copy_dir,
0042                             "Directory name to make an additional copy of the output file to. Copy "
0043                             "will be done at end of processing. Default is empty string which "
0044                             "means do not make a copy. No check is made on path existing.");
0045 
0046   // Get the list of output collections to include/exclude
0047   std::vector<std::string> output_collections = {
0048       // Header and other metadata
0049       "EventHeader",
0050 
0051       // Truth record
0052       "MCParticles",
0053       "MCBeamElectrons",
0054       "MCBeamProtons",
0055       "MCScatteredElectrons",
0056       "MCScatteredProtons",
0057       "MCParticlesHeadOnFrameNoBeamFX",
0058 
0059       // Central tracking hits combined
0060       "CentralTrackerTruthSeeds",
0061       "CentralTrackingRecHits",
0062       "CentralTrackingRawHitAssociations",
0063       "CentralTrackSeedingResults",
0064       "CentralTrackerMeasurements",
0065 
0066       // Si tracker hits
0067       "SiBarrelTrackerRecHits",
0068       "SiBarrelVertexRecHits",
0069       "SiEndcapTrackerRecHits",
0070 
0071       "SiBarrelRawHits",
0072       "SiBarrelVertexRawHits",
0073       "SiEndcapTrackerRawHits",
0074 
0075       "SiBarrelHits",
0076       "VertexBarrelHits",
0077       "TrackerEndcapHits",
0078 
0079       "SiBarrelRawHitAssociations",
0080       "SiBarrelVertexRawHitAssociations",
0081       "SiEndcapTrackerRawHitAssociations",
0082 
0083       // TOF
0084       "TOFBarrelRecHits",
0085       "TOFEndcapRecHits",
0086 
0087       "TOFBarrelRawHits",
0088       "TOFEndcapRawHits",
0089 
0090       "TOFBarrelHits",
0091       "TOFBarrelADCTDC",
0092       "TOFEndcapHits",
0093 
0094       "TOFBarrelRawHitAssociations",
0095       "TOFEndcapRawHitAssociations",
0096 
0097       "CombinedTOFTruthSeededParticleIDs",
0098       "CombinedTOFParticleIDs",
0099 
0100       // DRICH
0101       "DRICHRawHits",
0102       "DRICHRawHitsAssociations",
0103       "DRICHAerogelTracks",
0104       "DRICHGasTracks",
0105       "DRICHAerogelIrtCherenkovParticleID",
0106       "DRICHGasIrtCherenkovParticleID",
0107       "DRICHTruthSeededParticleIDs",
0108       "DRICHParticleIDs",
0109 
0110       // PFRICH
0111       "RICHEndcapNRawHits",
0112       "RICHEndcapNRawHitsAssociations",
0113       "RICHEndcapNTruthSeededParticleIDs",
0114       "RICHEndcapNParticleIDs",
0115 
0116       // MPGD
0117       "MPGDBarrelRecHits",
0118       "OuterMPGDBarrelRecHits",
0119       "BackwardMPGDEndcapRecHits",
0120       "ForwardMPGDEndcapRecHits",
0121 
0122       "MPGDBarrelRawHits",
0123       "OuterMPGDBarrelRawHits",
0124       "BackwardMPGDEndcapRawHits",
0125       "ForwardMPGDEndcapRawHits",
0126 
0127       "MPGDBarrelHits",
0128       "OuterMPGDBarrelHits",
0129       "BackwardMPGDEndcapHits",
0130       "ForwardMPGDEndcapHits",
0131 
0132       "MPGDBarrelRawHitAssociations",
0133       "OuterMPGDBarrelRawHitAssociations",
0134       "BackwardMPGDEndcapRawHitAssociations",
0135       "ForwardMPGDEndcapRawHitAssociations",
0136 
0137       // LOWQ2 hits
0138       "TaggerTrackerHits",
0139       "TaggerTrackerSharedHits",
0140       "TaggerTrackerHitPulses",
0141       "TaggerTrackerCombinedPulses",
0142       "TaggerTrackerCombinedPulsesWithNoise",
0143       "TaggerTrackerRawHits",
0144       "TaggerTrackerRawHitAssociations",
0145       "TaggerTrackerM1L0ClusterPositions",
0146       "TaggerTrackerM1L1ClusterPositions",
0147       "TaggerTrackerM1L2ClusterPositions",
0148       "TaggerTrackerM1L3ClusterPositions",
0149       "TaggerTrackerM2L0ClusterPositions",
0150       "TaggerTrackerM2L1ClusterPositions",
0151       "TaggerTrackerM2L2ClusterPositions",
0152       "TaggerTrackerM2L3ClusterPositions",
0153       "TaggerTrackerM1LocalTracks",
0154       "TaggerTrackerM2LocalTracks",
0155       "TaggerTrackerM1LocalTrackAssociations",
0156       "TaggerTrackerM2LocalTrackAssociations",
0157       "TaggerTrackerLocalTracks",
0158       "TaggerTrackerLocalTrackAssociations",
0159       "TaggerTrackerProjectedTracks",
0160       "TaggerTrackerTracks",
0161       "TaggerTrackerTrajectories",
0162       "TaggerTrackerTrackParameters",
0163       "TaggerTrackerTrackAssociations",
0164       "TaggerTrackerReconstructedParticles",
0165       "TaggerTrackerReconstructedParticleAssociations",
0166       "FarBackwardTruthSeededPhaseSpacePIDParticleIDs",
0167       "FarBackwardPhaseSpacePIDParticleIDs",
0168 
0169       // Forward & Far forward hits
0170       "B0TrackerTruthSeeds",
0171       "B0TrackerRecHits",
0172       "B0TrackerRawHits",
0173       "B0TrackerHits",
0174       "B0TrackerRawHitAssociations",
0175       "B0TrackerSeedingResults",
0176       "B0TrackerMeasurements",
0177 
0178       "ForwardRomanPotRecHits",
0179       "ForwardOffMTrackerRecHits",
0180 
0181       "ForwardRomanPotRecParticles",
0182       "ForwardOffMRecParticles",
0183 
0184       "ForwardRomanPotRawHits",
0185       "ForwardRomanPotRawHitAssociations",
0186       "ForwardOffMTrackerRawHits",
0187       "ForwardOffMTrackerRawHitAssociations",
0188 
0189       // Reconstructed data
0190       "GeneratedParticles",
0191       "GeneratedBreitFrameParticles",
0192       "ReconstructedParticles",
0193       "ReconstructedParticleAssociations",
0194       "ReconstructedTruthSeededChargedParticles",
0195       "ReconstructedTruthSeededChargedParticleAssociations",
0196       "ReconstructedChargedRealPIDParticles",
0197       "ReconstructedChargedRealPIDParticleIDs",
0198       "ReconstructedChargedParticles",
0199       "ReconstructedChargedParticleAssociations",
0200       "MCScatteredElectronAssociations",    // Remove if/when used internally
0201       "MCNonScatteredElectronAssociations", // Remove if/when used internally
0202       "ReconstructedBreitFrameParticles",
0203 
0204       // Central tracking
0205       "CentralTrackSegments",
0206       "CentralTrackVertices",
0207       "CentralCKFTruthSeededTrajectories",
0208       "CentralCKFTruthSeededTracks",
0209       "CentralCKFTruthSeededTrackAssociations",
0210       "CentralCKFTruthSeededTrackParameters",
0211       "CentralCKFTrajectories",
0212       "CentralCKFTracks",
0213       "CentralCKFTrackAssociations",
0214       "CentralCKFTrackParameters",
0215       // tracking properties - true seeding
0216       "CentralCKFTruthSeededTrajectoriesUnfiltered",
0217       "CentralCKFTruthSeededTracksUnfiltered",
0218       "CentralCKFTruthSeededTrackUnfilteredAssociations",
0219       "CentralCKFTruthSeededTrackParametersUnfiltered",
0220       // tracking properties - realistic seeding
0221       "CentralCKFTrajectoriesUnfiltered",
0222       "CentralCKFTracksUnfiltered",
0223       "CentralCKFTrackUnfilteredAssociations",
0224       "CentralCKFTrackParametersUnfiltered",
0225 
0226       // B0 tracking
0227       "B0TrackerCKFTruthSeededTrajectories",
0228       "B0TrackerCKFTruthSeededTracks",
0229       "B0TrackerCKFTruthSeededTrackAssociations",
0230       "B0TrackerCKFTruthSeededTrackParameters",
0231       "B0TrackerCKFTrajectories",
0232       "B0TrackerCKFTracks",
0233       "B0TrackerCKFTrackAssociations",
0234       "B0TrackerCKFTrackParameters",
0235       // tracking properties - true seeding
0236       "B0TrackerCKFTruthSeededTrajectoriesUnfiltered",
0237       "B0TrackerCKFTruthSeededTracksUnfiltered",
0238       "B0TrackerCKFTruthSeededTrackUnfilteredAssociations",
0239       "B0TrackerCKFTruthSeededTrackParametersUnfiltered",
0240       // tracking properties - realistic seeding
0241       "B0TrackerCKFTrajectoriesUnfiltered",
0242       "B0TrackerCKFTrackParametersUnfiltered",
0243       "B0TrackerCKFTracksUnfiltered",
0244       "B0TrackerCKFTrackUnfilteredAssociations",
0245 
0246       "CentralAndB0TrackVertices",
0247 
0248       // Inclusive kinematics
0249       "InclusiveKinematicsDA",
0250       "InclusiveKinematicsJB",
0251       "InclusiveKinematicsML",
0252       "InclusiveKinematicsSigma",
0253       "InclusiveKinematicseSigma", // Deprecated, use ESigma
0254       "InclusiveKinematicsESigma",
0255       "InclusiveKinematicsElectron",
0256       "InclusiveKinematicsTruth",
0257       "GeneratedJets",
0258       "GeneratedChargedJets",
0259       "GeneratedCentauroJets",
0260       "ReconstructedJets",
0261       "ReconstructedChargedJets",
0262       "ReconstructedCentauroJets",
0263       "ReconstructedElectrons",
0264       "ScatteredElectronsTruth",
0265       "ScatteredElectronsEMinusPz",
0266       "PrimaryVertices",
0267       "BarrelClusters",
0268       "HadronicFinalState",
0269 
0270       // Track projections
0271       "CalorimeterTrackProjections",
0272 
0273       // Ecal stuff
0274       "EcalEndcapNRawHits",
0275       "EcalEndcapNRecHits",
0276       "EcalEndcapNTruthClusters",
0277       "EcalEndcapNTruthClusterAssociations",
0278       "EcalEndcapNClusters",
0279       "EcalEndcapNClusterAssociations",
0280       "EcalEndcapNSplitMergeClusters",
0281       "EcalEndcapNSplitMergeClusterAssociations",
0282       "EcalEndcapPRawHits",
0283       "EcalEndcapPRecHits",
0284       "EcalEndcapPTruthClusters",
0285       "EcalEndcapPTruthClusterAssociations",
0286       "EcalEndcapPClusters",
0287       "EcalEndcapPClusterAssociations",
0288       "EcalEndcapPSplitMergeClusters",
0289       "EcalEndcapPSplitMergeClusterAssociations",
0290       "EcalBarrelClusters",
0291       "EcalBarrelClusterAssociations",
0292       "EcalBarrelTruthClusters",
0293       "EcalBarrelTruthClusterAssociations",
0294       "EcalBarrelImagingRawHits",
0295       "EcalBarrelImagingRecHits",
0296       "EcalBarrelImagingClusters",
0297       "EcalBarrelImagingClusterAssociations",
0298       "EcalBarrelScFiPAttenuatedHits",
0299       "EcalBarrelScFiPAttenuatedHitContributions",
0300       "EcalBarrelScFiNAttenuatedHits",
0301       "EcalBarrelScFiNAttenuatedHitContributions",
0302       "EcalBarrelScFiRawHits",
0303       "EcalBarrelScFiRecHits",
0304       "EcalBarrelScFiClusters",
0305       "EcalBarrelScFiClusterAssociations",
0306       "EcalLumiSpecRawHits",
0307       "EcalLumiSpecRecHits",
0308       "EcalLumiSpecTruthClusters",
0309       "EcalLumiSpecTruthClusterAssociations",
0310       "EcalLumiSpecClusters",
0311       "EcalLumiSpecClusterAssociations",
0312       "HcalEndcapNRawHits",
0313       "HcalEndcapNRecHits",
0314       "HcalEndcapNMergedHits",
0315       "HcalEndcapNClusters",
0316       "HcalEndcapNClusterAssociations",
0317       "HcalEndcapNSplitMergeClusters",
0318       "HcalEndcapNSplitMergeClusterAssociations",
0319       "HcalEndcapPInsertRawHits",
0320       "HcalEndcapPInsertRecHits",
0321       "HcalEndcapPInsertMergedHits",
0322       "HcalEndcapPInsertClusters",
0323       "HcalEndcapPInsertClusterAssociations",
0324       "LFHCALRawHits",
0325       "LFHCALRecHits",
0326       "LFHCALClusters",
0327       "LFHCALClusterAssociations",
0328       "LFHCALSplitMergeClusters",
0329       "LFHCALSplitMergeClusterAssociations",
0330       "HcalBarrelRawHits",
0331       "HcalBarrelRecHits",
0332       "HcalBarrelMergedHits",
0333       "HcalBarrelClusters",
0334       "HcalBarrelClusterAssociations",
0335       "HcalBarrelSplitMergeClusters",
0336       "HcalBarrelSplitMergeClusterAssociations",
0337       "B0ECalRawHits",
0338       "B0ECalRecHits",
0339       "B0ECalClusters",
0340       "B0ECalClusterAssociations",
0341       "HcalEndcapNTruthClusters",
0342       "HcalEndcapNTruthClusterAssociations",
0343       "HcalBarrelTruthClusters",
0344       "HcalBarrelTruthClusterAssociations",
0345 
0346       //ZDC Ecal
0347       "EcalFarForwardZDCRawHits",
0348       "EcalFarForwardZDCRecHits",
0349       "EcalFarForwardZDCClusters",
0350       "EcalFarForwardZDCClusterAssociations",
0351       "EcalFarForwardZDCTruthClusters",
0352       "EcalFarForwardZDCTruthClusterAssociations",
0353 
0354       //ZDC HCal
0355       "HcalFarForwardZDCRawHits",
0356       "HcalFarForwardZDCRecHits",
0357       "HcalFarForwardZDCSubcellHits",
0358       "HcalFarForwardZDCClusters",
0359       "HcalFarForwardZDCClusterAssociations",
0360       "HcalFarForwardZDCClustersBaseline",
0361       "HcalFarForwardZDCClusterAssociationsBaseline",
0362       "HcalFarForwardZDCTruthClusters",
0363       "HcalFarForwardZDCTruthClusterAssociations",
0364       "ReconstructedFarForwardZDCNeutrals",
0365       "ReconstructedFarForwardZDCLambdas",
0366       "ReconstructedFarForwardZDCLambdaDecayProductsCM",
0367 
0368       // DIRC
0369       "DIRCRawHits",
0370       "DIRCTruthSeededParticleIDs",
0371       "DIRCParticleIDs",
0372 
0373       "B0ECalRawHitAssociations",
0374       "EcalBarrelScFiRawHitAssociations",
0375       "EcalBarrelImagingRawHitAssociations",
0376       "HcalBarrelRawHitAssociations",
0377       "EcalEndcapNRawHitAssociations",
0378       "HcalEndcapNRawHitAssociations",
0379       "EcalEndcapPRawHitAssociations",
0380       "HcalEndcapPInsertRawHitAssociations",
0381       "LFHCALRawHitAssociations",
0382       "EcalLumiSpecRawHitAssociations",
0383       "EcalFarForwardZDCRawHitAssociations",
0384       "HcalFarForwardZDCRawHitAssociations",
0385 #if EDM4EIC_VERSION_MAJOR >= 8
0386       "EcalEndcapPTrackClusterMatches",
0387       "LFHCALTrackClusterMatches",
0388       "HcalEndcapPInsertClusterMatches",
0389       "EcalBarrelTrackClusterMatches",
0390       "HcalBarrelTrackClusterMatches",
0391       "EcalEndcapNTrackClusterMatches",
0392       "HcalEndcapNTrackClusterMatches",
0393 #endif
0394 
0395   };
0396   std::vector<std::string> output_exclude_collections; // need to get as vector, then convert to set
0397   std::string output_include_collections = "DEPRECATED";
0398   japp->SetDefaultParameter("podio:output_include_collections", output_include_collections,
0399                             "DEPRECATED. Use podio:output_collections instead.");
0400   if (output_include_collections != "DEPRECATED") {
0401     output_collections.clear();
0402     JParameterManager::Parse(output_include_collections, output_collections);
0403     m_output_include_collections_set = true;
0404   }
0405   japp->SetDefaultParameter(
0406       "podio:output_collections", output_collections,
0407       "Comma separated list of collection names to write out. If not set, all collections will be "
0408       "written (including ones from input file). Don't set this and use "
0409       "PODIO:OUTPUT_EXCLUDE_COLLECTIONS to write everything except a selection.");
0410   japp->SetDefaultParameter("podio:output_exclude_collections", output_exclude_collections,
0411                             "Comma separated list of collection names to not write out.");
0412   japp->SetDefaultParameter(
0413       "podio:print_collections", m_collections_to_print,
0414       "Comma separated list of collection names to print to screen, e.g. for debugging.");
0415 
0416   m_output_collections =
0417       std::set<std::string>(output_collections.begin(), output_collections.end());
0418   m_output_exclude_collections =
0419       std::set<std::string>(output_exclude_collections.begin(), output_exclude_collections.end());
0420 }
0421 
0422 void JEventProcessorPODIO::Init() {
0423 
0424   auto* app = GetApplication();
0425   m_log     = app->GetService<Log_service>()->logger("JEventProcessorPODIO");
0426   m_writer  = std::make_unique<podio::ROOTWriter>(m_output_file);
0427   // TODO: NWB: Verify that output file is writable NOW, rather than after event processing completes.
0428   //       I definitely don't trust PODIO to do this for me.
0429 
0430   if (m_output_include_collections_set) {
0431     m_log->error("The podio:output_include_collections was provided, but is deprecated. Use "
0432                  "podio:output_collections instead.");
0433     throw std::runtime_error("The podio:output_include_collections was provided, but is "
0434                              "deprecated. Use podio:output_collections instead.");
0435   }
0436 }
0437 
0438 void JEventProcessorPODIO::FindCollectionsToWrite(const std::shared_ptr<const JEvent>& event) {
0439 
0440   // Set up the set of collections_to_write.
0441   std::vector<std::string> all_collections = event->GetAllCollectionNames();
0442 
0443   if (m_output_collections.empty()) {
0444     // User has not specified an include list, so we include _all_ PODIO collections present in the first event.
0445     for (const std::string& col : all_collections) {
0446       if (m_output_exclude_collections.find(col) == m_output_exclude_collections.end()) {
0447         m_collections_to_write.push_back(col);
0448         m_log->info("Persisting collection '{}'", col);
0449       }
0450     }
0451   } else {
0452     m_log->debug("Persisting podio types from includes list");
0453 
0454     // We match up the include list with what is actually present in the event
0455     std::set<std::string> all_collections_set =
0456         std::set<std::string>(all_collections.begin(), all_collections.end());
0457 
0458     // Turn regexes among output collections into actual collection names
0459     std::set<std::string> matching_collections_set;
0460     std::vector<std::regex> output_collections_regex(m_output_collections.size());
0461     std::transform(m_output_collections.begin(), m_output_collections.end(),
0462                    output_collections_regex.begin(),
0463                    [](const std::string& r) { return std::regex(r); });
0464     std::copy_if(all_collections_set.begin(), all_collections_set.end(),
0465                  std::inserter(matching_collections_set, matching_collections_set.end()),
0466                  [&](const std::string& c) {
0467                    return std::any_of(output_collections_regex.begin(),
0468                                       output_collections_regex.end(),
0469                                       [&](const std::regex& r) { return std::regex_match(c, r); });
0470                  });
0471 
0472     for (const auto& col : matching_collections_set) {
0473       if (m_output_exclude_collections.find(col) == m_output_exclude_collections.end()) {
0474         // Included and not excluded
0475         if (all_collections_set.find(col) == all_collections_set.end()) {
0476           // Included, but not a valid PODIO type
0477           m_log->warn("Explicitly included collection '{}' not present in factory set, omitting.",
0478                       col);
0479         } else {
0480           // Included, not excluded, and a valid PODIO type
0481           m_collections_to_write.push_back(col);
0482           m_log->info("Persisting collection '{}'", col);
0483         }
0484       }
0485     }
0486   }
0487 }
0488 
0489 void JEventProcessorPODIO::Process(const std::shared_ptr<const JEvent>& event) {
0490 
0491   // Find all collections to write from the first event
0492   std::call_once(m_is_first_event, &JEventProcessorPODIO::FindCollectionsToWrite, this, event);
0493 
0494   // Print the contents of some collections, just for debugging purposes
0495   // Do this before writing just in case writing crashes
0496   if (!m_collections_to_print.empty()) {
0497     m_log->info("========================================");
0498     m_log->info("JEventProcessorPODIO: Event {}", event->GetEventNumber());
0499     ;
0500   }
0501   for (const auto& coll_name : m_collections_to_print) {
0502     m_log->info("------------------------------");
0503     m_log->info("{}", coll_name);
0504     try {
0505       const auto* coll_ptr = event->GetCollectionBase(coll_name);
0506       if (coll_ptr == nullptr) {
0507         m_log->info("missing");
0508       } else {
0509         std::stringstream ss;
0510         coll_ptr->print(ss);
0511         m_log->info(ss.str());
0512       }
0513     } catch (std::exception& e) {
0514       m_log->info("missing");
0515     }
0516   }
0517 
0518   m_log->trace("==================================");
0519   m_log->trace("Event #{}", event->GetEventNumber());
0520 
0521   // Make sure that all factories get called that need to be written into the frame.
0522   // We need to do this for _all_ factories unless we've constrained it by using includes/excludes.
0523   // Note that all collections need to be present in the first event, as podio::RootFrameWriter constrains us to write one event at a time, so there
0524   // is no way to add a new branch after the first event.
0525 
0526   // If we get an exception below while trying to add a factory for any
0527   // reason then mark that factory as bad and don't try running it again.
0528   // This is motivated by trying to write EcalBarrelSciGlass objects for
0529   // data simulated using the imaging calorimeter. In that case, it will
0530   // always throw an exception, but DD4hep also prints its own error message.
0531   // Thus, to prevent that error message every event, we must avoid calling
0532   // it.
0533 
0534   // Activate factories.
0535   std::vector<std::string> successful_collections;
0536   std::set<std::string> failed_collections;
0537   for (const std::string& coll : m_collections_to_write) {
0538     try {
0539       m_log->trace("Ensuring factory for collection '{}' has been called.", coll);
0540       const auto* coll_ptr = event->GetCollectionBase(coll);
0541       if (coll_ptr == nullptr) {
0542         // If a collection is missing from the frame, the podio root writer will segfault.
0543         // To avoid this, we treat this as a failing collection and omit from this point onwards.
0544         // However, this code path is expected to be unreachable because any missing collection will be
0545         // replaced with an empty collection in JFactoryPodioTFixed::Create.
0546         if (!failed_collections.contains(coll)) {
0547           m_log->error("Omitting PODIO collection '{}' because it is null", coll);
0548           failed_collections.insert(coll);
0549         }
0550       } else {
0551         m_log->trace("Including PODIO collection '{}'", coll);
0552         successful_collections.push_back(coll);
0553       }
0554     } catch (std::exception& e) {
0555       // Limit printing warning to just once per factory
0556       if (!failed_collections.contains(coll)) {
0557         m_log->error("Omitting PODIO collection '{}' due to exception: {}.", coll, e.what());
0558         failed_collections.insert(coll);
0559       }
0560     }
0561   }
0562 
0563   // Frame will contain data from all Podio factories that have been triggered,
0564   // including by the `event->GetCollectionBase(coll);` above.
0565   // Note that collections MUST be present in frame. If a collection is null, the writer will segfault.
0566   const auto* frame = event->GetSingle<podio::Frame>();
0567   {
0568     std::lock_guard<std::mutex> lock(m_mutex);
0569     m_writer->writeFrame(*frame, "events", m_collections_to_write);
0570   }
0571 }
0572 
0573 void JEventProcessorPODIO::Finish() {
0574   if (m_output_include_collections_set) {
0575     m_log->error("The podio:output_include_collections was provided, but is deprecated. Use "
0576                  "podio:output_collections instead.");
0577     throw std::runtime_error("The podio:output_include_collections was provided, but is "
0578                              "deprecated. Use podio:output_collections instead.");
0579   }
0580 
0581   m_writer->finish();
0582 }