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
13 changes: 10 additions & 3 deletions include/bbp/sonata/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,10 @@ class SONATA_API SimulationConfig
double delay{};
/// Time duration for how long input is activated (ms)
double duration{};
/// Node set which is affected by input
std::string nodeSet;
/// Node set which is affected by input. Not allowed in case of CompartmentSet
nonstd::optional<std::string> nodeSet{nonstd::nullopt};
/// CompartmentSet which is affected by the input. It has priority over nodeSet
nonstd::optional<std::string> compartmentSet{nonstd::nullopt};
};

struct InputLinear: public InputBase {
Expand Down Expand Up @@ -796,10 +798,15 @@ class SONATA_API SimulationConfig
const std::string& getCompartmentSetsFile() const noexcept;

/**
* Returns the name of node set to be instantiated for the simulation, default = None
* Returns the name of the node set to be instantiated for the simulation, default = None
*/
const nonstd::optional<std::string>& getNodeSet() const noexcept;

/**
* Returns the name of the compartment set to be instantiated for the simulation, default = None
*/
const nonstd::optional<std::string>& getCompartmentSet() const noexcept;

/**
* Returns the metadata section
*/
Expand Down
5 changes: 4 additions & 1 deletion python/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,10 @@ PYBIND11_MODULE(_libsonata, m) {
DOC_SIMULATIONCONFIG(InputBase, duration))
.def_readonly("node_set",
&SimulationConfig::InputBase::nodeSet,
DOC_SIMULATIONCONFIG(InputBase, nodeSet));
DOC_SIMULATIONCONFIG(InputBase, nodeSet))
.def_readonly("compartment_set",
&SimulationConfig::InputBase::compartmentSet,
DOC_SIMULATIONCONFIG(InputBase, compartmentSet));

