Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-06 07:55:54

0001 
0002 #include <JANA/JApplication.h>
0003 #include <JANA/JEvent.h>
0004 #include <JANA/JFactorySet.h>
0005 #include <JANA/JMultifactory.h>
0006 #include <JANA/Services/JComponentManager.h>
0007 #include <JANA/Services/JParameterManager.h>
0008 #include <JANA/Utils/JTypeInfo.h>
0009 #include <catch2/catch_test_macros.hpp>
0010 #include <cstdint>
0011 #include <edm4hep/SimCalorimeterHitCollection.h>
0012 #include <fmt/core.h>
0013 #include <iostream>
0014 #include <map>
0015 #include <memory>
0016 #include <spdlog/logger.h>
0017 #include <string>
0018 #include <utility>
0019 #include <vector>
0020 
0021 #include "extensions/jana/JOmniFactory.h"
0022 #include "extensions/jana/JOmniFactoryGeneratorT.h"
0023 
0024 struct BasicTestAlgConfig {
0025   int bucket_count = 42;
0026   double threshold = 7.6;
0027 };
0028 
0029 struct BasicTestAlg : public JOmniFactory<BasicTestAlg, BasicTestAlgConfig> {
0030 
0031   PodioOutput<edm4hep::SimCalorimeterHit> output_hits_left{this, "output_hits_left"};
0032   PodioOutput<edm4hep::SimCalorimeterHit> output_hits_right{this, "output_hits_right"};
0033   Output<edm4hep::SimCalorimeterHit> output_vechits{this, "output_vechits"};
0034 
0035   ParameterRef<int> bucket_count{this, "bucket_count", config().bucket_count,
0036                                  "The total number of buckets [dimensionless]"};
0037   ParameterRef<double> threshold{this, "threshold", config().threshold,
0038                                  "The max cutoff threshold [V * A * kg^-1 * m^-2 * sec^-3]"};
0039 
0040   std::vector<OutputBase*> GetOutputs() { return this->m_outputs; }
0041 
0042   int m_init_call_count      = 0;
0043   int m_changerun_call_count = 0;
0044   int m_process_call_count   = 0;
0045 
0046   void Configure() {
0047     m_init_call_count++;
0048     logger()->info("Calling BasicTestAlg::Configure");
0049   }
0050 
0051   void ChangeRun(int32_t /* run_number */) override {
0052     m_changerun_call_count++;
0053     logger()->info("Calling BasicTestAlg::ChangeRun");
0054   }
0055 
0056   // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
0057   void Process(int32_t /* run_number */, uint64_t /* event_number */) override {
0058     m_process_call_count++;
0059     logger()->info("Calling BasicTestAlg::Process with bucket_count={}, threshold={}",
0060                    config().bucket_count, config().threshold);
0061     // Provide empty collections (as opposed to nulls) so that PODIO doesn't crash
0062     output_hits_left()  = std::make_unique<edm4hep::SimCalorimeterHitCollection>();
0063     output_hits_right() = std::make_unique<edm4hep::SimCalorimeterHitCollection>();
0064     output_vechits().push_back(new edm4hep::SimCalorimeterHit());
0065   }
0066 };
0067 
0068 template <typename OutputCollectionT, typename MultifactoryT>
0069 MultifactoryT* RetrieveMultifactory(JFactorySet* facset, std::string output_collection_name) {
0070   auto fac = facset->GetFactory(JTypeInfo::demangle<OutputCollectionT>(), output_collection_name);
0071   REQUIRE(fac != nullptr);
0072   auto helper = dynamic_cast<JMultifactoryHelperPodio<OutputCollectionT>*>(fac);
0073   REQUIRE(helper != nullptr);
0074   auto multifactory = helper->GetMultifactory();
0075   REQUIRE(multifactory != nullptr);
0076   auto typed = dynamic_cast<MultifactoryT*>(multifactory);
0077   REQUIRE(typed != nullptr);
0078   return typed;
0079 }
0080 
0081 TEST_CASE("Registering Podio outputs works") {
0082   BasicTestAlg alg;
0083   REQUIRE(alg.GetOutputs().size() == 3);
0084   REQUIRE(alg.GetOutputs()[0]->collection_names[0] == "output_hits_left");
0085   REQUIRE(alg.GetOutputs()[0]->type_name == "edm4hep::SimCalorimeterHit");
0086   REQUIRE(alg.GetOutputs()[1]->collection_names[0] == "output_hits_right");
0087   REQUIRE(alg.GetOutputs()[1]->type_name == "edm4hep::SimCalorimeterHit");
0088   REQUIRE(alg.GetOutputs()[2]->collection_names[0] == "output_vechits");
0089   REQUIRE(alg.GetOutputs()[2]->type_name == "edm4hep::SimCalorimeterHit");
0090 }
0091 
0092 TEST_CASE("Configuration object is correctly wired from untyped wiring data") {
0093   JApplication app;
0094   app.AddPlugin("log");
0095   app.Initialize();
0096   JOmniFactoryGeneratorT<BasicTestAlg> facgen(&app);
0097   facgen.AddWiring("ECalTestAlg", {}, {"ECalLeftHits", "ECalRightHits", "ECalVecHits"},
0098                    {{"threshold", "6.1"}, {"bucket_count", "22"}});
0099 
0100   JFactorySet facset;
0101   facgen.GenerateFactories(&facset);
0102   // for (auto* fac : facset.GetAllFactories()) {
0103   // std::cout << "typename=" << fac->GetFactoryName() << ", tag=" << fac->GetTag() << std::endl;
0104   // }
0105 
0106   auto* basictestalg =
0107       RetrieveMultifactory<edm4hep::SimCalorimeterHit, BasicTestAlg>(&facset, "ECalLeftHits");
0108 
0109   REQUIRE(basictestalg->threshold() == 6.1);
0110   REQUIRE(basictestalg->bucket_count() == 22);
0111 
0112   REQUIRE(basictestalg->config().threshold == 6.1);
0113   REQUIRE(basictestalg->config().bucket_count == 22);
0114 
0115   REQUIRE(basictestalg->m_init_call_count == 0);
0116 }
0117 
0118 TEST_CASE("Multiple configuration objects are correctly wired from untyped wiring data") {
0119   JApplication app;
0120   app.AddPlugin("log");
0121   app.Initialize();
0122   JOmniFactoryGeneratorT<BasicTestAlg> facgen(&app);
0123   facgen.AddWiring("BCalTestAlg", {}, {"BCalLeftHits", "BCalRightHits", "BCalVecHits"},
0124                    {{"threshold", "6.1"}, {"bucket_count", "22"}});
0125   facgen.AddWiring("CCalTestAlg", {}, {"CCalLeftHits", "CCalRightHits", "CCalVecHits"},
0126                    {{"threshold", "9.0"}, {"bucket_count", "27"}});
0127   facgen.AddWiring("ECalTestAlg", {}, {"ECalLeftHits", "ECalRightHits", "ECalVecHits"},
0128                    {{"threshold", "16.25"}, {"bucket_count", "49"}});
0129 
0130   JFactorySet facset;
0131   facgen.GenerateFactories(&facset);
0132   // for (auto* fac : facset.GetAllFactories()) {
0133   // std::cout << "typename=" << fac->GetFactoryName() << ", tag=" << fac->GetTag() << std::endl;
0134   // }
0135   auto* b = RetrieveMultifactory<edm4hep::SimCalorimeterHit, BasicTestAlg>(&facset, "BCalLeftHits");
0136   auto* c = RetrieveMultifactory<edm4hep::SimCalorimeterHit, BasicTestAlg>(&facset, "CCalLeftHits");
0137   auto* e = RetrieveMultifactory<edm4hep::SimCalorimeterHit, BasicTestAlg>(&facset, "ECalLeftHits");
0138 
0139   REQUIRE(b->threshold() == 6.1);
0140   REQUIRE(b->bucket_count() == 22);
0141   REQUIRE(b->config().threshold == 6.1);
0142   REQUIRE(b->config().bucket_count == 22);
0143 
0144   REQUIRE(c->threshold() == 9.0);
0145   REQUIRE(c->bucket_count() == 27);
0146   REQUIRE(c->config().threshold == 9.0);
0147   REQUIRE(c->config().bucket_count == 27);
0148 
0149   REQUIRE(e->threshold() == 16.25);
0150   REQUIRE(e->bucket_count() == 49);
0151   REQUIRE(e->config().threshold == 16.25);
0152   REQUIRE(e->config().bucket_count == 49);
0153 
0154   REQUIRE(b->m_init_call_count == 0);
0155   REQUIRE(c->m_init_call_count == 0);
0156   REQUIRE(e->m_init_call_count == 0);
0157 }
0158 
0159 TEST_CASE(
0160     "JParameterManager correctly understands which values are defaulted and which are overridden") {
0161   JApplication app;
0162   app.AddPlugin("log");
0163 
0164   auto* facgen = new JOmniFactoryGeneratorT<BasicTestAlg>(&app);
0165   facgen->AddWiring("FunTest", {}, {"BCalLeftHits", "BCalRightHits", "BCalVecHits"},
0166                     {{"threshold", "6.1"}, {"bucket_count", "22"}});
0167   app.Add(facgen);
0168 
0169   app.GetJParameterManager()->SetParameter("FunTest:threshold", 12.0);
0170   app.Initialize();
0171 
0172   auto event = std::make_shared<JEvent>();
0173   app.GetService<JComponentManager>()->configure_event(*event);
0174 
0175   // for (auto* fac : event->GetFactorySet()->GetAllFactories()) {
0176   // std::cout << "typename=" << fac->GetFactoryName() << ", tag=" << fac->GetTag() << std::endl;
0177   // }
0178 
0179   // Retrieve multifactory
0180   auto* b = RetrieveMultifactory<edm4hep::SimCalorimeterHit, BasicTestAlg>(event->GetFactorySet(),
0181                                                                            "BCalLeftHits");
0182 
0183   // Overrides won't happen until factory gets Init()ed. However, defaults will be applied immediately
0184   REQUIRE(b->threshold() == 6.1);
0185   REQUIRE(b->config().threshold == 6.1);
0186 
0187   // Trigger JMF::Execute(), in order to trigger Init(), in order to Configure()s all Parameter fields...
0188   auto lefthits = event->Get<edm4hep::SimCalorimeterHit>("BCalLeftHits");
0189 
0190   REQUIRE(b->threshold() == 12.0);
0191   REQUIRE(b->config().threshold == 12.0);
0192 
0193   std::cout << "Showing the full table of config parameters" << std::endl;
0194   app.GetJParameterManager()->PrintParameters(2, 1); // verbosity, strictness
0195 
0196   std::cout << "Showing only overridden config parameters" << std::endl;
0197   app.GetJParameterManager()->PrintParameters(1, 1); // verbosity, strictness
0198 }
0199 
0200 TEST_CASE("Wiring itself is correctly defaulted") {
0201   JApplication app;
0202   app.AddPlugin("log");
0203 
0204   auto* facgen = new JOmniFactoryGeneratorT<BasicTestAlg>(&app);
0205   facgen->AddWiring("FunTest", {}, {"BCalLeftHits", "BCalRightHits", "BCalVecHits"},
0206                     {{"threshold", "6.1"}});
0207   app.Add(facgen);
0208   app.Initialize();
0209 
0210   auto event = std::make_shared<JEvent>();
0211   app.GetService<JComponentManager>()->configure_event(*event);
0212 
0213   // Retrieve multifactory
0214   auto* b = RetrieveMultifactory<edm4hep::SimCalorimeterHit, BasicTestAlg>(event->GetFactorySet(),
0215                                                                            "BCalLeftHits");
0216 
0217   // Overrides won't happen until factory gets Init()ed. However, defaults will be applied immediately
0218   REQUIRE(b->bucket_count() == 42);        // Not provided by wiring
0219   REQUIRE(b->config().bucket_count == 42); // Not provided by wiring
0220 
0221   REQUIRE(b->threshold() == 6.1);        // Provided by wiring
0222   REQUIRE(b->config().threshold == 6.1); // Provided by wiring
0223 
0224   // Trigger JMF::Execute(), in order to trigger Init(), in order to Configure()s all Parameter fields...
0225   auto lefthits = event->Get<edm4hep::SimCalorimeterHit>("BCalLeftHits");
0226 
0227   // We didn't override the config values via the parameter manager, so all of these should be the same
0228   REQUIRE(b->bucket_count() == 42);        // Not provided by wiring
0229   REQUIRE(b->config().bucket_count == 42); // Not provided by wiring
0230 
0231   REQUIRE(b->threshold() == 6.1);        // Provided by wiring
0232   REQUIRE(b->config().threshold == 6.1); // Provided by wiring
0233 
0234   b->logger()->info("Showing the full table of config parameters");
0235   app.GetJParameterManager()->PrintParameters(2, 1); // verbosity, strictness
0236 
0237   b->logger()->info("Showing only overridden config parameters");
0238   // Should be empty because everything is defaulted
0239   app.GetJParameterManager()->PrintParameters(1, 1); // verbosity, strictness
0240 }
0241 
0242 struct VariadicTestAlg : public JOmniFactory<VariadicTestAlg, BasicTestAlgConfig> {
0243 
0244   PodioInput<edm4hep::SimCalorimeterHit> m_hits_in{this};
0245   VariadicPodioInput<edm4hep::SimCalorimeterHit> m_variadic_hits_in{this};
0246   PodioOutput<edm4hep::SimCalorimeterHit> m_hits_out{this};
0247 
0248   std::vector<OutputBase*> GetOutputs() { return this->m_outputs; }
0249 
0250   int m_init_call_count      = 0;
0251   int m_changerun_call_count = 0;
0252   int m_process_call_count   = 0;
0253 
0254   void Configure() {
0255     m_init_call_count++;
0256     logger()->info("Calling VariadicTestAlg::Configure");
0257   }
0258 
0259   void ChangeRun(int32_t /* run_number */) override {
0260     m_changerun_call_count++;
0261     logger()->info("Calling VariadicTestAlg::ChangeRun");
0262   }
0263 
0264   // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
0265   void Process(int32_t /* run_number */, uint64_t /* event_number */) override {
0266     m_process_call_count++;
0267     logger()->info("Calling VariadicTestAlg::Process with bucket_count={}, threshold={}",
0268                    config().bucket_count, config().threshold);
0269 
0270     REQUIRE(m_hits_in()->size() == 3);
0271     REQUIRE(m_variadic_hits_in().size() == 2);
0272     REQUIRE(m_variadic_hits_in()[0]->size() == 1);
0273     REQUIRE(m_variadic_hits_in()[1]->size() == 2);
0274 
0275     m_hits_out() = std::make_unique<edm4hep::SimCalorimeterHitCollection>();
0276     m_hits_out()->create();
0277     m_hits_out()->create();
0278     m_hits_out()->create();
0279     m_hits_out()->create();
0280   }
0281 };
0282 
0283 TEST_CASE("VariadicOmniFactoryTests") {
0284   VariadicTestAlg alg;
0285   JApplication app;
0286   app.AddPlugin("log");
0287 
0288   auto* facgen = new JOmniFactoryGeneratorT<VariadicTestAlg>(
0289       "VariadicTest", {"main_hits", "fun_hits", "funner_hits"}, {"processed_hits"}, &app);
0290   app.Add(facgen);
0291   app.Initialize();
0292 
0293   auto event = std::make_shared<JEvent>();
0294   app.GetService<JComponentManager>()->configure_event(*event);
0295 
0296   edm4hep::SimCalorimeterHitCollection mains;
0297   edm4hep::SimCalorimeterHitCollection funs;
0298   edm4hep::SimCalorimeterHitCollection funners;
0299 
0300   mains.create();
0301   mains.create();
0302   mains.create();
0303 
0304   funs.create();
0305   funners.create();
0306   funners.create();
0307 
0308   event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(mains), "main_hits");
0309   event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(funs), "fun_hits");
0310   event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(funners), "funner_hits");
0311 
0312   const auto* processed = event->GetCollection<edm4hep::SimCalorimeterHit>("processed_hits");
0313   REQUIRE(processed->size() == 4);
0314 }
0315 
0316 struct SubsetTestAlg : public JOmniFactory<SubsetTestAlg, BasicTestAlgConfig> {
0317 
0318   VariadicPodioInput<edm4hep::SimCalorimeterHit> m_left_hits_in{this};
0319   PodioInput<edm4hep::SimCalorimeterHit> m_center_hits_in{this};
0320   VariadicPodioInput<edm4hep::SimCalorimeterHit> m_right_hits_in{this};
0321   PodioOutput<edm4hep::SimCalorimeterHit> m_hits_out{this};
0322 
0323   std::vector<OutputBase*> GetOutputs() { return this->m_outputs; }
0324 
0325   void Configure() {}
0326 
0327   void ChangeRun(int32_t /* run_number */) override {}
0328 
0329   // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
0330   void Process(int32_t /* run_number */, uint64_t /* event_number */) override {
0331 
0332     // Variadic collection count constrained to be same size
0333     REQUIRE(m_left_hits_in().size() == 1);
0334     REQUIRE(m_right_hits_in().size() == 1);
0335 
0336     REQUIRE(m_left_hits_in()[0]->size() == 2);
0337     REQUIRE(m_right_hits_in()[0]->size() == 1);
0338 
0339     REQUIRE(m_center_hits_in()->size() == 3);
0340 
0341     m_hits_out() = std::make_unique<edm4hep::SimCalorimeterHitCollection>();
0342     m_hits_out()->setSubsetCollection();
0343 
0344     const auto* lhi = m_left_hits_in()[0];
0345     for (const auto& hit : *lhi) {
0346       m_hits_out()->push_back(hit);
0347     }
0348     for (const auto& hit : *m_center_hits_in()) {
0349       m_hits_out()->push_back(hit);
0350     }
0351   }
0352 };
0353 
0354 TEST_CASE("SubsetOmniFactoryTests") {
0355   JApplication app;
0356   app.AddPlugin("log");
0357 
0358   auto* facgen = new JOmniFactoryGeneratorT<SubsetTestAlg>(
0359       "SubsetTest", {"left", "center", "right"}, {"processed_hits"}, &app);
0360   app.Add(facgen);
0361   app.Initialize();
0362 
0363   auto event = std::make_shared<JEvent>();
0364   app.GetService<JComponentManager>()->configure_event(*event);
0365 
0366   edm4hep::SimCalorimeterHitCollection left;
0367   edm4hep::SimCalorimeterHitCollection center;
0368   edm4hep::SimCalorimeterHitCollection right;
0369 
0370   left.create();
0371   left.create();
0372   right.create();
0373 
0374   center.create();
0375   center.create();
0376   center.create();
0377 
0378   event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(left), "left");
0379   event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(center), "center");
0380   event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(right), "right");
0381 
0382   const auto* processed = event->GetCollection<edm4hep::SimCalorimeterHit>("processed_hits");
0383   REQUIRE(processed->size() == 5);
0384 }
0385 
0386 struct VariadicOutputTestAlg : public JOmniFactory<VariadicOutputTestAlg, BasicTestAlgConfig> {
0387 
0388   PodioInput<edm4hep::SimCalorimeterHit> m_hits_in{this};
0389 
0390   VariadicPodioOutput<edm4hep::SimCalorimeterHit> m_hits_out{this};
0391 
0392   void Configure() {}
0393   void ChangeRun(int32_t /* run_number */) override {}
0394 
0395   // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
0396   void Process(int32_t /* run_number */, uint64_t /* event_number */) override {
0397 
0398     REQUIRE(m_hits_out().size() == 2);
0399     m_hits_out()[0]->setSubsetCollection();
0400     m_hits_out()[1]->setSubsetCollection();
0401 
0402     int i = 0;
0403     for (const auto& hit : *(m_hits_in())) {
0404       m_hits_out()[i]->push_back(hit);
0405       i = (i == 1) ? 0 : 1;
0406     }
0407   }
0408 };
0409 
0410 TEST_CASE("VariadicPodioOutputTests") {
0411   JApplication app;
0412   app.AddPlugin("log");
0413 
0414   auto* facgen = new JOmniFactoryGeneratorT<VariadicOutputTestAlg>(
0415       "VariadicOutputTest", {"all_hits"}, {"left_hits", "right_hits"}, &app);
0416   app.Add(facgen);
0417   app.Initialize();
0418 
0419   auto event = std::make_shared<JEvent>();
0420   app.GetService<JComponentManager>()->configure_event(*event);
0421 
0422   edm4hep::SimCalorimeterHitCollection all_hits;
0423 
0424   all_hits.create();
0425   all_hits.create();
0426   all_hits.create();
0427 
0428   event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(all_hits), "all_hits");
0429 
0430   const auto* left_hits  = event->GetCollection<edm4hep::SimCalorimeterHit>("left_hits");
0431   const auto* right_hits = event->GetCollection<edm4hep::SimCalorimeterHit>("right_hits");
0432   REQUIRE(left_hits->size() == 2);
0433   REQUIRE(right_hits->size() == 1);
0434 }
0435 
0436 struct OptionalPodioInputTestAlg
0437     : public JOmniFactory<OptionalPodioInputTestAlg, BasicTestAlgConfig> {
0438 
0439   PodioInput<edm4hep::SimCalorimeterHit, true> m_left_hits_in{this};
0440   PodioInput<edm4hep::SimCalorimeterHit, false> m_right_hits_in{this};
0441 
0442   PodioOutput<edm4hep::SimCalorimeterHit> m_left_hits_out{this};
0443   PodioOutput<edm4hep::SimCalorimeterHit> m_right_hits_out{this};
0444 
0445   void Configure() {}
0446 
0447   void ChangeRun(int32_t /* run_number */) override {}
0448 
0449   void Process(int32_t /* run_number */, uint64_t /* event_number */) override {
0450 
0451     logger()->info("Calling OptionalPodioInputTestAlg::Process");
0452 
0453     m_left_hits_out()  = std::make_unique<edm4hep::SimCalorimeterHitCollection>();
0454     m_right_hits_out() = std::make_unique<edm4hep::SimCalorimeterHitCollection>();
0455     //Set the subset flag
0456     m_left_hits_out()->setSubsetCollection();
0457     m_right_hits_out()->setSubsetCollection();
0458 
0459     //Copy hits to output collections
0460     if (m_left_hits_in() != nullptr) {
0461       for (const auto& hit : *(m_left_hits_in())) {
0462         m_left_hits_out()->push_back(hit);
0463       }
0464     }
0465     if (m_right_hits_in() != nullptr) {
0466       for (const auto& hit : *(m_right_hits_in())) {
0467         m_right_hits_out()->push_back(hit);
0468       }
0469     }
0470   }
0471 };
0472 
0473 TEST_CASE("Optional PodioInput") {
0474   JApplication app;
0475   app.AddPlugin("log");
0476 
0477   auto* facgen = new JOmniFactoryGeneratorT<OptionalPodioInputTestAlg>(
0478       "OptionalPodioInputTest", {"left_hits", "right_hits"}, {"left_hits_out", "right_hits_out"},
0479       &app);
0480 
0481   app.Add(facgen);
0482   app.Initialize();
0483 
0484   auto event = std::make_shared<JEvent>();
0485   app.GetService<JComponentManager>()->configure_event(*event);
0486 
0487   SECTION("Both collections are set") {
0488     edm4hep::SimCalorimeterHitCollection left_hits;
0489     edm4hep::SimCalorimeterHitCollection right_hits;
0490     left_hits.create();
0491     left_hits.create();
0492     right_hits.create();
0493     event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(left_hits), "left_hits");
0494     event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(right_hits), "right_hits");
0495 
0496     const auto* left_hits_out  = event->GetCollection<edm4hep::SimCalorimeterHit>("left_hits_out");
0497     const auto* right_hits_out = event->GetCollection<edm4hep::SimCalorimeterHit>("right_hits_out");
0498     REQUIRE(left_hits_out->size() == 2);
0499     REQUIRE(right_hits_out->size() == 1);
0500   }
0501   SECTION("Left hits are not set") {
0502     edm4hep::SimCalorimeterHitCollection right_hits;
0503     right_hits.create();
0504     event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(right_hits), "right_hits");
0505 
0506     const auto* left_hits_out  = event->GetCollection<edm4hep::SimCalorimeterHit>("left_hits_out");
0507     const auto* right_hits_out = event->GetCollection<edm4hep::SimCalorimeterHit>("right_hits_out");
0508     REQUIRE(left_hits_out->empty());
0509     REQUIRE(right_hits_out->size() == 1);
0510   }
0511   SECTION("Right hits are not set") {
0512     edm4hep::SimCalorimeterHitCollection left_hits;
0513     left_hits.create();
0514     left_hits.create();
0515     event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(left_hits), "left_hits");
0516 
0517     REQUIRE_THROWS(event->GetCollection<edm4hep::SimCalorimeterHit>("left_hits_out"));
0518     REQUIRE_THROWS(event->GetCollection<edm4hep::SimCalorimeterHit>("right_hits_out"));
0519   }
0520 }
0521 
0522 struct OptionalVariadicPodioInputTestAlg
0523     : public JOmniFactory<OptionalVariadicPodioInputTestAlg, BasicTestAlgConfig> {
0524 
0525   VariadicPodioInput<edm4hep::SimCalorimeterHit, true> m_hits_in{this};
0526 
0527   PodioOutput<edm4hep::SimCalorimeterHit> m_hits_out{this};
0528 
0529   void Configure() {}
0530 
0531   void ChangeRun(int32_t /* run_number */) override {}
0532 
0533   void Process(int32_t /* run_number */, uint64_t /* event_number */) override {
0534 
0535     logger()->info("Calling OptionalVariadicPodioInputTestAlg::Process");
0536 
0537     m_hits_out() = std::make_unique<edm4hep::SimCalorimeterHitCollection>();
0538     //Set the subset flag
0539     m_hits_out()->setSubsetCollection();
0540     //Copy hits to output collections
0541     for (const auto& coll : m_hits_in()) {
0542       if (coll != nullptr) {
0543         for (const auto& hit : *coll) {
0544           m_hits_out()->push_back(hit);
0545         }
0546       }
0547     }
0548   }
0549 };
0550 
0551 TEST_CASE("Optional Variadic Podio Input") {
0552   JApplication app;
0553   app.AddPlugin("log");
0554 
0555   auto* facgen = new JOmniFactoryGeneratorT<OptionalVariadicPodioInputTestAlg>(
0556       "OptionalVariadicPodioInputTest", {"left_hits", "center_hits", "right_hits"}, {"hits_out"},
0557       &app);
0558 
0559   app.Add(facgen);
0560   app.Initialize();
0561 
0562   auto event = std::make_shared<JEvent>();
0563   app.GetService<JComponentManager>()->configure_event(*event);
0564 
0565   SECTION("All collections are set") {
0566     edm4hep::SimCalorimeterHitCollection left_hits;
0567     edm4hep::SimCalorimeterHitCollection center_hits;
0568     edm4hep::SimCalorimeterHitCollection right_hits;
0569     left_hits.create();
0570     left_hits.create();
0571     left_hits.create();
0572     center_hits.create();
0573     center_hits.create();
0574     right_hits.create();
0575     event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(left_hits), "left_hits");
0576     event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(center_hits), "center_hits");
0577     event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(right_hits), "right_hits");
0578 
0579     const auto* hits_out = event->GetCollection<edm4hep::SimCalorimeterHit>("hits_out");
0580 
0581     REQUIRE(hits_out->size() == 6);
0582   }
0583 
0584   SECTION("No collections are set") {
0585     const auto* hits_out = event->GetCollection<edm4hep::SimCalorimeterHit>("hits_out");
0586 
0587     REQUIRE(hits_out->empty());
0588   }
0589   SECTION("Only right collection is set") {
0590     edm4hep::SimCalorimeterHitCollection right_hits;
0591     right_hits.create();
0592     event->InsertCollection<edm4hep::SimCalorimeterHit>(std::move(right_hits), "right_hits");
0593 
0594     const auto* hits_out = event->GetCollection<edm4hep::SimCalorimeterHit>("hits_out");
0595     REQUIRE(hits_out->size() == 1);
0596   }
0597 }