Skip to content

Commit

Permalink
New parameters in SimulationConfig
Browse files Browse the repository at this point in the history
- Parse floating point with type "double" to align with parser "nlohmann::json"
- Parse variables in "manifest" section and apply them to the configuration file
- Parse "network" parameter for the path of circuit_config file
  • Loading branch information
WeinaJi committed Apr 6, 2022
1 parent 4b11c8d commit 6606b49
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 25 deletions.
14 changes: 9 additions & 5 deletions include/bbp/sonata/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,9 @@ class SONATA_API SimulationConfig
*/
struct Run {
/// Biological simulation end time in milliseconds
float tstop{};
double tstop{};
/// Integration step duration in milliseconds
float dt{};
double dt{};
};
/**
* Parameters to override simulator output for spike reports
Expand All @@ -208,11 +208,11 @@ class SONATA_API SimulationConfig
/// Report type. Possible values: "compartment", "summation", "synapse"
std::string type;
/// Interval between reporting steps in milliseconds
float dt{};
double dt{};
/// Time to step reporting in milliseconds
float startTime{};
double startTime{};
/// Time to stop reporting in milliseconds
float endTime{};
double endTime{};
/// Report filename. Default is "<report name>_SONATA.h5"
std::string fileName;
};
Expand Down Expand Up @@ -265,6 +265,8 @@ class SONATA_API SimulationConfig
*/
const Report& getReport(const std::string& name) const;

const std::string& getNetwork() const noexcept;

private:
// JSON string
const std::string _jsonContent;
Expand All @@ -277,6 +279,8 @@ class SONATA_API SimulationConfig
Output _output;
// List of reports
std::unordered_map<std::string, Report> _reports;
// Path of circuit config file for the simulation
std::string _network;

