Skip to content

Commit

Permalink
SimulationConfig parser: add modifications properties in conditions s…
Browse files Browse the repository at this point in the history
…ection (#228)

* SimulationConfig parser: add modifications properties in conditions section
  • Loading branch information
WeinaJi authored Sep 30, 2022
1 parent 24e7484 commit 5f08cd4
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 1 deletion.
31 changes: 31 additions & 0 deletions include/bbp/sonata/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,29 @@ class SONATA_API SimulationConfig
/// The sorting order of the spike report. Default is "by_time"
SpikesSortOrder sortOrder;
};

struct ModificationBase {
enum class ModificationType { invalid = -1, TTX, ConfigureAllSections };

/// Node set which receives the manipulation
std::string nodeSet;
/// Name of the manipulation. Supported values are “TTX” and “ConfigureAllSections”.
ModificationType type;
};

struct ModificationTTX: public ModificationBase {};

struct ModificationConfigureAllSections: public ModificationBase {
/// For “ConfigureAllSections” manipulation, a snippet of python code to perform one or more
/// assignments involving section attributes, for all sections that have all the referenced
/// attributes. The format is "%s.xxxx; %s.xxxx; ...".
std::string sectionConfigure;
};

using Modification = nonstd::variant<ModificationTTX, ModificationConfigureAllSections>;

using ModificationMap = std::unordered_map<std::string, Modification>;

