diff --git a/src/libraries/JANA/Components/JWiredFactoryGeneratorT.h b/src/libraries/JANA/Components/JWiredFactoryGeneratorT.h new file mode 100644 index 000000000..c12c41d9d --- /dev/null +++ b/src/libraries/JANA/Components/JWiredFactoryGeneratorT.h @@ -0,0 +1,56 @@ +// Copyright 2025, Jefferson Science Associates, LLC. +// Subject to the terms in the LICENSE file found in the top-level directory. +// Created by Nathan Brei + +#pragma once + +#include +#include +#include + + +namespace jana::components { + +template +class JWiredFactoryGeneratorT : public JFactoryGenerator { + +public: + using FactoryConfigType = typename FactoryT::ConfigType; + + explicit JWiredFactoryGeneratorT() = default; + + void GenerateFactories(JFactorySet *factory_set) override { + + auto wiring_svc = GetApplication()->template GetService(); + const auto& type_name = JTypeInfo::demangle(); + for (const auto* wiring : wiring_svc->GetWirings(GetPluginName(), type_name)) { + + FactoryT *factory = new FactoryT; + factory->SetApplication(GetApplication()); + factory->SetPluginName(this->GetPluginName()); + factory->SetTypeName(type_name); + + // Set the parameter values on the factory. This way, the values in the wiring file + // show up as "defaults" and the values set on the command line show up as "overrides". + factory->ConfigureAllParameters(wiring->configs); + + // Check that output levels in wiring file match the factory's level + for (auto output_level : wiring->output_levels) { + if (output_level != wiring->level) { + throw JException("JOmniFactories are constrained to a single output level"); + } + } + + factory->PreInit(wiring->prefix, + wiring->level, + wiring->input_names, + wiring->input_levels, + wiring->output_names); + + factory_set->Add(factory); + } + } +}; + +} // namespace jana::components +using jana::components::JWiredFactoryGeneratorT; diff --git a/src/libraries/JANA/JApplication.cc b/src/libraries/JANA/JApplication.cc index 7fb9ae402..ee8a33033 100644 --- a/src/libraries/JANA/JApplication.cc +++ b/src/libraries/JANA/JApplication.cc @@ -48,6 +48,8 @@ JApplication::JApplication(JParameterManager* params) { ProvideService(m_execution_engine); ProvideService(std::make_shared()); ProvideService(std::make_shared()); + ProvideService(std::make_shared()); + } @@ -134,9 +136,6 @@ void JApplication::Initialize() { LOG_WARN(m_logger) << oss.str() << LOG_END; } - // Set up wiring - ProvideService(std::make_shared()); - // Attach all plugins plugin_loader->attach_plugins(component_manager.get()); @@ -152,6 +151,10 @@ void JApplication::Initialize() { topology_builder->create_topology(); auto execution_engine = m_service_locator->get(); + + // Make sure that Init() is called on any remaining JServices + m_service_locator->wire_everything(); + m_initialized = true; // This needs to be at the end so that m_initialized==false while InitPlugin() is being called } diff --git a/src/libraries/JANA/Services/JServiceLocator.h b/src/libraries/JANA/Services/JServiceLocator.h index 21cfd0218..3be0206d1 100644 --- a/src/libraries/JANA/Services/JServiceLocator.h +++ b/src/libraries/JANA/Services/JServiceLocator.h @@ -46,6 +46,7 @@ class JServiceLocator { std::lock_guard lock(mutex); auto svc = std::dynamic_pointer_cast(t); assert(svc != nullptr); + svc->SetTypeName(JTypeInfo::demangle()); underlying[std::type_index(typeid(T))] = svc; } diff --git a/src/libraries/JANA/Services/JWiringService.cc b/src/libraries/JANA/Services/JWiringService.cc index 0056e371b..5ff58ef14 100644 --- a/src/libraries/JANA/Services/JWiringService.cc +++ b/src/libraries/JANA/Services/JWiringService.cc @@ -72,7 +72,7 @@ void JWiringService::AddWirings(const toml::table& table, const std::string& sou } auto& f = *fac.as_table(); - wiring->plugin_name = f["plugin_name"].value().value(); + wiring->plugin_name = f["plugin_name"].value().value_or(""); wiring->type_name = f["type_name"].value().value(); wiring->prefix = f["prefix"].value().value(); diff --git a/src/libraries/JANA/Services/JWiringService.h b/src/libraries/JANA/Services/JWiringService.h index 75e79cd72..169bf52f8 100644 --- a/src/libraries/JANA/Services/JWiringService.h +++ b/src/libraries/JANA/Services/JWiringService.h @@ -29,7 +29,7 @@ class JWiringService : public JService { }; private: - Parameter m_wirings_input_file {this, "jana:wiring_file", "wiring.toml", + Parameter m_wirings_input_file {this, "jana:wiring_file", "", "Path to TOML file containing wiring definitions"}; Parameter m_strict_inheritance {this, "jana:wiring_strictness", true, diff --git a/src/programs/unit_tests/Services/JWiringServiceTests.cc b/src/programs/unit_tests/Services/JWiringServiceTests.cc index 84c69494c..b8ec13b12 100644 --- a/src/programs/unit_tests/Services/JWiringServiceTests.cc +++ b/src/programs/unit_tests/Services/JWiringServiceTests.cc @@ -1,4 +1,6 @@ +#include "JANA/Components/JOmniFactory.h" +#include "JANA/Components/JWiredFactoryGeneratorT.h" #include "JANA/JException.h" #include "JANA/Utils/JEventLevel.h" #include @@ -179,3 +181,85 @@ TEST_CASE("WiringTests_FakeFacGen") { REQUIRE(final_wirings[2]->configs["x"] == "27"); // from facgen only } + +struct Cluster { double x,y,E; }; + +struct WiredOmniFac : jana::components::JOmniFactory { + Input m_protoclusters_in {this}; + Output m_clusters_out {this}; + + Parameter m_x {this, "x", 1, "x"}; + Parameter m_y {this, "y", "silent", "y" }; + + void Configure() { + } + + void ChangeRun(int32_t /*run_nr*/) { + } + + void Execute(int32_t /*run_nr*/, uint64_t /*evt_nr*/) { + + for (auto protocluster : *m_protoclusters_in) { + m_clusters_out().push_back(new Cluster {protocluster->x, protocluster->y, protocluster->E + 1}); + } + } +}; + +static constexpr std::string_view realfacgen_wiring = R"( + [[factory]] + type_name = "WiredOmniFac" + prefix = "myfac" + input_names = ["usual_input"] + output_names = ["usual_output"] + + [factory.configs] + x = "22" + y = "verbose" + + [[factory]] + type_name = "WiredOmniFac" + prefix = "myfac_modified" + input_names = ["different_input"] + output_names = ["different_output"] + + [factory.configs] + x = "100" + y = "silent" + +)"; + +TEST_CASE("WiringTests_RealFacGen") { + + JApplication app; + + auto wiring_svc = app.GetService(); + toml::table table = toml::parse(realfacgen_wiring); + wiring_svc->AddWirings(table, "testcase"); + + auto gen = new jana::components::JWiredFactoryGeneratorT; + app.Add(gen); + app.Initialize(); + + auto& summary = app.GetComponentSummary(); + jout << summary; + auto vf = summary.FindComponents("myfac"); + REQUIRE(vf.size() == 1); + REQUIRE(vf.at(0)->GetOutputs().at(0)->GetName() == "usual_output"); + + auto ef = summary.FindComponents("myfac_modified"); + REQUIRE(ef.size() == 1); + REQUIRE(ef.at(0)->GetOutputs().at(0)->GetName() == "different_output"); + + // Check that parameter values propagated from wiring file to parameter manager + REQUIRE(app.GetParameterValue("myfac:x") == 22); + REQUIRE(app.GetParameterValue("myfac:y") == "verbose"); + REQUIRE(app.GetParameterValue("myfac_modified:x") == 100); + REQUIRE(app.GetParameterValue("myfac_modified:y") == "silent"); + + //app.GetJParameterManager()->PrintParameters(2, 0); + //auto event = std::make_shared(&app); + //auto facs = event->GetFactorySet()->GetAllMultifactories(); + +} + +