27 #include <momemta/ConfigurationReader.h> 28 #include <momemta/Logging.h> 34 return reader.freeze();
37 TEST_CASE(
"Graph",
"[core][graph]") {
39 logging::set_level(logging::level::warning);
41 momemta::ModuleList available_modules;
44 SECTION(
"Single module") {
45 const std::string conf_str = R
"( 46 local input = declare_input("input") 48 DoubleConstant.constant = { value = 42. } 50 integrand("constant::value") 53 auto conf = get_conf(conf_str);
55 REQUIRE(conf.getIntegrands().size() == 1);
56 REQUIRE(conf.getInputs().size() == 1);
57 REQUIRE(conf.getModules().size() == 5);
60 auto graph = builder.build();
62 REQUIRE(graph->getPaths().size() == 1);
63 REQUIRE(graph->getPaths().front() == DEFAULT_EXECUTION_PATH);
65 auto modules = graph->getDecls(DEFAULT_EXECUTION_PATH);
66 REQUIRE(modules.size() == 1);
67 REQUIRE(modules.front().type ==
"DoubleConstant");
68 REQUIRE(modules.front().name ==
"constant");
71 SECTION(
"Unused module should be removed") {
72 const std::string conf_str = R
"( 73 local input = declare_input("input") 75 DoubleConstant.constant = { value = 42. } 77 DoubleConstant.unused = { value = 42. } 79 integrand("constant::value") 82 auto conf = get_conf(conf_str);
84 REQUIRE(conf.getModules().size() == 6);
87 auto graph = builder.build();
89 REQUIRE(graph->getPaths().size() == 1);
90 REQUIRE(graph->getPaths().front() == DEFAULT_EXECUTION_PATH);
92 auto modules = graph->getDecls(DEFAULT_EXECUTION_PATH);
93 REQUIRE(modules.size() == 1);
96 SECTION(
"Sticky module should not be removed") {
97 const std::string conf_str = R
"( 98 local input = declare_input("input") 100 DoubleConstant.constant = { value = 42. } 102 DoublePrinter.unused = { input = "constant::value" } 104 integrand("constant::value") 107 auto conf = get_conf(conf_str);
109 REQUIRE(conf.getModules().size() == 6);
112 auto graph = builder.build();
114 REQUIRE(graph->getPaths().size() == 1);
115 REQUIRE(graph->getPaths().front() == DEFAULT_EXECUTION_PATH);
117 auto modules = graph->getDecls(DEFAULT_EXECUTION_PATH);
118 REQUIRE(modules.size() == 2);
121 SECTION(
"Module should be correctly ordered") {
122 const std::string conf_str = R
"( 123 local input_a = declare_input("input_a") 124 local input_b = declare_input("input_b") 126 GaussianTransferFunctionOnEnergy.tf = { 127 ps_point = add_dimension(), 128 reco_particle = "input_sum::output", 132 VectorLinearCombinator.input_sum = { 133 inputs = { input_a.reco_p4, input_b.reco_p4 }, 134 coefficients = {1, 1} 137 integrand("tf::output") 140 auto conf = get_conf(conf_str);
142 REQUIRE(conf.getModules().size() == 7);
145 auto graph = builder.build();
147 REQUIRE(graph->getPaths().size() == 1);
148 REQUIRE(graph->getPaths().front() == DEFAULT_EXECUTION_PATH);
150 auto modules = graph->getDecls(DEFAULT_EXECUTION_PATH);
151 REQUIRE(modules.size() == 2);
153 REQUIRE(modules.at(0).name ==
"input_sum");
154 REQUIRE(modules.at(1).name ==
"tf");
157 SECTION(
"Circular dependencies are not allowed") {
158 const std::string conf_str = R
"( 159 GaussianTransferFunctionOnEnergy.tf_1 = { 160 ps_point = "dummy::dummy", 161 reco_particle = "tf_2::output", 165 GaussianTransferFunctionOnEnergy.tf_2 = { 166 ps_point = "dummy::dummy", 167 reco_particle = "tf_1::output", 172 auto conf = get_conf(conf_str);
174 REQUIRE(conf.getModules().size() == 5);
176 logging::set_level(logging::level::off);
178 REQUIRE_THROWS(builder.build());
181 SECTION(
"Two execution paths") {
182 const std::string conf_str = R
"( 184 DoubleConstant.dummy = { value = 42. } 187 solutions = "dummy::value", 188 path = Path("sum", "constant_1", "constant_2", "printer") 191 SolutionPrinter.printer = { input = "looper::particles" } 192 DoubleConstant.constant_1 = { value = 42. } 193 DoubleConstant.constant_2 = { value = 42. } 195 DoubleLinearCombinator.sum = { 196 inputs = { "constant_1::value", "constant_2::value" }, 197 coefficients = {1, 1} 200 integrand("sum::output") 203 auto conf = get_conf(conf_str);
205 REQUIRE(conf.getModules().size() == 9);
206 REQUIRE(conf.getPaths().size() == 1);
209 auto graph = builder.build();
211 REQUIRE(graph->getPaths().size() == 2);
212 REQUIRE(graph->getPaths().front() == DEFAULT_EXECUTION_PATH);
213 REQUIRE(graph->getPaths().back() == conf.getPaths().front()->id);
215 auto modules = graph->getDecls(DEFAULT_EXECUTION_PATH);
216 REQUIRE(modules.size() == 2);
218 REQUIRE(modules.at(0).name ==
"dummy");
219 REQUIRE(modules.at(1).name ==
"looper");
221 modules = graph->getDecls(graph->getPaths().back());
223 REQUIRE(modules.size() == 4);
226 SECTION(
"A module using looper's output must be inside the looper execution path") {
227 const std::string conf_str = R
"( 228 DoubleConstant.dummy = { value = 42. } 231 solutions = "dummy::value", 232 path = Path("constant") 235 SolutionPrinter.printer = { input = "looper::particles" } 236 DoubleConstant.constant = { value = 42. } 238 integrand("sum::output") 241 auto conf = get_conf(conf_str);
243 REQUIRE(conf.getModules().size() == 7);
244 REQUIRE(conf.getPaths().size() == 1);
246 logging::set_level(logging::level::off);
250 Catch::Matchers::Contains(
"A module is using the looper output but not actually part of its execution path")
254 SECTION(
"A module inside the execution path may not exists") {
255 const std::string conf_str = R
"( 256 DoubleConstant.dummy = { value = 42. } 259 solutions = "dummy::value", 260 path = Path("unexisting", "printer") 263 SolutionPrinter.printer = { input = "looper::particles" } 265 integrand("dummy::dummy") 268 auto conf = get_conf(conf_str);
270 REQUIRE(conf.getModules().size() == 6);
271 REQUIRE(conf.getPaths().size() == 1);
273 logging::set_level(logging::level::off);
275 auto graph = builder.build();
278 SECTION(
"Three execution paths") {
279 const std::string conf_str = R
"( 281 DoubleConstant.dummy_1 = { value = 42. } 282 DoubleConstant.dummy_2 = { value = 42. } 285 solutions = "dummy_2::value", 286 path = Path("printer_2") 290 solutions = "dummy_1::value", 291 path = Path("printer_1", "looper_2", "dummy_2") 294 SolutionPrinter.printer_1 = { input = "looper_1::particles" } 295 SolutionPrinter.printer_2 = { input = "looper_2::particles" } 297 integrand("some::output") 300 auto conf = get_conf(conf_str);
302 REQUIRE(conf.getModules().size() == 9);
303 REQUIRE(conf.getPaths().size() == 2);
306 auto graph = builder.build();
308 REQUIRE(graph->getPaths().size() == 3);
309 REQUIRE(graph->getPaths().front() == DEFAULT_EXECUTION_PATH);
312 REQUIRE(graph->getPaths().back() == conf.getPaths().front()->id);
314 auto modules = graph->getDecls(DEFAULT_EXECUTION_PATH);
315 REQUIRE(modules.size() == 2);
317 REQUIRE(modules.at(0).name ==
"dummy_1");
318 REQUIRE(modules.at(1).name ==
"looper_1");
320 modules = graph->getDecls(graph->getPaths().at(1));
323 REQUIRE(modules.size() == 3);
325 modules = graph->getDecls(graph->getPaths().at(2));
327 REQUIRE(modules.size() == 1);
328 REQUIRE(modules.at(0).name ==
"printer_2");
331 SECTION(
"Unused module should not increase the number of dimension") {
332 const std::string conf_str = R
"( 334 local first_dim = add_dimension() 335 local unused_dim = add_dimension() 337 DoubleConstant.dummy = { value = 42. } 339 GaussianTransferFunctionOnEnergy.tf_1 = { 340 ps_point = first_dim, 341 reco_particle = "dummy::value", 345 GaussianTransferFunctionOnEnergy.tf_2 = { 346 ps_point = first_dim, 347 reco_particle = "dummy::value", 351 GaussianTransferFunctionOnEnergy.tf_3 = { 352 ps_point = add_dimension(), 353 reco_particle = "dummy::value", 357 GaussianTransferFunctionOnEnergy.unused = { 358 ps_point = unused_dim, 359 reco_particle = "dummy::value", 363 integrand("tf_1::output", "tf_2::output", "tf_3::output") 366 auto conf = get_conf(conf_str);
369 REQUIRE(conf.getNDimensions() == 3);
372 auto graph = builder.build();
375 REQUIRE(graph->getNDimensions() == 2);
377 REQUIRE(graph->getPaths().size() == 1);
378 REQUIRE(graph->getPaths().front() == DEFAULT_EXECUTION_PATH);
380 auto modules = graph->getDecls(DEFAULT_EXECUTION_PATH);
381 REQUIRE(modules.size() == 4);
384 SECTION(
"Using a non-existing input should throw an exception") {
385 const std::string conf_str = R
"( 387 GaussianTransferFunctionOnEnergy.tf_1 = { 388 ps_point = add_dimension(), 389 reco_particle = "non_existing_module::output", 393 integrand("tf_1::output") 396 auto conf = get_conf(conf_str);
397 logging::set_level(logging::level::off);
401 Catch::Matchers::Equals(
"Module 'tf_1' requested a non-existing input (non_existing_module::output)")
405 SECTION(
"Using a non-existing input should throw an exception") {
406 const std::string conf_str = R
"( 408 DoubleConstant.dummy = { value = 42. } 410 GaussianTransferFunctionOnEnergy.tf_1 = { 411 ps_point = add_dimension(), 412 reco_particle = "dummy::non_existing_param", 416 integrand("tf_1::output") 419 auto conf = get_conf(conf_str);
420 logging::set_level(logging::level::off);
424 Catch::Matchers::Equals(
"Module 'tf_1' requested a non-existing input (dummy::non_existing_param)")
A lua configuration file parser.
static ModuleRegistry & get()
A singleton available at startup.
A frozen snapshot of the configuration file.
void exportList(bool ignore_internal, ModuleList &list) const