Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion phlex/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ cet_make_library(
Boost::boost
Boost::json
phlex::core
phlex::configuration
)

install(FILES concurrency.hpp module.hpp source.hpp DESTINATION include/phlex)
Expand All @@ -27,9 +28,11 @@ cet_make_library(
EXPORT_NAME
configuration
INTERFACE
NO_SOURCE
SOURCE
configuration.cpp
LIBRARIES
Boost::json
phlex::core
)
install(FILES configuration.hpp DESTINATION include/phlex)

Expand Down
31 changes: 31 additions & 0 deletions phlex/configuration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "phlex/configuration.hpp"
#include "phlex/core/product_query.hpp"

#include <ranges>
#include <string>

namespace phlex::experimental {
std::vector<std::string> configuration::keys() const
{
std::vector<std::string> result;
result.reserve(config_.size());
std::ranges::transform(
config_, std::back_inserter(result), [](auto const& element) { return element.key(); });
return result;
}

configuration tag_invoke(boost::json::value_to_tag<configuration> const&,
boost::json::value const& jv)
{
return configuration{jv.as_object()};
}

product_query tag_invoke(boost::json::value_to_tag<product_query> const&,
boost::json::value const& jv)
{
using detail::value_decorate_exception;
auto query_object = jv.as_object();
return product_query{.spec = {value_decorate_exception<std::string>(query_object, "product")},
.layer = value_decorate_exception<std::string>(query_object, "layer")};
}
}
31 changes: 28 additions & 3 deletions phlex/configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,24 @@
#define PHLEX_CONFIGURATION_HPP

#include "boost/json.hpp"
#include "phlex/core/product_query.hpp"

#include <optional>
#include <string>
#include <vector>

