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
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions include/Simo/core/Time.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,22 @@ struct from<Format, Time> {
}
};

template <>
struct from<YAML, Time> {
template <auto Opts>
static void op(Time& value, is_context auto&& ctx, auto&& it, auto end) {
auto wrapper = custom_t{value,
[](Time& output, TimeValue input) {
output = Time{input.time, input.unit};
},
[](const Time& input) {
return TimeValue{.time = input.to_picoseconds(),
.unit = Time::Unit::PS};
}};
from<YAML, decltype(wrapper)>::template op<Opts>(wrapper, ctx, it, end);
}
};

template <unsigned int Format>
struct to<Format, Time> {
template <auto Opts>
Expand Down
5 changes: 5 additions & 0 deletions include/Simo/module/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ class SIMO_PUBLIC Parameters {
[[nodiscard]] std::optional<Parameters> get_subtree(
const std::string& name) const;

template <typename Function>
void visit(Function f) {
trie.visit(f);
}

protected:
Parameter::ParameterTrie trie;
std::string name_;
Expand Down
16 changes: 16 additions & 0 deletions include/Simo/parameter/Parameter.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,16 @@ class Parameter {
return self;
}

/// Set stored value from glaze generic representation
[[nodiscard]]
virtual std::expected<Parameter*, std::string> value_from_generic(
const glz::generic_u64& glz_value) = 0;

/// Produce glaze generic representation of the value
[[nodiscard]]
virtual std::expected<glz::generic_u64, std::string> value_to_generic()
const = 0;

protected:
bool has_value_ = false;
};
Expand Down Expand Up @@ -101,6 +107,16 @@ class ParameterTyped : public Parameter {
return this;
}

std::expected<glz::generic_u64, std::string> value_to_generic()
const override {
if (!has_value()) {
return glz::generic_u64(nullptr);
}
glz::generic_u64 out;
out = value_;
return out;
}

[[nodiscard]] T value() const { return value_; }

[[nodiscard]] bool validate() const override {
Expand Down
29 changes: 27 additions & 2 deletions include/Simo/parameter/ParameterTrie.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <Simo/compiler/Compiler.h>

#include <ranges>
#include <string_view>
#include <unordered_map>

#include "Parameter.h"
Expand Down Expand Up @@ -106,7 +107,7 @@ class SIMO_PUBLIC ParameterTrie {
template <typename Function>
[[nodiscard]]
bool all(Function f) const {
if (value != nullptr && value->has_value() && !f(*value)) {
if (value != nullptr && !f(*value)) {
return false;
}
for (const auto& snd : children | std::views::values) {
Expand All @@ -117,6 +118,30 @@ class SIMO_PUBLIC ParameterTrie {
return true;
}

/// Use function on all the elements of the trie
/// The function must accept a T* argument
template <typename Function>
void visit(Function f) const {
visit_impl("", f);
}

template <typename Function>
void visit_impl(std::string_view name, Function f) const {
if (value != nullptr) {
if (!value->has_value()) {
f(name, nullptr);
} else {
f(name, value.get());
}
}
for (const auto& [child_name, sub_tree] : children) {
std::string sub_tree_name =
(name.empty() ? "" : std::string(name) + PARAMETER_NODE_SEPARATOR) +
child_name;
sub_tree.visit_impl(sub_tree_name, f);
}
}

std::unique_ptr<Parameter> value;

protected:
Expand All @@ -140,4 +165,4 @@ class SIMO_PUBLIC ParameterTrie {
};
} // namespace Simo::Parameter

#endif // SIMO_PARAMETERTRIE_HH
#endif // SIMO_PARAMETERTRIE_HH
2 changes: 2 additions & 0 deletions src/SimoSim/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define SIMO_CONFIG_HH
#include <Simo/Simo.h>

#include <filesystem>
#include <glaze/json/generic.hpp>
#include <string>
#include <vector>
Expand Down Expand Up @@ -47,6 +48,7 @@ namespace SimoSim::Config {

struct SimulationInfo {
Simo::Time time;
std::optional<std::string> dump_parameters_path;
};

struct Config {
Expand Down
74 changes: 68 additions & 6 deletions src/SimoSim/SimoSim.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
#include <Simo/Simo.h>
#include <Simo/module/core/CoreModules.h>

#include <expected>
#include <filesystem>
#include <fstream>
#include <glaze/yaml.hpp>
#include <iostream>
#include <optional>
Expand Down Expand Up @@ -88,6 +90,60 @@ void print_system_ports(
}
}

struct ParamDumpPair {
std::string name;
glz::generic_u64 param;
};

void dump_parameters(
const std::unordered_map<ModuleName, ModuleParameterPair>& module_map,
std::filesystem::path dump_path) {
std::ofstream out_file(dump_path);
if (!out_file.is_open()) {
std::cout << "Cannot open file " << dump_path << " to dump parameters\n";
return;
}
std::vector<ParamDumpPair> vect;
for (const auto& [module_name, module_param_pair] : module_map) {
const auto& [module, params] = module_param_pair;
params->visit([&module, &vect](std::string_view name,
Simo::Parameter::Parameter* param) {
const auto param_wrapper = param->value_to_generic();
if (!param_wrapper) {
std::cerr << param_wrapper.error() << "\n";
return;
}
vect.emplace_back(std::string(module->name()) + "/" + name,
param_wrapper.value());
});
if (auto ec = glz::write_file_yaml(vect, dump_path.string())) {
std::cerr << "Error when dumping YAML parameters at " << dump_path
<< " :\n";
std::cerr << glz::format_error(ec) << "\n";
return;
}
}
}

std::expected<SimoSim::Config::Config, std::string> read_config(
std::filesystem::path config_path) {
std::ifstream in_file(config_path);
if (!in_file.is_open()) {
return std::unexpected(std::format(
"Cannot open file {} to read configuration", config_path.c_str()));
}
std::stringstream buffer;
buffer << in_file.rdbuf();
std::string config_str = buffer.str();
SimoSim::Config::Config cfg;
if (auto ec = glz::read_yaml(cfg, config_str)) {
return std::unexpected(
std::format("Error during YAML config parsing of file {} :\n{}",
config_path.c_str(), glz::format_error(ec, config_str)));
}
return cfg;
}

int main(const int argc, char* argv[]) {
std::filesystem::path config_path;
std::vector<std::string> collection_search_paths;
Expand All @@ -102,7 +158,7 @@ int main(const int argc, char* argv[]) {
->check(CLI::ExistingFile);
app.add_option(
"--search-path", collection_search_paths,
"directory where to look for shared object containing collections")
"directory where to look for hared object containing collections")
->check(CLI::ExistingDirectory);
app.add_flag("-v,--verbose", verbosity,
"Increase verbosity level (e.g., -v, -vv, -vvv)");
Expand Down Expand Up @@ -153,13 +209,15 @@ int main(const int argc, char* argv[]) {
}
}

SimoSim::Config::Config cfg;
if (auto ec = glz::read_file_yaml(cfg, config_path.c_str())) {
std::cerr << "Error during YAML config parsing of file " << config_path
<< " :\n";
std::cerr << glz::format_error(ec) << "\n";
auto expected_cfg = read_config(config_path);
if (!expected_cfg.has_value()) {
std::cerr << expected_cfg.error();
return INVALID_CONFIG_FILE;
}
SimoSim::Config::Config cfg = expected_cfg.value();

const std::filesystem::path dump_parameters_path =
cfg.simulation.dump_parameters_path.value_or("");

std::vector<std::pair<ModuleName, ModuleType>> unrecognized_module_types;
std::vector<ModuleName> duplicate_module_names;
Expand Down Expand Up @@ -221,6 +279,10 @@ int main(const int argc, char* argv[]) {
return INITIALIZATION_FAILED;
}

if (!dump_parameters_path.empty()) {
dump_parameters(module_map, dump_parameters_path);
}

if (print_ports) {
print_system_ports(module_map);
}
Expand Down
2 changes: 1 addition & 1 deletion src/module/Module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,4 @@ void Module::populate_default_log_levels() {
logger.populate_default_log_levels();
}

} // namespace Simo
} // namespace Simo
1 change: 1 addition & 0 deletions tests/SimoSim/test_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ simulation:
time:
time: 100
unit: NS
dump_parameters_path: "parameters_dump.yaml"
22 changes: 22 additions & 0 deletions tests/core/TimePeriod/TimePeriodTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@

#define BOOST_TEST_MODULE SimoTimePeriod
#include <glaze/glaze.hpp>
#include <glaze/yaml.hpp>
#include <sstream>
#include <string>
#include <unordered_set>

#include "Simo/Simo.h"
#include "support/BoostInclude.h"

namespace Simo::Tests {
struct TimeWithFollowingMember {
Time time;
std::string label;
};

BOOST_AUTO_TEST_CASE(TimeUnitConversions) {
using Simo::Time;

Expand Down Expand Up @@ -111,4 +118,19 @@ BOOST_AUTO_TEST_CASE(TimeJsonSerializationAndParsing) {
BOOST_CHECK(invalid_error);
BOOST_CHECK_EQUAL(unchanged.to_picoseconds(), 99U);
}

BOOST_AUTO_TEST_CASE(TimeYamlParsingPreservesParentMapping) {
TimeWithFollowingMember parsed;
constexpr std::string_view yaml = R"(time:
time: 7
unit: NS
label: parsed
)";

const auto parse_error = glz::read_yaml(parsed, yaml);

BOOST_CHECK(!parse_error);
BOOST_CHECK_EQUAL(parsed.time.to_picoseconds(), 7'000U);
BOOST_CHECK_EQUAL(parsed.label, "parsed");
}
} // namespace Simo::Tests
2 changes: 1 addition & 1 deletion tests/statistics/StatisticsTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ BOOST_AUTO_TEST_CASE(CollectorParametersValidation) {
using Simo::Modules::Core::Collector;

Collector::Parameters params;
BOOST_CHECK_EQUAL(params.check(), true);
BOOST_CHECK_EQUAL(params.check(), false);

params.get<Time>("start_time")->value(Time(10));
params.get<Time>("end_time")->value(Time(5));
Expand Down