Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-08 09:23:22

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