namespace phlex::experimental {

namespace detail {
template <typename T>
T value_decorate_exception(boost::json::object const& obj, std::string const& key)
try {
return value_to<T>(obj.at(key));
} catch (std::exception const& e) {
throw std::runtime_error("Error retrieving parameter '" + key + "':\n" + e.what());
}
}

class configuration {
public:
configuration() = default;
Expand All @@ -14,16 +28,16 @@ namespace phlex::experimental {
template <typename T>
std::optional<T> get_if_present(std::string const& key) const
{
if (auto pkey = config_.if_contains(key)) {
return value_to<T>(*pkey);
if (config_.contains(key)) {
return detail::value_decorate_exception<T>(config_, key);
}
return std::nullopt;
}

template <typename T>
T get(std::string const& key) const
{
return value_to<T>(config_.at(key));
return detail::value_decorate_exception<T>(config_, key);
}

template <typename T>
Expand All @@ -32,10 +46,21 @@ namespace phlex::experimental {
return get_if_present<T>(key).value_or(std::forward<T>(default_value));
}

std::vector<std::string> keys() const;

private:
boost::json::object config_;
};

// =================================================================================
// To enable direct conversions from Boost JSON types to our own types, we implement
// tag_invoke(...) function overloads, which are the customization points Boost JSON
// provides.
configuration tag_invoke(boost::json::value_to_tag<configuration> const&,
boost::json::value const& jv);

product_query tag_invoke(boost::json::value_to_tag<product_query> const&,
boost::json::value const& jv);
}

#endif // PHLEX_CONFIGURATION_HPP
3 changes: 3 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ include(CetTest)
cet_test_env(SPDLOG_LEVEL=debug)

cet_test(concepts SOURCE concepts.cpp LIBRARIES phlex::core)
cet_test(config_test USE_CATCH2_MAIN SOURCE configuration.cpp LIBRARIES
phlex::configuration
)
cet_test(string_literal SOURCE string_literal.cpp LIBRARIES phlex::utilities)
cet_test(type_deduction SOURCE type_deduction.cpp LIBRARIES
phlex::metaprogramming
Expand Down
2 changes: 1 addition & 1 deletion test/benchmarks/accept_even_ids.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ PHLEX_EXPERIMENTAL_REGISTER_ALGORITHMS(m, config)
"accept_even_ids",
[](data_cell_index const& id) { return id.number() % 2 == 0; },
concurrency::unlimited)
.input_family(product_query{config.get<std::string>("product_name"), "event"});
.input_family(config.get<product_query>("input"));
}
2 changes: 1 addition & 1 deletion test/benchmarks/accept_even_numbers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ PHLEX_EXPERIMENTAL_REGISTER_ALGORITHMS(m, config)
using namespace phlex::experimental;
m.predicate(
"accept_even_numbers", [](int i) { return i % 2 == 0; }, concurrency::unlimited)
.input_family(product_query{config.get<std::string>("consumes"), "event"});
.input_family(config.get<product_query>("consumes"));
}
2 changes: 1 addition & 1 deletion test/benchmarks/accept_fibonacci_numbers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ PHLEX_EXPERIMENTAL_REGISTER_ALGORITHMS(m, config)
using namespace phlex::experimental;
m.make<test::fibonacci_numbers>(config.get<int>("max_number"))
.predicate("accept", &test::fibonacci_numbers::accept, concurrency::unlimited)
.input_family(product_query{config.get<std::string>("consumes"), "event"});
.input_family(config.get<product_query>("consumes"));
}
2 changes: 1 addition & 1 deletion test/benchmarks/benchmark-04.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
read_index: {
plugin: 'read_index',
consumes: 'a'
consumes: { product: 'a', layer: "event" }
},
provider: {
plugin: 'benchmarks_provider'
Expand Down
2 changes: 1 addition & 1 deletion test/benchmarks/benchmark-07.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
modules: {
even_filter: {
plugin: 'accept_even_ids',
product_name: 'id',
input: { product: 'id', layer: 'event' },
},
b_creator: {
plugin: 'last_index',
Expand Down
6 changes: 3 additions & 3 deletions test/benchmarks/benchmark-08.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ local max_number = 100000;
},
even_filter: {
plugin: 'accept_even_numbers',
consumes: 'a',
consumes: { product: 'a', layer: 'event' }
},
fibonacci_filter: {
plugin: 'accept_fibonacci_numbers',
consumes: 'a',
consumes: { product: 'a', layer: "event" },
max_number: max_number,
},
d: {
plugin: 'verify_even_fibonacci_numbers',
when: ['even_filter:accept_even_numbers', 'fibonacci_filter:accept'],
consumes: 'a',
consumes: { product: 'a', layer: "event" },
max_number: max_number,
},
provider: {
Expand Down
4 changes: 2 additions & 2 deletions test/benchmarks/benchmark-09.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
},
even_filter: {
plugin: 'accept_even_numbers',
consumes: 'a',
consumes: { product: 'a', layer: "event" }
},
d: {
plugin: 'read_index',
when: ['even_filter:accept_even_numbers'],
consumes: 'b',
consumes: { product: 'b', layer: "event" }
},
provider: {
plugin: 'benchmarks_provider'
Expand Down
4 changes: 2 additions & 2 deletions test/benchmarks/read_index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ namespace {
PHLEX_EXPERIMENTAL_REGISTER_ALGORITHMS(m, config)
{
using namespace phlex::experimental;
m.observe("read_index", read_index, phlex::experimental::concurrency::unlimited)
.input_family(product_query{config.get<std::string>("consumes"), "event"});
m.observe("read_index", read_index, concurrency::unlimited)
.input_family(config.get<product_query>("consumes"));
}
2 changes: 1 addition & 1 deletion test/benchmarks/verify_even_fibonacci_numbers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ PHLEX_EXPERIMENTAL_REGISTER_ALGORITHMS(m, config)
m.make<even_fibonacci_numbers>(config.get<int>("max_number"))
.observe(
"only_even", &even_fibonacci_numbers::only_even, phlex::experimental::concurrency::unlimited)
.input_family(product_query{config.get<std::string>("consumes"), "event"});
.input_family(config.get<product_query>("consumes"));
}
60 changes: 60 additions & 0 deletions test/configuration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "phlex/configuration.hpp"

#include "boost/json.hpp"
#include "catch2/catch_test_macros.hpp"
#include "catch2/matchers/catch_matchers_string.hpp"

using namespace phlex::experimental;
using namespace Catch::Matchers;

TEST_CASE("Check parameter-retrieval errors", "[config]")
{
boost::json::object underlying_config;
underlying_config["b"] = 2.5;
configuration const config{underlying_config};

CHECK(config.keys() == std::vector<std::string>{"b"});

CHECK_THROWS_WITH(config.get<int>("a"), ContainsSubstring("Error retrieving parameter 'a'"));
CHECK_THROWS_WITH(config.get<std::string>("b"),
ContainsSubstring("Error retrieving parameter 'b'"));
}

TEST_CASE("Retrieve value that is a configuration object", "[config]")
{
boost::json::object underlying_config;
underlying_config["nested_table"] = boost::json::object{};
configuration const config{underlying_config};
auto nested_table = config.get<configuration>("nested_table");
CHECK(nested_table.keys().empty());
}

TEST_CASE("Retrieve product_query", "[config]")
{
boost::json::object input;
input["product"] = "tracks";
input["layer"] = "job";

boost::json::object malformed_input1;
malformed_input1["product"] = 16.; // Should be string
malformed_input1["layer"] = "job";

boost::json::object malformed_input2;
malformed_input2["product"] = "hits";
malformed_input2["level"] = "should be layer, not level";

boost::json::object underlying_config;
underlying_config["input"] = std::move(input);
underlying_config["malformed1"] = std::move(malformed_input1);
underlying_config["malformed2"] = std::move(malformed_input2);
configuration config{underlying_config};

auto input_query = config.get<product_query>("input");
CHECK(input_query == "tracks"_in("job"));
CHECK_THROWS_WITH(config.get<product_query>("malformed1"),
ContainsSubstring("Error retrieving parameter 'malformed1'") &&
ContainsSubstring("Error retrieving parameter 'product'"));
CHECK_THROWS_WITH(config.get<product_query>("malformed2"),
ContainsSubstring("Error retrieving parameter 'malformed2'") &&
ContainsSubstring("Error retrieving parameter 'layer'"));
}
3 changes: 2 additions & 1 deletion test/mock-workflow/G4Stage1.libsonnet
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
local ev = import "event_product.libsonnet";
local generators = import 'SinglesGen.libsonnet';

{
largeant: {
plugin: 'largeant',
duration_usec: 156, # Typical: 15662051
inputs: [f + "/MCTruths" for f in std.objectFields(generators)],
inputs: [ev.event_product(f + "/MCTruths") for f in std.objectFields(generators)],
outputs: ["ParticleAncestryMap", "Assns", "SimEnergyDeposits", "AuxDetHits", "MCParticles"],
}
}
5 changes: 3 additions & 2 deletions test/mock-workflow/G4Stage2.libsonnet
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
local ev = import "event_product.libsonnet";
local g4stage1 = import 'G4Stage1.libsonnet';

{
IonAndScint: {
plugin: 'ion_and_scint',
duration_usec: 546, # Typical: 5457973
inputs: [f + "/SimEnergyDeposits" for f in std.objectFields(g4stage1)],
inputs: [ev.event_product(f + "/SimEnergyDeposits") for f in std.objectFields(g4stage1)],
outputs: ["SimEnergyDeposits", "SimEnergyDeposits_priorSCE"],
},
PDFastSim: {
plugin: 'pd_fast_sim',
duration_usec: 69, # Typical: 69681950
inputs: ['SimEnergyDeposits_priorSCE'],
inputs: [ev.event_product('SimEnergyDeposits_priorSCE')],
outputs: ['SimPhotonLites', 'OpDetBacktrackerRecords'],
}
}
14 changes: 8 additions & 6 deletions test/mock-workflow/SinglesGen.libsonnet
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
local ev = import 'event_product.libsonnet';

{
rn222: {
plugin: "MC_truth_algorithm",
duration_usec: 39,
inputs: ["id"],
inputs: [ev.event_product("id")],
outputs: ["MCTruths"]
},
ar39: {
plugin: "MC_truth_algorithm",
duration_usec: 12410,
inputs: ["id"],
inputs: [ev.event_product("id")],
outputs: ["MCTruths"]
},
cosmicgenerator: {
plugin: "MC_truth_algorithm",
duration_usec: 492, # Typical: 4926215
inputs: ["id"],
inputs: [ev.event_product("id")],
outputs: ["MCTruths"]
},
kr85: {
plugin: "MC_truth_algorithm",
duration_usec: 1643,
inputs: ["id"],
inputs: [ev.event_product("id")],
outputs: ["MCTruths"]
},
generator: {
plugin: "three_tuple_algorithm",
duration_usec: 69616,
inputs: ["id"],
inputs: [ev.event_product("id")],
outputs: ["MCTruths", "BeamEvents", "beamsims"]
},
ar42: {
plugin: "MC_truth_algorithm",
duration_usec: 148,
inputs: ["id"],
inputs: [ev.event_product("id")],
outputs: ["MCTruths"]
},
}
14 changes: 3 additions & 11 deletions test/mock-workflow/algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "phlex/concurrency.hpp"
#include "phlex/configuration.hpp"
#include "phlex/core/product_query.hpp"
#include "test/mock-workflow/timed_busy.hpp"

#include "fmt/std.h"
Expand Down Expand Up @@ -55,7 +56,7 @@ namespace phlex::experimental::test {
return Outputs{};
}

using inputs = std::array<std::string, sizeof...(Inputs)>;
using inputs = std::array<product_query, sizeof...(Inputs)>;
using outputs = std::array<std::string, output_size<Outputs>>;

private:
Expand All @@ -70,19 +71,10 @@ namespace phlex::experimental::test {
using algorithm_t = algorithm<inputs_t, Outputs>;
concurrency const j{c.get<unsigned>("concurrency", concurrency::unlimited.value)};

// Convert product strings to product queries.
// FIXME: There should be a c.get<product_query>(...) specialization
auto input_product_strings = c.get<typename algorithm_t::inputs>("inputs");
std::array<product_query, std::tuple_size_v<inputs_t>> queries{};
std::ranges::transform(
input_product_strings, queries.begin(), [](std::string const& product_string) {
return product_query{product_string, "event"};
});

m.template make<algorithm_t>(c.get<std::string>("module_label"),
c.get<unsigned>("duration_usec"))
.transform("execute", &algorithm_t::execute, j)
.input_family(std::move(queries))
.input_family(c.get<typename algorithm_t::inputs>("inputs"))
.output_products(c.get<typename algorithm_t::outputs>("outputs"));
}
}
Expand Down
Loading
Loading