py::class_<SimulationConfig::InputLinear, SimulationConfig::InputBase>(simConf, "Linear")
.def_readonly("amp_start",
Expand Down
2 changes: 2 additions & 0 deletions python/generated/docstrings.h
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,8 @@ static const char *__doc_bbp_sonata_SimulationConfig_InputBase_module = R"doc(Ty

static const char *__doc_bbp_sonata_SimulationConfig_InputBase_nodeSet = R"doc(Node set which is affected by input)doc";

static const char *__doc_bbp_sonata_SimulationConfig_InputBase_compartmentSet = R"doc(Compartment set which is affected by input)doc";

static const char *__doc_bbp_sonata_SimulationConfig_InputHyperpolarizing = R"doc()doc";

static const char *__doc_bbp_sonata_SimulationConfig_InputHyperpolarizing_representsPhysicalElectrode = R"doc(Whether this input represents a physical electrode. Default is false)doc";
Expand Down
45 changes: 45 additions & 0 deletions python/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ def test_basic(self):
"ex_extracellular_stimulation",
"ex_hyperpolarizing",
"ex_linear",
"ex_linear_compartment_set",
"ex_noise_mean",
"ex_noise_meanpercent",
"ex_OU",
Expand All @@ -506,9 +507,13 @@ def test_basic(self):
self.assertEqual(self.config.input('ex_linear').delay, 0)
self.assertEqual(self.config.input('ex_linear').duration, 15)
self.assertEqual(self.config.input('ex_linear').node_set, "Column")
self.assertEqual(self.config.input('ex_linear').compartment_set, None)
self.assertEqual(self.config.input('ex_linear').amp_start, 0.15)
self.assertEqual(self.config.input('ex_linear').amp_end, 0.15)

self.assertEqual(self.config.input('ex_linear_compartment_set').node_set, None)
self.assertEqual(self.config.input('ex_linear_compartment_set').compartment_set, "cs1")

self.assertEqual(self.config.input('ex_rel_linear').input_type.name, 'current_clamp')
self.assertEqual(self.config.input('ex_rel_linear').module.name, 'relative_linear')
self.assertEqual(self.config.input('ex_rel_linear').delay, 0)
Expand Down Expand Up @@ -723,3 +728,43 @@ def test_simulation_config_failures(self):
"""
SimulationConfig(contents, "./")
self.assertEqual(e.exception.args, ('Replay spike_file should be a SONATA h5 file', ))

with self.assertRaises(SonataError) as e:
contents = """
{
"run": { "random_seed": 12345, "dt": 0.05, "tstop": 1000 },
"inputs" : {
"ex_linear": {
"input_type": "current_clamp",
"module": "linear",
"amp_start": 0.15,
"delay": 0,
"duration": 15,
"node_set":"Column",
"compartment_set":"cs1"
}
}
}
"""
SimulationConfig(contents, "./")
self.assertEqual(e.exception.args, ('`node_set` is not allowed if `compartment_set` is set in input ex_linear', ))

with self.assertRaises(SonataError) as e:
contents = """
{
"run": { "random_seed": 12345, "dt": 0.05, "tstop": 1000 },
"inputs" : {
"ex_linear": {
"input_type": "current_clamp",
"module": "linear",
"amp_start": 0.15,
"delay": 0,
"duration": 15
}
}
}
"""
SimulationConfig(contents, "./")
self.assertEqual(e.exception.args, ('One of `node_set` or `compartment_set` need to have a value in input ex_linear', ))


24 changes: 13 additions & 11 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,17 @@ SimulationConfig::Input parseInputModule(const nlohmann::json& valueIt,
parseMandatory(valueIt, "input_type", debugStr, input.inputType);
parseMandatory(valueIt, "delay", debugStr, input.delay);
parseMandatory(valueIt, "duration", debugStr, input.duration);
parseMandatory(valueIt, "node_set", debugStr, input.nodeSet);

parseOptional(valueIt, "node_set", input.nodeSet);
parseOptional(valueIt, "compartment_set", input.compartmentSet);

if (input.nodeSet.has_value() && input.compartmentSet.has_value()) {
throw SonataError("`node_set` is not allowed if `compartment_set` is set in " +
debugStr);
} else if (!input.nodeSet.has_value() && !input.compartmentSet.has_value()) {
throw SonataError("One of `node_set` or `compartment_set` need to have a value in " +
debugStr);
}
};

switch (module) {
Expand Down Expand Up @@ -466,16 +476,8 @@ SimulationConfig::Input parseInputModule(const nlohmann::json& valueIt,
case Module::noise: {
SimulationConfig::InputNoise ret;
parseCommon(ret);
const auto mean = valueIt.find("mean");
const auto mean_percent = valueIt.find("mean_percent");

if (mean != valueIt.end()) {
parseOptional(valueIt, "mean", ret.mean);
}

if (mean_percent != valueIt.end()) {
parseOptional(valueIt, "mean_percent", ret.meanPercent);
}
parseOptional(valueIt, "mean", ret.mean);
parseOptional(valueIt, "mean_percent", ret.meanPercent);

if (ret.mean.has_value() && ret.meanPercent.has_value()) {
throw SonataError("Both `mean` or `mean_percent` have values in " + debugStr);
Expand Down
8 changes: 8 additions & 0 deletions tests/data/config/simulation_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@
"duration": 15,
"node_set":"Column"
},
"ex_linear_compartment_set": {
"input_type": "current_clamp",
"module": "linear",
"amp_start": 0.15,
"delay": 0,
"duration": 15,
"compartment_set":"cs1"
},
"ex_rel_linear": {
"input_type": "current_clamp",
"module": "relative_linear",
Expand Down
65 changes: 58 additions & 7 deletions tests/test_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,6 @@ TEST_CASE("SimulationConfig") {
CHECK(configAllSects.sectionConfigure == "%s.gSK_E2bar_SK_E2 = 0");

CHECK_THROWS_AS(config.getReport("DoesNotExist"), SonataError);

CHECK(config.listReportNames() == std::set<std::string>{
"axonal_comp_centers",
"cell_imembrane",
Expand Down Expand Up @@ -587,6 +586,7 @@ TEST_CASE("SimulationConfig") {
"ex_extracellular_stimulation",
"ex_hyperpolarizing",
"ex_linear",
"ex_linear_compartment_set",
"ex_noise_mean",
"ex_noise_meanpercent",
"ex_OU",
Expand Down Expand Up @@ -1202,15 +1202,66 @@ TEST_CASE("SimulationConfig") {
},
"inputs": {
"linear": {
"input_type": "current_clamp",
"module": "spike_replay",
"delay": 0,
"duration": 15,
"node_set":"Column"
"input_type": "current_clamp",
"module": "linear",
"delay": 0,
"duration": 15,
"node_set":"Column"
}
}
})";
CHECK_THROWS_AS(SimulationConfig(contents, "./"), SonataError);
CHECK_THROWS_WITH(
SimulationConfig(contents, "./"),
Catch::Matchers::Contains("amp_start")
);
}
{ // Both node_set and compartment_set are given in an input object
auto contents = R"({
"run": {
"random_seed": 12345,
"dt": 0.05,
"tstop": 1000
},
"inputs": {
"linear": {
"input_type": "current_clamp",
"module": "linear",
"delay": 0,
"duration": 15,
"amp_start": 1,
"node_set":"Column",
"compartment_set":"cs1"
}
}
})";
CHECK_THROWS_WITH(
SimulationConfig(contents, "./"),
Catch::Matchers::Contains("node_set") &&
Catch::Matchers::Contains("compartment_set")
);
}
{ // Both node_set and compartment_set are missing in an input object
auto contents = R"({
"run": {
"random_seed": 12345,
"dt": 0.05,
"tstop": 1000
},
"inputs": {
"linear": {
"input_type": "current_clamp",
"module": "linear",
"delay": 0,
"duration": 15,
"amp_start": 1
}
}
})";
CHECK_THROWS_WITH(
SimulationConfig(contents, "./"),
Catch::Matchers::Contains("node_set") &&
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we use Catch::Matchers::AllOf(...) here instead of &&?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are still useing catch2 v2. It does not have AllOf

Catch::Matchers::Contains("compartment_set")
);
}
{ // Both mean and mean_percent are given in a noise input object
auto contents = R"({
Expand Down
Loading