Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-09 09:30:01

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 
0020 #include "services/log/Log_service.h"
0021 
0022 JEventProcessorPODIO::JEventProcessorPODIO() {
0023   SetTypeName(NAME_OF_THIS); // Provide JANA with this class's name
0024 
0025   japp->SetDefaultParameter("podio:output_file", m_output_file,
0026                             "Name of EDM4hep/podio output file to write to. Setting this will "
0027                             "cause the output file to be created and written to.");
0028 
0029   // Allow user to set PODIO:OUTPUT_FILE to "1" to specify using the default name.
0030   if (m_output_file == "1") {
0031     auto* param = japp->GetJParameterManager()->FindParameter("podio:output_file");
0032     if (param != nullptr) {
0033       param->SetValue(param->GetDefault());
0034       m_output_file = param->GetDefault();
0035     }
0036   }
0037 
0038   // Get the output directory path for creating a second copy of the output file at the end of processing.
0039   // (this is duplicating similar functionality in Juggler/Gaudi so assume it is useful).
0040   japp->SetDefaultParameter("podio:output_file_copy_dir", m_output_file_copy_dir,
0041                             "Directory name to make an additional copy of the output file to. Copy "
0042                             "will be done at end of processing. Default is empty string which "
0043                             "means do not make a copy. No check is made on path existing.");
0044 
0045   // Get the list of output collections to include/exclude
0046   std::vector<std::string> output_collections = {
0047       // Header and other metadata
0048       "EventHeader",
0049 
0050       // Truth record
0051       "MCParticles",
0052       "MCBeamElectrons",
0053       "MCBeamProtons",
0054       "MCScatteredElectrons",
0055       "MCScatteredProtons",
0056       "MCParticlesHeadOnFrameNoBeamFX",
0057 
0058       // Central tracking hits combined
0059       "CentralTrackerTruthSeeds",
0060       "CentralTrackingRecHits",
0061       "CentralTrackingRawHitAssociations",
0062       "CentralTrackSeedingResults",
0063       "CentralTrackerMeasurements",
0064 
0065       // Si tracker hits
0066       "SiBarrelTrackerRecHits",
0067       "SiBarrelVertexRecHits",
0068       "SiEndcapTrackerRecHits",
0069 
0070       "SiBarrelRawHits",
0071       "SiBarrelVertexRawHits",
0072       "SiEndcapTrackerRawHits",
0073 
0074       "SiBarrelHits",
0075       "VertexBarrelHits",
0076       "TrackerEndcapHits",
0077 
0078       "SiBarrelRawHitAssociations",
0079       "SiBarrelVertexRawHitAssociations",
0080       "SiEndcapTrackerRawHitAssociations",
0081 
0082       // TOF
0083       "TOFBarrelRecHits",
0084       "TOFEndcapRecHits",
0085 
0086       "TOFBarrelRawHits",
0087       "TOFEndcapRawHits",
0088 
0089       "TOFBarrelHits",
0090       "TOFBarrelClusterHits",
0091       "TOFBarrelADCTDC",
0092       "TOFEndcapHits",
0093 
0094       "TOFEndcapSharedHits",
0095       "TOFEndcapADCTDC",
0096 
0097       "TOFBarrelRawHitAssociations",
0098       "TOFEndcapRawHitAssociations",
0099 
0100       "CombinedTOFTruthSeededParticleIDs",
0101       "CombinedTOFParticleIDs",
0102 
0103       // DRICH
0104       "DRICHRawHits",
0105       "DRICHRawHitsAssociations",
0106       "DRICHAerogelTracks",
0107       "DRICHGasTracks",
0108       "DRICHAerogelIrtCherenkovParticleID",
0109       "DRICHGasIrtCherenkovParticleID",
0110       "DRICHTruthSeededParticleIDs",
0111       "DRICHParticleIDs",
0112 
0113       // PFRICH
0114       "RICHEndcapNRawHits",
0115       "RICHEndcapNRawHitsAssociations",
0116       "RICHEndcapNTruthSeededParticleIDs",
0117       "RICHEndcapNParticleIDs",
0118 
0119       // MPGD
0120       "MPGDBarrelRecHits",
0121       "OuterMPGDBarrelRecHits",
0122       "BackwardMPGDEndcapRecHits",
0123       "ForwardMPGDEndcapRecHits",
0124 
0125       "MPGDBarrelRawHits",
0126       "OuterMPGDBarrelRawHits",
0127       "BackwardMPGDEndcapRawHits",
0128       "ForwardMPGDEndcapRawHits",
0129 
0130       "MPGDBarrelHits",
0131       "OuterMPGDBarrelHits",
0132       "BackwardMPGDEndcapHits",
0133       "ForwardMPGDEndcapHits",
0134 
0135       "MPGDBarrelRawHitAssociations",
0136       "OuterMPGDBarrelRawHitAssociations",
0137       "BackwardMPGDEndcapRawHitAssociations",
0138       "ForwardMPGDEndcapRawHitAssociations",
0139 
0140       // LOWQ2 hits
0141       "TaggerTrackerHits",
0142       "TaggerTrackerSharedHits",
0143       "TaggerTrackerHitPulses",
0144       "TaggerTrackerCombinedPulses",
0145       "TaggerTrackerCombinedPulsesWithNoise",
0146       "TaggerTrackerRawHits",
0147       "TaggerTrackerRawHitAssociations",
0148       "TaggerTrackerM1L0ClusterPositions",
0149       "TaggerTrackerM1L1ClusterPositions",
0150       "TaggerTrackerM1L2ClusterPositions",
0151       "TaggerTrackerM1L3ClusterPositions",
0152       "TaggerTrackerM2L0ClusterPositions",
0153       "TaggerTrackerM2L1ClusterPositions",
0154       "TaggerTrackerM2L2ClusterPositions",
0155       "TaggerTrackerM2L3ClusterPositions",
0156       "TaggerTrackerM1LocalTracks",
0157       "TaggerTrackerM2LocalTracks",
0158       "TaggerTrackerM1LocalTrackAssociations",
0159       "TaggerTrackerM2LocalTrackAssociations",
0160       "TaggerTrackerLocalTracks",
0161       "TaggerTrackerLocalTrackAssociations",
0162       "TaggerTrackerReconstructedParticles",
0163       "TaggerTrackerReconstructedParticleAssociations",
0164 
0165       // Forward & Far forward hits
0166       "B0TrackerTruthSeeds",
0167       "B0TrackerRecHits",
0168       "B0TrackerRawHits",
0169       "B0TrackerHits",
0170       "B0TrackerRawHitAssociations",
0171       "B0TrackerSeedingResults",
0172       "B0TrackerMeasurements",
0173 
0174       "ForwardRomanPotRecHits",
0175       "ForwardOffMTrackerRecHits",
0176 
0177       "ForwardRomanPotRecParticles",
0178       "ForwardRomanPotStaticRecParticles",
0179       "ForwardOffMRecParticles",
0180 
0181       "ForwardRomanPotRawHits",
0182       "ForwardRomanPotRawHitAssociations",
0183       "ForwardOffMTrackerRawHits",
0184       "ForwardOffMTrackerRawHitAssociations",
0185 
0186       // Reconstructed data
0187       "GeneratedParticles",
0188       "GeneratedBreitFrameParticles",
0189       "ReconstructedParticles",
0190       "ReconstructedParticleAssociations",
0191       "ReconstructedTruthSeededChargedParticles",
0192       "ReconstructedTruthSeededChargedParticleAssociations",
0193       "ReconstructedChargedRealPIDParticles",
0194       "ReconstructedChargedRealPIDParticleIDs",
0195       "ReconstructedChargedParticles",
0196       "ReconstructedChargedParticleAssociations",
0197       "MCScatteredElectronAssociations",    // Remove if/when used internally
0198       "MCNonScatteredElectronAssociations", // Remove if/when used internally
0199       "ReconstructedBreitFrameParticles",
0200 
0201       // Central tracking
0202       "CentralTrackSegments",
0203       "CentralTrackVertices",
0204       "CentralCKFTruthSeededTrajectories",
0205       "CentralCKFTruthSeededTracks",
0206       "CentralCKFTruthSeededTrackAssociations",
0207       "CentralCKFTruthSeededTrackParameters",
0208       "CentralCKFTrajectories",
0209       "CentralCKFTracks",
0210       "CentralCKFTrackAssociations",
0211       "CentralCKFTrackParameters",
0212       // tracking properties - true seeding
0213       "CentralCKFTruthSeededTrajectoriesUnfiltered",
0214       "CentralCKFTruthSeededTracksUnfiltered",
0215       "CentralCKFTruthSeededTrackUnfilteredAssociations",
0216       "CentralCKFTruthSeededTrackParametersUnfiltered",
0217       // tracking properties - realistic seeding
0218       "CentralCKFTrajectoriesUnfiltered",
0219       "CentralCKFTracksUnfiltered",
0220       "CentralCKFTrackUnfilteredAssociations",
0221       "CentralCKFTrackParametersUnfiltered",
0222 
0223       // B0 tracking
0224       "B0TrackerCKFTruthSeededTrajectories",
0225       "B0TrackerCKFTruthSeededTracks",
0226       "B0TrackerCKFTruthSeededTrackAssociations",
0227       "B0TrackerCKFTruthSeededTrackParameters",
0228       "B0TrackerCKFTrajectories",
0229       "B0TrackerCKFTracks",
0230       "B0TrackerCKFTrackAssociations",
0231       "B0TrackerCKFTrackParameters",
0232       // tracking properties - true seeding
0233       "B0TrackerCKFTruthSeededTrajectoriesUnfiltered",
0234       "B0TrackerCKFTruthSeededTracksUnfiltered",
0235       "B0TrackerCKFTruthSeededTrackUnfilteredAssociations",
0236       "B0TrackerCKFTruthSeededTrackParametersUnfiltered",
0237       // tracking properties - realistic seeding
0238       "B0TrackerCKFTrajectoriesUnfiltered",
0239       "B0TrackerCKFTrackParametersUnfiltered",
0240       "B0TrackerCKFTracksUnfiltered",
0241       "B0TrackerCKFTrackUnfilteredAssociations",
0242 
0243       "CentralAndB0TrackVertices",
0244 
0245       // Inclusive kinematics
0246       "InclusiveKinematicsDA",
0247       "InclusiveKinematicsJB",
0248       "InclusiveKinematicsML",
0249       "InclusiveKinematicsSigma",
0250       "InclusiveKinematicseSigma", // Deprecated, use ESigma
0251       "InclusiveKinematicsESigma",
0252       "InclusiveKinematicsElectron",
0253       "InclusiveKinematicsTruth",
0254       "GeneratedJets",
0255       "GeneratedChargedJets",
0256       "GeneratedCentauroJets",
0257       "ReconstructedJets",
0258       "ReconstructedChargedJets",
0259       "ReconstructedCentauroJets",
0260       "ReconstructedElectrons",
0261       "ScatteredElectronsTruth",
0262       "ScatteredElectronsEMinusPz",
0263       "PrimaryVertices",
0264       "SecondaryVerticesHelix",
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   japp->SetDefaultParameter(
0400       "podio:output_collections", output_collections,
0401       "Comma separated list of collection names to write out. If not set, all collections will be "
0402       "written (including ones from input file). Don't set this and use "
0403       "PODIO:OUTPUT_EXCLUDE_COLLECTIONS to write everything except a selection.");
0404   japp->SetDefaultParameter("podio:output_exclude_collections", output_exclude_collections,
0405                             "Comma separated list of collection names to not write out.");
0406   japp->SetDefaultParameter(
0407       "podio:print_collections", m_collections_to_print,
0408       "Comma separated list of collection names to print to screen, e.g. for debugging.");
0409 
0410   m_output_collections =
0411       std::set<std::string>(output_collections.begin(), output_collections.end());
0412   m_output_exclude_collections =
0413       std::set<std::string>(output_exclude_collections.begin(), output_exclude_collections.end());
0414 }
0415 
0416 void JEventProcessorPODIO::Init() {
0417 
0418   auto* app = GetApplication();
0419   m_log     = app->GetService<Log_service>()->logger("JEventProcessorPODIO");
0420   m_writer  = std::make_unique<podio::ROOTWriter>(m_output_file);
0421 }
0422 
0423 void JEventProcessorPODIO::FindCollectionsToWrite(const std::shared_ptr<const JEvent>& event) {
0424 
0425   // Set up the set of collections_to_write.
0426   std::vector<std::string> all_collections = event->GetAllCollectionNames();
0427 
0428   if (m_output_collections.empty()) {
0429     // User has not specified an include list, so we include _all_ PODIO collections present in the first event.
0430     for (const std::string& col : all_collections) {
0431       if (m_output_exclude_collections.find(col) == m_output_exclude_collections.end()) {
0432         m_collections_to_write.push_back(col);
0433         m_log->debug("Persisting collection '{}'", col);
0434       }
0435     }
0436   } else {
0437     m_log->debug("Persisting podio types from includes list");
0438 
0439     // We match up the include list with what is actually present in the event
0440     std::set<std::string> all_collections_set =
0441         std::set<std::string>(all_collections.begin(), all_collections.end());
0442 
0443     // Turn regexes among output collections into actual collection names
0444     std::set<std::string> matching_collections_set;
0445     std::vector<std::regex> output_collections_regex(m_output_collections.size());
0446     std::ranges::transform(m_output_collections, output_collections_regex.begin(),
0447                            [](const std::string& r) { return std::regex(r); });
0448     std::ranges::copy_if(all_collections_set,
0449                          std::inserter(matching_collections_set, matching_collections_set.end()),
0450                          [&](const std::string& c) {
0451                            return std::ranges::any_of(
0452                                output_collections_regex,
0453 
0454                                [&](const std::regex& r) { return std::regex_match(c, r); });
0455                          });
0456 
0457     for (const auto& col : matching_collections_set) {
0458       if (m_output_exclude_collections.find(col) == m_output_exclude_collections.end()) {
0459         // Included and not excluded
0460         if (all_collections_set.find(col) == all_collections_set.end()) {
0461           // Included, but not a valid PODIO type
0462           m_log->warn("Explicitly included collection '{}' not present in factory set, omitting.",
0463                       col);
0464         } else {
0465           // Included, not excluded, and a valid PODIO type
0466           m_collections_to_write.push_back(col);
0467           m_log->info("Persisting collection '{}'", col);
0468         }
0469       }
0470     }
0471   }
0472 }
0473 
0474 void JEventProcessorPODIO::Process(const std::shared_ptr<const JEvent>& event) {
0475 
0476   // Find all collections to write from the first event
0477   std::call_once(m_is_first_event, &JEventProcessorPODIO::FindCollectionsToWrite, this, event);
0478 
0479   // Print the contents of some collections, just for debugging purposes
0480   // Do this before writing just in case writing crashes
0481   if (!m_collections_to_print.empty()) {
0482     m_log->info("========================================");
0483     m_log->info("JEventProcessorPODIO: Event {}", event->GetEventNumber());
0484     ;
0485   }
0486   for (const auto& coll_name : m_collections_to_print) {
0487     m_log->info("------------------------------");
0488     m_log->info("{}", coll_name);
0489     try {
0490       const auto* coll_ptr = event->GetCollectionBase(coll_name);
0491       if (coll_ptr == nullptr) {
0492         m_log->info("missing");
0493       } else {
0494         std::stringstream ss;
0495         coll_ptr->print(ss);
0496         m_log->info(ss.str());
0497       }
0498     } catch (std::exception& e) {
0499       m_log->info("missing");
0500     }
0501   }
0502 
0503   m_log->trace("==================================");
0504   m_log->trace("Event #{}", event->GetEventNumber());
0505 
0506   // Make sure that all factories get called that need to be written into the frame.
0507   // We need to do this for _all_ factories unless we've constrained it by using includes/excludes.
0508   // 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
0509   // is no way to add a new branch after the first event.
0510 
0511   // If we get an exception below while trying to add a factory for any
0512   // reason then mark that factory as bad and don't try running it again.
0513   // This is motivated by trying to write EcalBarrelSciGlass objects for
0514   // data simulated using the imaging calorimeter. In that case, it will
0515   // always throw an exception, but DD4hep also prints its own error message.
0516   // Thus, to prevent that error message every event, we must avoid calling
0517   // it.
0518 
0519   // Activate factories.
0520   std::vector<std::string> successful_collections;
0521   std::set<std::string> failed_collections;
0522   for (const std::string& coll : m_collections_to_write) {
0523     try {
0524       m_log->trace("Ensuring factory for collection '{}' has been called.", coll);
0525       const auto* coll_ptr = event->GetCollectionBase(coll);
0526       if (coll_ptr == nullptr) {
0527         // If a collection is missing from the frame, the podio root writer will segfault.
0528         // To avoid this, we treat this as a failing collection and omit from this point onwards.
0529         // However, this code path is expected to be unreachable because any missing collection will be
0530         // replaced with an empty collection in JFactoryPodioTFixed::Create.
0531         if (!failed_collections.contains(coll)) {
0532           m_log->error("Omitting PODIO collection '{}' because it is null", coll);
0533           failed_collections.insert(coll);
0534         }
0535       } else {
0536         m_log->trace("Including PODIO collection '{}'", coll);
0537         successful_collections.push_back(coll);
0538       }
0539     } catch (std::exception& e) {
0540       // Limit printing warning to just once per factory
0541       if (!failed_collections.contains(coll)) {
0542         m_log->error("Omitting PODIO collection '{}' due to exception: {}.", coll, e.what());
0543         failed_collections.insert(coll);
0544       }
0545     }
0546   }
0547 
0548   // Frame will contain data from all Podio factories that have been triggered,
0549   // including by the `event->GetCollectionBase(coll);` above.
0550   // Note that collections MUST be present in frame. If a collection is null, the writer will segfault.
0551   const auto* frame = event->GetSingle<podio::Frame>();
0552   {
0553     std::lock_guard<std::mutex> lock(m_mutex);
0554     m_writer->writeFrame(*frame, "events", m_collections_to_write);
0555   }
0556 }
0557 
0558 void JEventProcessorPODIO::Finish() { m_writer->finish(); }