File indexing completed on 2026-09-22 08:48:40
0001
0002
0003
0004
0005 #pragma once
0006
0007
0008
0009
0010
0011
0012
0013 #include <JANA/JEvent.h>
0014 #include <JANA/JMultifactory.h>
0015 #include <spdlog/spdlog.h>
0016 #include <spdlog/version.h>
0017 #if SPDLOG_VERSION >= 11400 && (!defined(SPDLOG_NO_TLS) || !SPDLOG_NO_TLS)
0018 #include <spdlog/mdc.h>
0019 #endif
0020
0021 #include "services/log/Log_service.h"
0022
0023 #include <string>
0024 #include <vector>
0025
0026
0027
0028
0029 template <typename T> struct PodioTypeMap {
0030 using collection_t = typename T::collection_type;
0031 using mutable_t = typename T::mutable_type;
0032 };
0033
0034 struct EmptyConfig {};
0035
0036 template <typename AlgoT, typename ConfigT = EmptyConfig>
0037 class JOmniFactory : public JMultifactory {
0038 public:
0039
0040
0041
0042
0043 struct InputBase {
0044 std::string type_name;
0045 std::vector<std::string> collection_names;
0046 bool is_variadic = false;
0047
0048 virtual void GetCollection(const JEvent& event) = 0;
0049 };
0050
0051 template <typename T, bool IsOptional = false> class Input : public InputBase {
0052
0053 std::vector<const T*> m_data;
0054
0055 public:
0056 Input(JOmniFactory* owner, std::string default_tag = "") {
0057 owner->RegisterInput(this);
0058 this->collection_names.push_back(default_tag);
0059 this->type_name = JTypeInfo::demangle<T>();
0060 }
0061
0062 const std::vector<const T*>& operator()() { return m_data; }
0063
0064 private:
0065 friend class JOmniFactory;
0066
0067 void GetCollection(const JEvent& event) {
0068 try {
0069 m_data = event.Get<T>(this->collection_names[0], !IsOptional);
0070 } catch (const JException& e) {
0071 if constexpr (!IsOptional) {
0072 throw JException("JOmniFactory: Failed to get collection %s: %s",
0073 this->collection_names[0].c_str(), e.what());
0074 }
0075 }
0076 }
0077 };
0078
0079 template <typename PodioT, bool IsOptional = false> class PodioInput : public InputBase {
0080
0081 const typename PodioTypeMap<PodioT>::collection_t* m_data;
0082
0083 public:
0084 PodioInput(JOmniFactory* owner, std::string default_collection_name = "") {
0085 owner->RegisterInput(this);
0086 this->collection_names.push_back(default_collection_name);
0087 this->type_name = JTypeInfo::demangle<PodioT>();
0088 }
0089
0090 const typename PodioTypeMap<PodioT>::collection_t* operator()() { return m_data; }
0091
0092 private:
0093 friend class JOmniFactory;
0094
0095 void GetCollection(const JEvent& event) {
0096 try {
0097 m_data = event.GetCollection<PodioT>(this->collection_names[0], !IsOptional);
0098 } catch (const JException& e) {
0099 if constexpr (!IsOptional) {
0100 throw JException("JOmniFactory: Failed to get collection %s: %s",
0101 this->collection_names[0].c_str(), e.what());
0102 }
0103 }
0104 }
0105 };
0106
0107 template <typename PodioT, bool IsOptional = false> class VariadicPodioInput : public InputBase {
0108
0109 std::vector<const typename PodioTypeMap<PodioT>::collection_t*> m_data;
0110
0111 public:
0112 VariadicPodioInput(JOmniFactory* owner, std::vector<std::string> default_names = {}) {
0113 owner->RegisterInput(this);
0114 this->collection_names = default_names;
0115 this->type_name = JTypeInfo::demangle<PodioT>();
0116 this->is_variadic = true;
0117 }
0118
0119 const std::vector<const typename PodioTypeMap<PodioT>::collection_t*> operator()() {
0120 return m_data;
0121 }
0122
0123 private:
0124 friend class JOmniFactory;
0125
0126 void GetCollection(const JEvent& event) {
0127 m_data.clear();
0128 for (auto& coll_name : this->collection_names) {
0129 try {
0130 m_data.push_back(event.GetCollection<PodioT>(coll_name, !IsOptional));
0131 } catch (const JException& e) {
0132 if constexpr (!IsOptional) {
0133 throw JException("JOmniFactory: Failed to get collection %s: %s", coll_name.c_str(),
0134 e.what());
0135 }
0136 }
0137 }
0138 }
0139 };
0140
0141 void RegisterInput(InputBase* input) { m_inputs.push_back(input); }
0142
0143
0144
0145
0146
0147 struct OutputBase {
0148 std::string type_name;
0149 std::vector<std::string> collection_names;
0150 bool is_variadic = false;
0151
0152 virtual void CreateHelperFactory(JOmniFactory& fac) = 0;
0153 virtual void SetCollection(JOmniFactory& fac) = 0;
0154 virtual void Reset() = 0;
0155 };
0156
0157 template <typename T> class Output : public OutputBase {
0158 std::vector<T*> m_data;
0159
0160 public:
0161 Output(JOmniFactory* owner, std::string default_tag_name = "") {
0162 owner->RegisterOutput(this);
0163 this->collection_names.push_back(default_tag_name);
0164 this->type_name = JTypeInfo::demangle<T>();
0165 }
0166
0167 std::vector<T*>& operator()() { return m_data; }
0168
0169 private:
0170 friend class JOmniFactory;
0171
0172 void CreateHelperFactory(JOmniFactory& fac) override {
0173 fac.DeclareOutput<T>(this->collection_names[0]);
0174 }
0175
0176 void SetCollection(JOmniFactory& fac) override {
0177 fac.SetData<T>(this->collection_names[0], this->m_data);
0178 }
0179
0180 void Reset() override { m_data.clear(); }
0181 };
0182
0183 template <typename PodioT> class PodioOutput : public OutputBase {
0184
0185 std::unique_ptr<typename PodioTypeMap<PodioT>::collection_t> m_data;
0186
0187 public:
0188 PodioOutput(JOmniFactory* owner, std::string default_collection_name = "") {
0189 owner->RegisterOutput(this);
0190 this->collection_names.push_back(default_collection_name);
0191 this->type_name = JTypeInfo::demangle<PodioT>();
0192 }
0193
0194 std::unique_ptr<typename PodioTypeMap<PodioT>::collection_t>& operator()() { return m_data; }
0195
0196 private:
0197 friend class JOmniFactory;
0198
0199 void CreateHelperFactory(JOmniFactory& fac) override {
0200 fac.DeclarePodioOutput<PodioT>(this->collection_names[0]);
0201 }
0202
0203 void SetCollection(JOmniFactory& fac) override {
0204 if (m_data == nullptr) {
0205 throw JException("JOmniFactory: SetCollection failed due to missing output collection '%s'",
0206 this->collection_names[0].c_str());
0207
0208 }
0209 fac.SetCollection<PodioT>(this->collection_names[0], std::move(this->m_data));
0210 }
0211
0212 void Reset() override {
0213 m_data = std::move(std::make_unique<typename PodioTypeMap<PodioT>::collection_t>());
0214 }
0215 };
0216
0217 template <typename PodioT> class VariadicPodioOutput : public OutputBase {
0218
0219 std::vector<std::unique_ptr<typename PodioTypeMap<PodioT>::collection_t>> m_data;
0220
0221 public:
0222 VariadicPodioOutput(JOmniFactory* owner,
0223 std::vector<std::string> default_collection_names = {}) {
0224 owner->RegisterOutput(this);
0225 this->collection_names = default_collection_names;
0226 this->type_name = JTypeInfo::demangle<PodioT>();
0227 this->is_variadic = true;
0228 }
0229
0230 std::vector<std::unique_ptr<typename PodioTypeMap<PodioT>::collection_t>>& operator()() {
0231 return m_data;
0232 }
0233
0234 private:
0235 friend class JOmniFactory;
0236
0237 void CreateHelperFactory(JOmniFactory& fac) override {
0238 for (auto& coll_name : this->collection_names) {
0239 fac.DeclarePodioOutput<PodioT>(coll_name);
0240 }
0241 }
0242
0243 void SetCollection(JOmniFactory& fac) override {
0244 if (m_data.size() != this->collection_names.size()) {
0245 throw JException("JOmniFactory: VariadicPodioOutput SetCollection failed: Declared %d "
0246 "collections, but provided %d.",
0247 this->collection_names.size(), m_data.size());
0248
0249 }
0250 std::size_t i = 0;
0251 for (auto& coll_name : this->collection_names) {
0252 fac.SetCollection<PodioT>(coll_name, std::move(this->m_data[i++]));
0253 }
0254 }
0255
0256 void Reset() override {
0257 m_data.clear();
0258 for (auto& coll_name [[maybe_unused]] : this->collection_names) {
0259 m_data.push_back(std::make_unique<typename PodioTypeMap<PodioT>::collection_t>());
0260 }
0261 }
0262 };
0263
0264 void RegisterOutput(OutputBase* output) { m_outputs.push_back(output); }
0265
0266
0267
0268
0269
0270 struct ParameterBase {
0271 std::string m_name;
0272 std::string m_description;
0273 virtual void Configure(JParameterManager& parman, const std::string& prefix) = 0;
0274 virtual void Configure(std::map<std::string, std::string> fields) = 0;
0275 };
0276
0277 template <typename T> class ParameterRef : public ParameterBase {
0278
0279 T* m_data;
0280
0281 public:
0282 ParameterRef(JOmniFactory* owner, std::string name, T& slot, std::string description = "") {
0283 owner->RegisterParameter(this);
0284 this->m_name = name;
0285 this->m_description = description;
0286 m_data = &slot;
0287 }
0288
0289 const T& operator()() { return *m_data; }
0290
0291 private:
0292 friend class JOmniFactory;
0293
0294 void Configure(JParameterManager& parman, const std::string& prefix) override {
0295 parman.SetDefaultParameter(prefix + ":" + this->m_name, *m_data, this->m_description);
0296 }
0297 void Configure(std::map<std::string, std::string> fields) override {
0298 auto it = fields.find(this->m_name);
0299 if (it != fields.end()) {
0300 const auto& value_str = it->second;
0301 JParameterManager::Parse(value_str, *m_data);
0302 }
0303 }
0304 };
0305
0306 template <typename T> class Parameter : public ParameterBase {
0307
0308 T m_data;
0309
0310 public:
0311 Parameter(JOmniFactory* owner, std::string name, T default_value, std::string description) {
0312 owner->RegisterParameter(this);
0313 this->m_name = name;
0314 this->m_description = description;
0315 m_data = default_value;
0316 }
0317
0318 const T& operator()() { return m_data; }
0319
0320 private:
0321 friend class JOmniFactory;
0322
0323 void Configure(JParameterManager& parman, const std::string& prefix) override {
0324 parman.SetDefaultParameter(prefix + ":" + this->m_name, m_data, this->m_description);
0325 }
0326 void Configure(std::map<std::string, std::string> fields) override {
0327 auto it = fields.find(this->m_name);
0328 if (it != fields.end()) {
0329 const auto& value_str = it->second;
0330 if constexpr (10000 * JVersion::major + 100 * JVersion::minor + 1 * JVersion::patch <
0331 20102) {
0332 m_data = JParameterManager::Parse<T>(value_str);
0333 } else {
0334 JParameterManager::Parse(value_str, m_data);
0335 }
0336 }
0337 }
0338 };
0339
0340 void RegisterParameter(ParameterBase* parameter) { m_parameters.push_back(parameter); }
0341
0342 void ConfigureAllParameters(std::map<std::string, std::string> fields) {
0343 for (auto* parameter : this->m_parameters) {
0344 parameter->Configure(fields);
0345 }
0346 }
0347
0348
0349
0350
0351
0352 struct ServiceBase {
0353 virtual void Init(JApplication* app) = 0;
0354 };
0355
0356 template <typename ServiceT> class Service : public ServiceBase {
0357
0358 std::shared_ptr<ServiceT> m_data;
0359
0360 public:
0361 Service(JOmniFactory* owner) { owner->RegisterService(this); }
0362
0363 ServiceT& operator()() { return *m_data; }
0364
0365 private:
0366 friend class JOmniFactory;
0367
0368 void Init(JApplication* app) { m_data = app->GetService<ServiceT>(); }
0369 };
0370
0371 void RegisterService(ServiceBase* service) { m_services.push_back(service); }
0372
0373
0374
0375
0376
0377 struct ResourceBase {
0378 virtual void ChangeRun(const JEvent& event) = 0;
0379 };
0380
0381 template <typename ServiceT, typename ResourceT, typename LambdaT>
0382 class Resource : public ResourceBase {
0383 ResourceT m_data;
0384 LambdaT m_lambda;
0385
0386 public:
0387 Resource(JOmniFactory* owner, LambdaT lambda) : m_lambda(lambda) {
0388 owner->RegisterResource(this);
0389 };
0390
0391 const ResourceT& operator()() { return m_data; }
0392
0393 private:
0394 friend class JOmniFactory;
0395
0396 void ChangeRun(const JEvent& event) {
0397 auto run_nr = event.GetRunNumber();
0398 std::shared_ptr<ServiceT> service = event.GetJApplication()->template GetService<ServiceT>();
0399 m_data = m_lambda(service, run_nr);
0400 }
0401 };
0402
0403 void RegisterResource(ResourceBase* resource) { m_resources.push_back(resource); }
0404
0405 public:
0406 std::vector<InputBase*> m_inputs;
0407 std::vector<OutputBase*> m_outputs;
0408 std::vector<ParameterBase*> m_parameters;
0409 std::vector<ServiceBase*> m_services;
0410 std::vector<ResourceBase*> m_resources;
0411
0412 private:
0413
0414 JApplication* m_app;
0415
0416
0417 std::string m_plugin_name;
0418
0419
0420 std::string m_prefix;
0421
0422
0423 std::shared_ptr<spdlog::logger> m_logger;
0424
0425
0426 ConfigT m_config;
0427
0428 public:
0429 std::size_t FindVariadicCollectionCount(std::size_t total_input_count,
0430 std::size_t variadic_input_count,
0431 std::size_t total_collection_count, bool is_input) {
0432
0433 std::size_t variadic_collection_count =
0434 total_collection_count - (total_input_count - variadic_input_count);
0435
0436 if (variadic_input_count == 0) {
0437
0438 if (total_input_count != total_collection_count) {
0439 throw JException(
0440 "JOmniFactory '%s': Wrong number of %s collection names: %d expected, %d found.",
0441 m_prefix.c_str(), (is_input ? "input" : "output"), total_input_count,
0442 total_collection_count);
0443 }
0444 } else {
0445
0446 if (total_input_count - variadic_input_count > total_collection_count) {
0447 throw JException("JOmniFactory '%s': Not enough %s collection names: %d needed, %d found.",
0448 m_prefix.c_str(), (is_input ? "input" : "output"),
0449 total_input_count - variadic_input_count, total_collection_count);
0450 }
0451
0452
0453 if (variadic_collection_count % variadic_input_count != 0) {
0454 throw JException("JOmniFactory '%s': Wrong number of %s collection names: %d found total, "
0455 "but %d can't be distributed among %d variadic inputs evenly.",
0456 m_prefix.c_str(), (is_input ? "input" : "output"), total_collection_count,
0457 variadic_collection_count, variadic_input_count);
0458 }
0459 }
0460 return variadic_collection_count;
0461 }
0462
0463 inline void PreInit(std::string tag, std::vector<std::string> default_input_collection_names,
0464 std::vector<std::string> default_output_collection_names) {
0465
0466 m_prefix = (this->GetPluginName().empty()) ? tag : this->GetPluginName() + ":" + tag;
0467
0468
0469
0470 m_app->SetDefaultParameter(m_prefix + ":InputTags", default_input_collection_names,
0471 "Input collection names");
0472 m_app->SetDefaultParameter(m_prefix + ":OutputTags", default_output_collection_names,
0473 "Output collection names");
0474
0475
0476 std::size_t variadic_input_count = 0;
0477 for (auto* input : m_inputs) {
0478 if (input->is_variadic) {
0479 variadic_input_count += 1;
0480 }
0481 }
0482 std::size_t variadic_input_collection_count = FindVariadicCollectionCount(
0483 m_inputs.size(), variadic_input_count, default_input_collection_names.size(), true);
0484
0485
0486 for (std::size_t i = 0; auto* input : m_inputs) {
0487 input->collection_names.clear();
0488 if (input->is_variadic) {
0489 for (std::size_t j = 0; j < (variadic_input_collection_count / variadic_input_count); ++j) {
0490 input->collection_names.push_back(default_input_collection_names[i++]);
0491 }
0492 } else {
0493 input->collection_names.push_back(default_input_collection_names[i++]);
0494 }
0495 }
0496
0497
0498 std::size_t variadic_output_count = 0;
0499 for (auto* output : m_outputs) {
0500 if (output->is_variadic) {
0501 variadic_output_count += 1;
0502 }
0503 }
0504 std::size_t variadic_output_collection_count = FindVariadicCollectionCount(
0505 m_outputs.size(), variadic_output_count, default_output_collection_names.size(), true);
0506
0507
0508 for (std::size_t i = 0; auto* output : m_outputs) {
0509 output->collection_names.clear();
0510 if (output->is_variadic) {
0511 for (std::size_t j = 0; j < (variadic_output_collection_count / variadic_output_count);
0512 ++j) {
0513 output->collection_names.push_back(default_output_collection_names[i++]);
0514 }
0515 } else {
0516 output->collection_names.push_back(default_output_collection_names[i++]);
0517 }
0518 output->CreateHelperFactory(*this);
0519 }
0520
0521
0522 m_logger = m_app->GetService<Log_service>()->logger(m_prefix);
0523 }
0524
0525 void Init() override {
0526 auto app = GetApplication();
0527 for (auto* parameter : m_parameters) {
0528 parameter->Configure(*(app->GetJParameterManager()), m_prefix);
0529 }
0530 for (auto* service : m_services) {
0531 service->Init(app);
0532 }
0533 static_cast<AlgoT*>(this)->Configure();
0534 }
0535
0536 void BeginRun(const std::shared_ptr<const JEvent>& event) override {
0537 for (auto* resource : m_resources) {
0538 resource->ChangeRun(*event);
0539 }
0540 static_cast<AlgoT*>(this)->ChangeRun(event->GetRunNumber());
0541 }
0542
0543 virtual void ChangeRun(int32_t ) override {};
0544
0545 virtual void Process(int32_t , uint64_t ) {};
0546
0547 void Process(const std::shared_ptr<const JEvent>& event) override {
0548 try {
0549 for (auto* input : m_inputs) {
0550 input->GetCollection(*event);
0551 }
0552 for (auto* output : m_outputs) {
0553 output->Reset();
0554 }
0555 #if SPDLOG_VERSION >= 11400 && (!defined(SPDLOG_NO_TLS) || !SPDLOG_NO_TLS)
0556 spdlog::mdc::put("e", std::to_string(event->GetEventNumber()));
0557 #endif
0558 static_cast<AlgoT*>(this)->Process(event->GetRunNumber(), event->GetEventNumber());
0559 for (auto* output : m_outputs) {
0560 output->SetCollection(*this);
0561 }
0562 } catch (std::exception& e) {
0563 throw JException(e.what());
0564 }
0565 }
0566
0567 using ConfigType = ConfigT;
0568
0569 void SetApplication(JApplication* app) { m_app = app; }
0570
0571 JApplication* GetApplication() { return m_app; }
0572
0573 void SetPluginName(std::string plugin_name) { m_plugin_name = plugin_name; }
0574
0575 std::string GetPluginName() { return m_plugin_name; }
0576
0577 inline std::string GetPrefix() { return m_prefix; }
0578
0579
0580 std::shared_ptr<spdlog::logger>& logger() { return m_logger; }
0581
0582
0583 ConfigT& config() { return m_config; }
0584 };