/**
* Parameters defining global experimental conditions.
*/
Expand All @@ -253,6 +276,14 @@ class SONATA_API SimulationConfig
/// dictionaries of variables' names and values.
std::unordered_map<std::string, std::unordered_map<std::string, variantValueType>>
mechanisms;
/// Collection of dictionaries with each member decribing a modification that mimics
/// experimental manipulations to the circuit.
ModificationMap modifications;
/// Returns the names of the modifications
std::set<std::string> listModificationNames() const;
/// Returns the given modification parameters
/// \throws SonataError if the given modification name does not exist
const Modification& getModification(const std::string& name) const;
};
/**
* List of report parameters collected during the simulation
Expand Down
36 changes: 35 additions & 1 deletion python/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,41 @@ PYBIND11_MODULE(_libsonata, m) {
DOC_SIMULATIONCONFIG(Conditions, randomizeGabaRiseTime))
.def_readonly("mechanisms",
&SimulationConfig::Conditions::mechanisms,
DOC_SIMULATIONCONFIG(Conditions, mechanisms));
DOC_SIMULATIONCONFIG(Conditions, mechanisms))
.def_property_readonly("list_modification_names",
&SimulationConfig::Conditions::listModificationNames,
DOC_SIMULATIONCONFIG(Conditions, listModificationNames))
.def("modification",
&SimulationConfig::Conditions::getModification,
"name"_a,
DOC_SIMULATIONCONFIG(Conditions, getModification));

py::class_<SimulationConfig::ModificationBase> modificationBase(m, "ModificationBase");
modificationBase
.def_readonly("node_set",
&SimulationConfig::ModificationBase::nodeSet,
DOC_SIMULATIONCONFIG(ModificationBase, nodeSet))
.def_readonly("type",
&SimulationConfig::ModificationBase::type,
DOC_SIMULATIONCONFIG(ModificationBase, type));

py::class_<SimulationConfig::ModificationTTX, SimulationConfig::ModificationBase>(
m, "ModificationTTX");

py::class_<SimulationConfig::ModificationConfigureAllSections,
SimulationConfig::ModificationBase>(m, "ModificationConfigureAllSections")
.def_readonly("section_configure",
&SimulationConfig::ModificationConfigureAllSections::sectionConfigure,
DOC_SIMULATIONCONFIG(ModificationConfigureAllSections, sectionConfigure));

py::enum_<SimulationConfig::ModificationBase::ModificationType>(modificationBase,
"ModificationType")
.value("TTX",
SimulationConfig::ModificationBase::ModificationType::TTX,
DOC_SIMULATIONCONFIG(ModificationBase, ModificationType, TTX))
.value("ConfigureAllSections",
SimulationConfig::ModificationBase::ModificationType::ConfigureAllSections,
DOC_SIMULATIONCONFIG(ModificationBase, ModificationType, ConfigureAllSections));

py::class_<SimulationConfig::Report> report(m, "Report", "Parameters of a report");
report
Expand Down
42 changes: 42 additions & 0 deletions python/generated/docstrings.h
Original file line number Diff line number Diff line change
Expand Up @@ -545,11 +545,27 @@ R"doc(Extracellular calcium concentration, being applied to the synapse
uHill parameter in order to scale the U parameter of synapses. Default
is None.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Conditions_getModification =
R"doc(Returns the given modification parameters
Throws:
SonataError if the given modification name does not exist)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Conditions_listModificationNames = R"doc(Returns the names of the modifications)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Conditions_mechanisms =
R"doc(Properties to assign values to variables in synapse MOD files. The
format is a dictionary with keys being the SUFFIX names and values
being dictionaries of variables' names and values.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Conditions_minisSingleVesicle =
R"doc(Limit spontaneous release to single vesicle when true. Default is
false)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Conditions_modifications =
R"doc(Collection of dictionaries with each member decribing a modification
that mimics experimental manipulations to the circuit.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Conditions_randomizeGabaRiseTime =
R"doc(Enable legacy behavior to randomize the GABA_A rise time in the helper
functions. Default is false)doc";
Expand Down Expand Up @@ -792,6 +808,32 @@ static const char *__doc_bbp_sonata_SimulationConfig_InputSynapseReplay_source =

static const char *__doc_bbp_sonata_SimulationConfig_InputSynapseReplay_spikeFile = R"doc(The location of the file with the spike info for injection)doc";

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

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

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

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

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

static const char *__doc_bbp_sonata_SimulationConfig_ModificationBase_nodeSet = R"doc(Node set which receives the manipulation)doc";

static const char *__doc_bbp_sonata_SimulationConfig_ModificationBase_type =
R"doc(Name of the manipulation. Supported values are “TTX” and
“ConfigureAllSections”.)doc";

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

static const char *__doc_bbp_sonata_SimulationConfig_ModificationConfigureAllSections_sectionConfigure =
R"doc(For “ConfigureAllSections” manipulation, a snippet of python code to
perform one or more assignments involving section attributes, for all
sections that have all the referenced attributes. The format is
"%s.xxxx; %s.xxxx; ...".)doc";

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

static const char *__doc_bbp_sonata_SimulationConfig_Output = R"doc(Parameters to override simulator output for spike reports)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Output_SpikesSortOrder = R"doc()doc";
Expand Down
8 changes: 8 additions & 0 deletions python/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,14 @@ def test_basic(self):
'property1': False},
'GluSynapse': {'property4': 'test',
'property3': 0.025}})
self.assertEqual(self.config.conditions.list_modification_names, {"applyTTX", "no_SK_E2"})
self.assertEqual(self.config.conditions.modification("applyTTX").type.name, "TTX")
self.assertEqual(self.config.conditions.modification("applyTTX").node_set, "single")
self.assertEqual(self.config.conditions.modification("no_SK_E2").type.name,
"ConfigureAllSections")
self.assertEqual(self.config.conditions.modification("no_SK_E2").node_set, "single")
self.assertEqual(self.config.conditions.modification("no_SK_E2").section_configure,
"%s.gSK_E2bar_SK_E2 = 0")

self.assertEqual(self.config.list_report_names,
{ "axonal_comp_centers", "cell_imembrane", "compartment", "soma" })
Expand Down
58 changes: 58 additions & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ NLOHMANN_JSON_SERIALIZE_ENUM(SimulationConfig::SimulatorType,
{SimulationConfig::SimulatorType::NEURON, "NEURON"},
{SimulationConfig::SimulatorType::CORENEURON, "CORENEURON"}})

NLOHMANN_JSON_SERIALIZE_ENUM(
SimulationConfig::ModificationBase::ModificationType,
{{SimulationConfig::ModificationBase::ModificationType::invalid, nullptr},
{SimulationConfig::ModificationBase::ModificationType::TTX, "TTX"},
{SimulationConfig::ModificationBase::ModificationType::ConfigureAllSections,
"ConfigureAllSections"}})

namespace {
// to be replaced by std::filesystem once C++17 is used
namespace fs = ghc::filesystem;
Expand Down Expand Up @@ -460,6 +467,41 @@ void parseConditionsMechanisms(
}
}

void parseConditionsModifications(const nlohmann::json& it,
SimulationConfig::ModificationMap& buf) {
const auto sectionIt = it.find("modifications");
if (sectionIt == it.end()) {
return;
}
for (auto& mIt : sectionIt->items()) {
const auto valueIt = mIt.value();
const auto debugStr = fmt::format("modification {}", mIt.key());

SimulationConfig::ModificationBase::ModificationType type;
parseMandatory(valueIt, "type", debugStr, type);

switch (type) {
case SimulationConfig::ModificationBase::ModificationType::TTX: {
SimulationConfig::ModificationTTX result;
result.type = type;
parseMandatory(valueIt, "node_set", debugStr, result.nodeSet);
buf[mIt.key()] = result;
break;
}
case SimulationConfig::ModificationBase::ModificationType::ConfigureAllSections: {
SimulationConfig::ModificationConfigureAllSections result;
result.type = type;
parseMandatory(valueIt, "node_set", debugStr, result.nodeSet);
parseMandatory(valueIt, "section_configure", debugStr, result.sectionConfigure);
buf[mIt.key()] = result;
break;
}
default:
throw SonataError("Unknown modificationn type in " + debugStr);
}
}
}

} // namespace

class CircuitConfig::Parser
Expand Down Expand Up @@ -887,6 +929,7 @@ class SimulationConfig::Parser
result.randomizeGabaRiseTime,
{false});
parseConditionsMechanisms(*conditionsIt, result.mechanisms);
parseConditionsModifications(*conditionsIt, result.modifications);
return result;
}

Expand Down Expand Up @@ -1218,5 +1261,20 @@ const std::string& SimulationConfig::getExpandedJSON() const {
return _expandedJSON;
}

std::set<std::string> SimulationConfig::Conditions::listModificationNames() const {
return getMapKeys(modifications);
}

const SimulationConfig::Modification& SimulationConfig::Conditions::getModification(
const std::string& name) const {
const auto it = modifications.find(name);
if (it == modifications.end()) {
throw SonataError(
fmt::format("The modification '{}' is not present in the simulation config file",
name));
}
return it->second;
}

} // namespace sonata
} // namespace bbp
11 changes: 11 additions & 0 deletions tests/data/config/simulation_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@
"property3": 0.025,
"property4": "test"
}
},
"modifications": {
"applyTTX": {
"node_set": "single",
"type": "TTX"
},
"no_SK_E2": {
"node_set": "single",
"type": "ConfigureAllSections",
"section_configure": "%s.gSK_E2bar_SK_E2 = 0"
}
}
},
"inputs": {
Expand Down
12 changes: 12 additions & 0 deletions tests/test_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,18 @@ TEST_CASE("SimulationConfig") {
itr = config.getConditions().mechanisms.find("GluSynapse");
CHECK(nonstd::get<double>(itr->second.find("property3")->second) == 0.025);
CHECK(nonstd::get<std::string>(itr->second.find("property4")->second) == "test");
CHECK(config.getConditions().listModificationNames() ==
std::set<std::string>{"applyTTX", "no_SK_E2"});
const auto TTX = nonstd::get<SimulationConfig::ModificationTTX>(
config.getConditions().getModification("applyTTX"));
const auto configAllSects = nonstd::get<SimulationConfig::ModificationConfigureAllSections>(
config.getConditions().getModification("no_SK_E2"));
CHECK_THROWS_AS(config.getConditions().getModification("DoesNotExist"), SonataError);
CHECK(TTX.type == SimulationConfig::ModificationBase::ModificationType::TTX);
CHECK(TTX.nodeSet == "single");
CHECK(configAllSects.type ==
SimulationConfig::ModificationBase::ModificationType::ConfigureAllSections);
CHECK(configAllSects.sectionConfigure == "%s.gSK_E2bar_SK_E2 = 0");

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

Expand Down

0 comments on commit 5f08cd4

Please sign in to comment.