class Parser;
friend class Parser;
Expand Down
1 change: 1 addition & 0 deletions python/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@ PYBIND11_MODULE(_libsonata, m) {
.def_property_readonly("json", &SimulationConfig::getJSON)
.def_property_readonly("run", &SimulationConfig::getRun)
.def_property_readonly("output", &SimulationConfig::getOutput)
.def_property_readonly("network", &SimulationConfig::getNetwork)
.def("report", &SimulationConfig::getReport, "name"_a);

bindPopulationClass<EdgePopulation>(
Expand Down
7 changes: 5 additions & 2 deletions python/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,20 +585,23 @@ def test_basic(self):
self.assertEqual(self.config.base_path, os.path.abspath(os.path.join(PATH, 'config')))

self.assertEqual(self.config.run.tstop, 1000)
self.assertTrue(abs(self.config.run.dt - 0.025) < 0.01)
self.assertEqual(self.config.run.dt, 0.025)

self.assertEqual(self.config.output.output_dir,
os.path.abspath(os.path.join(PATH, 'config/output')))
self.assertEqual(self.config.output.spikes_file, 'out.h5')

self.assertEqual(self.config.report('soma').cells, 'Mosaic')
self.assertEqual(self.config.report('soma').type, 'compartment')
self.assertTrue(abs(self.config.report('compartment').dt - 0.1) < 0.01)
self.assertEqual(self.config.report('compartment').dt, 0.1)
self.assertEqual(self.config.report('axonal_comp_centers').start_time, 0)
self.assertEqual(self.config.report('axonal_comp_centers').file_name,
os.path.abspath(os.path.join(PATH, 'config/axon_centers.h5')))
self.assertEqual(self.config.report('cell_imembrane').end_time, 500)

self.assertEqual(self.config.network,
os.path.abspath(os.path.join(PATH, 'config/circuit_config.json')))

def test_json(self):
temp_config = json.loads(self.config.json)
self.assertEqual(temp_config['run']['tstop'], 1000)
Expand Down
42 changes: 31 additions & 11 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,9 @@ nlohmann::json expandVariables(const nlohmann::json& json,

using Variables = std::map<std::string, std::string>;

Variables readVariables(const nlohmann::json& json) {
// parse variables named like $[a-zA-Z0-9_]* like in manifest sections
Variables parseManifest(const nlohmann::json& manifest) {
Variables variables;

if (json.find("networks") == json.end() || json.find("manifest") == json.end()) {
return variables;
}

const auto manifest = json["manifest"];

const std::regex regexVariable(R"(\$[a-zA-Z0-9_]*)");

for (auto it = manifest.begin(); it != manifest.end(); ++it) {
Expand All @@ -124,6 +118,16 @@ Variables readVariables(const nlohmann::json& json) {
return variables;
}

// read variables in manifest section for circuit_config
Variables readVariables(const nlohmann::json& json) {
Variables variables;

if (json.find("networks") == json.end() || json.find("manifest") == json.end()) {
return variables;
}
return parseManifest(json["manifest"]);
}

std::string toAbsolute(const fs::path& base, const fs::path& path) {
const auto absolute = path.is_absolute() ? path : fs::absolute(base / path);
return absolute.lexically_normal().string();
Expand Down Expand Up @@ -482,8 +486,14 @@ class SimulationConfig::Parser
{
public:
Parser(const std::string& content, const std::string& basePath)
: _basePath(fs::absolute(fs::path(basePath)).lexically_normal())
, _json(nlohmann::json::parse(content)) {}
: _basePath(fs::absolute(fs::path(basePath)).lexically_normal()) {
// Parse manifest section and expand JSON string
_json = nlohmann::json::parse(content);
if (_json.contains("manifest")) {
const auto vars = replaceVariables(parseManifest(_json["manifest"]));
_json = expandVariables(_json, vars);
}
}

template <typename Iterator, typename Type, typename SectionName>
void parseMandatory(const Iterator& it,
Expand Down Expand Up @@ -560,9 +570,14 @@ class SimulationConfig::Parser
return result;
}

const std::string parseNetwork() const {
auto val = _json.find("network") != _json.end() ? _json["network"] : "circuit_config.json";
return toAbsolute(_basePath, val);
}

private:
const fs::path _basePath;
const nlohmann::json _json;
nlohmann::json _json;
};

SimulationConfig::SimulationConfig(const std::string& content, const std::string& basePath)
Expand All @@ -572,6 +587,7 @@ SimulationConfig::SimulationConfig(const std::string& content, const std::string
_run = parser.parseRun();
_output = parser.parseOutput();
_reports = parser.parseReports();
_network = parser.parseNetwork();
}

SimulationConfig SimulationConfig::fromFile(const std::string& path) {
Expand All @@ -594,6 +610,10 @@ const SimulationConfig::Output& SimulationConfig::getOutput() const noexcept {
return _output;
}

const std::string& SimulationConfig::getNetwork() const noexcept {
return _network;
}

const SimulationConfig::Report& SimulationConfig::getReport(const std::string& name) const {
const auto it = _reports.find(name);
if (it == _reports.end())
Expand Down
9 changes: 7 additions & 2 deletions tests/data/config/simulation_config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{
"run": {
"manifest": {
"$OUTPUT_DIR": ".",
"$INPUT_DIR": "."
},
"network": "$INPUT_DIR/circuit_config.json",
"run": {
"tstop": 1000,
"dt": 0.025,
"random_seed": 201506,
Expand All @@ -8,7 +13,7 @@
"forward_skip": 500
},
"output": {
"output_dir": "output",
"output_dir": "$OUTPUT_DIR/output",
"spikes_file": "out.h5"
},
"reports": {
Expand Down
13 changes: 8 additions & 5 deletions tests/test_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,8 @@ TEST_CASE("SimulationConfig") {
const auto config = SimulationConfig::fromFile("./data/config/simulation_config.json");
CHECK_NOTHROW(config.getRun());
using Catch::Matchers::WithinULP;
REQUIRE_THAT(config.getRun().tstop, WithinULP(1000.f, 1));
REQUIRE_THAT(config.getRun().dt, WithinULP(0.025f, 1));
CHECK(config.getRun().tstop == 1000);
CHECK(config.getRun().dt == 0.025);

namespace fs = ghc::filesystem;
const auto basePath = fs::absolute(
Expand All @@ -312,15 +312,18 @@ TEST_CASE("SimulationConfig") {

CHECK(config.getReport("soma").cells == "Mosaic");
CHECK(config.getReport("soma").type == "compartment");
CHECK(config.getReport("compartment").dt == 0.1f);
CHECK(config.getReport("axonal_comp_centers").startTime == 0.f);
CHECK(config.getReport("compartment").dt == 0.1);
CHECK(config.getReport("axonal_comp_centers").startTime == 0.);
const auto axonalFilePath = fs::absolute(basePath / fs::path("axon_centers.h5"));
CHECK(config.getReport("axonal_comp_centers").fileName ==
axonalFilePath.lexically_normal());
CHECK(config.getReport("cell_imembrane").endTime == 500.f);
CHECK(config.getReport("cell_imembrane").endTime == 500.);

CHECK_NOTHROW(nlohmann::json::parse(config.getJSON()));
CHECK(config.getBasePath() == basePath.lexically_normal());

const auto network = fs::absolute(basePath / fs::path("circuit_config.json"));
CHECK(config.getNetwork() == network.lexically_normal());
}

SECTION("Exception") {
Expand Down

0 comments on commit 6606b49

Please sign in to comment.