Skip to content

Commit

Permalink
Updates on the SimulationConfig parser (#227)
Browse files Browse the repository at this point in the history
* remove forward_skip key from run (BBPBGLIB-913)
* remove minis_single_vesicle key from conditions (BBPBGLIB-915)
* add keys for additional seedings (BBPBGLIB-920)
      stimulus_seed, ionchannel_seed, minis_seed, synapse_seed
* add series_resistance key in seclamp (BBPBGLIB-921)
* add keys neuromodulation_dtc and neuromodulation_strength in connection_overrides
(BBPBGLIB-885)

Co-authored-by: Mike Gevaert <[email protected]>
  • Loading branch information
WeinaJi and mgeplf authored Sep 29, 2022
1 parent 309da9b commit 24e7484
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 70 deletions.
27 changes: 21 additions & 6 deletions include/bbp/sonata/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,16 @@ class SONATA_API SimulationConfig
/// Selects the NEURON/CoreNEURON integration method. This parameter sets the NEURON
/// global variable h.secondorder. Default 0 ('euler')
IntegrationMethod integrationMethod;
/// Run without Stimulus or Reports for given duration prior to t=0
/// using a timestep computed as dt=0.1*forward_skip. Default = None
nonstd::optional<int> forwardSkip{nonstd::nullopt};
/// A non-negative integer used for seeding noise stimuli and any other future stochastic
/// stimuli, default is 0.
int stimulusSeed;
/// A non-negative integer used for seeding stochastic ion channels, default is 0.
int ionchannelSeed;
/// A non-negative integer used for seeding the Poisson processes that drives the minis,
/// default is 0.
int minisSeed;
/// A non-negative integer used for seeding stochastic synapses, default is 0.
int synapseSeed;
};
/**
* Parameters to override simulator output for spike reports
Expand Down Expand Up @@ -238,8 +245,6 @@ class SONATA_API SimulationConfig
/// Extracellular calcium concentration, being applied to the synapse uHill parameter in
/// order to scale the U parameter of synapses. Default is None.
nonstd::optional<double> extracellularCalcium{nonstd::nullopt};
/// Limit spontaneous release to single vesicle when true. Default is false
bool minisSingleVesicle;
/// Enable legacy behavior to randomize the GABA_A rise time in the helper functions.
/// Default is false
bool randomizeGabaRiseTime;
Expand Down Expand Up @@ -270,7 +275,9 @@ class SONATA_API SimulationConfig
/// For compartment type, select compartments to report.
/// Default value: "center"(for sections: soma), "all"(for other sections)
Compartments compartments;
/// The simulation variable to access
/// The simulation variable to access. The variables available are model dependent. For
/// summation type, it supports multiple variables by comma separated strings. E.g. “ina”,
/// "AdEx.V_M, v", "i_membrane, IClamp".
std::string variableName;
/// Descriptive text of the unit recorded. Not validated for correctness
std::string unit;
Expand Down Expand Up @@ -369,6 +376,8 @@ class SONATA_API SimulationConfig
struct InputSeclamp: public InputBase {
/// The membrane voltage the targeted cells should be held at (mV)
double voltage{};
/// The series resistance (Mohm), default is 0.01 Mohm
double seriesResistance{};
};

struct InputNoise: public InputBase {
Expand Down Expand Up @@ -508,6 +517,12 @@ class SONATA_API SimulationConfig
/// Adjustments from weight of this connection_override are applied after the specified
/// delay has elapsed in ms, default = 0.
double delay{0.};
/// To override the neuromod_dtc values between the selected source and target neurons for
/// the neuromodulatory projection. Given in ms.
nonstd::optional<double> neuromodulationDtc{nonstd::nullopt};
/// To override the neuromod_strength values between the selected source and target neurons
/// for the neuromodulatory projection. Given in muM.
nonstd::optional<double> neuromodulationStrength{nonstd::nullopt};
};
using ConnectionMap = std::unordered_map<std::string, ConnectionOverride>;

Expand Down
45 changes: 30 additions & 15 deletions python/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,9 +541,18 @@ PYBIND11_MODULE(_libsonata, m) {
.def_readonly("integration_method",
&SimulationConfig::Run::integrationMethod,
DOC_SIMULATIONCONFIG(Run, integrationMethod))
.def_readonly("forward_skip",
&SimulationConfig::Run::forwardSkip,
DOC_SIMULATIONCONFIG(Run, forwardSkip));
.def_readonly("stimulus_seed",
&SimulationConfig::Run::stimulusSeed,
DOC_SIMULATIONCONFIG(Run, stimulusSeed))
.def_readonly("ionchannel_seed",
&SimulationConfig::Run::ionchannelSeed,
DOC_SIMULATIONCONFIG(Run, ionchannelSeed))
.def_readonly("minis_seed",
&SimulationConfig::Run::minisSeed,
DOC_SIMULATIONCONFIG(Run, minisSeed))
.def_readonly("synapse_seed",
&SimulationConfig::Run::synapseSeed,
DOC_SIMULATIONCONFIG(Run, synapseSeed));

py::enum_<SimulationConfig::Run::SpikeLocation>(run, "SpikeLocation")
.value("soma", SimulationConfig::Run::SpikeLocation::soma)
Expand Down Expand Up @@ -592,9 +601,6 @@ PYBIND11_MODULE(_libsonata, m) {
.def_readonly("extracellular_calcium",
&SimulationConfig::Conditions::extracellularCalcium,
DOC_SIMULATIONCONFIG(Conditions, extracellularCalcium))
.def_readonly("minis_single_vesicle",
&SimulationConfig::Conditions::minisSingleVesicle,
DOC_SIMULATIONCONFIG(Conditions, minisSingleVesicle))
.def_readonly("randomize_gaba_rise_time",
&SimulationConfig::Conditions::randomizeGabaRiseTime,
DOC_SIMULATIONCONFIG(Conditions, randomizeGabaRiseTime))
Expand Down Expand Up @@ -734,7 +740,10 @@ PYBIND11_MODULE(_libsonata, m) {
py::class_<SimulationConfig::InputSeclamp, SimulationConfig::InputBase>(m, "Seclamp")
.def_readonly("voltage",
&SimulationConfig::InputSeclamp::voltage,
DOC_SIMULATIONCONFIG(InputSeclamp, voltage));
DOC_SIMULATIONCONFIG(InputSeclamp, voltage))
.def_readonly("series_resistance",
&SimulationConfig::InputSeclamp::seriesResistance,
DOC_SIMULATIONCONFIG(InputSeclamp, seriesResistance));

py::class_<SimulationConfig::InputNoise, SimulationConfig::InputBase>(m, "Noise")
.def_readonly("mean",
Expand Down Expand Up @@ -910,14 +919,16 @@ PYBIND11_MODULE(_libsonata, m) {
DOC_SIMULATIONCONFIG(ConnectionOverride, synapseDelayOverride))
.def_readonly("delay",
&SimulationConfig::ConnectionOverride::delay,
DOC_SIMULATIONCONFIG(ConnectionOverride, delay));

py::enum_<SimulationConfig::SimulatorType>(inputBase, "SimulatorType")
.value("NEURON", SimulationConfig::SimulatorType::NEURON)
.value("CORENEURON", SimulationConfig::SimulatorType::CORENEURON);

py::class_<SimulationConfig>(m, "SimulationConfig", "")
.def(py::init<const std::string&, const std::string&>())
DOC_SIMULATIONCONFIG(ConnectionOverride, delay))
.def_readonly("neuromodulation_dtc",
&SimulationConfig::ConnectionOverride::neuromodulationDtc,
DOC_SIMULATIONCONFIG(ConnectionOverride, neuromodulationDtc))
.def_readonly("neuromodulation_strength",
&SimulationConfig::ConnectionOverride::neuromodulationStrength,
DOC_SIMULATIONCONFIG(ConnectionOverride, neuromodulationStrength));

py::class_<SimulationConfig> simConf(m, "SimulationConfig", "");
simConf.def(py::init<const std::string&, const std::string&>())
.def_static(
"from_file",
[](py::object path) { return SimulationConfig::fromFile(py::str(path)); },
Expand Down Expand Up @@ -969,6 +980,10 @@ PYBIND11_MODULE(_libsonata, m) {
&SimulationConfig::getBetaFeatures,
DOC_SIMULATIONCONFIG(getBetaFeatures));

py::enum_<SimulationConfig::SimulatorType>(simConf, "SimulatorType")
.value("NEURON", SimulationConfig::SimulatorType::NEURON)
.value("CORENEURON", SimulationConfig::SimulatorType::CORENEURON);

bindPopulationClass<EdgePopulation>(
m, "EdgePopulation", "Collection of edges with attributes and connectivity index")
.def_property_readonly("source", &EdgePopulation::source, DOC_POP_EDGE(source))
Expand Down
39 changes: 30 additions & 9 deletions python/generated/docstrings.h
Original file line number Diff line number Diff line change
Expand Up @@ -550,10 +550,6 @@ 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_randomizeGabaRiseTime =
R"doc(Enable legacy behavior to randomize the GABA_A rise time in the helper
functions. Default is false)doc";
Expand All @@ -574,6 +570,14 @@ static const char *__doc_bbp_sonata_SimulationConfig_ConnectionOverride_modoverr
R"doc(Synapse helper files to instantiate the synapses in this
connection_override, default = None)doc";

static const char *__doc_bbp_sonata_SimulationConfig_ConnectionOverride_neuromodulationDtc =
R"doc(To override the neuromod_dtc values between the selected source and
target neurons for the neuromodulatory projection. Given in ms.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_ConnectionOverride_neuromodulationStrength =
R"doc(To override the neuromod_strength values between the selected source
and target neurons for the neuromodulatory projection. Given in muM.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_ConnectionOverride_source = R"doc(node_set specifying presynaptic nodes)doc";

static const char *__doc_bbp_sonata_SimulationConfig_ConnectionOverride_spontMinis =
Expand Down Expand Up @@ -754,6 +758,8 @@ R"doc(signal std dev as percentage of a cell’s threshold current

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

static const char *__doc_bbp_sonata_SimulationConfig_InputSeclamp_seriesResistance = R"doc(The series resistance (Mohm), default is 0.01 Mohm)doc";

static const char *__doc_bbp_sonata_SimulationConfig_InputSeclamp_voltage = R"doc(The membrane voltage the targeted cells should be held at (mV))doc";

static const char *__doc_bbp_sonata_SimulationConfig_InputShotNoise = R"doc()doc";
Expand Down Expand Up @@ -876,7 +882,10 @@ static const char *__doc_bbp_sonata_SimulationConfig_Report_type = R"doc(Report

static const char *__doc_bbp_sonata_SimulationConfig_Report_unit = R"doc(Descriptive text of the unit recorded. Not validated for correctness)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Report_variableName = R"doc(The simulation variable to access)doc";
static const char *__doc_bbp_sonata_SimulationConfig_Report_variableName =
R"doc(The simulation variable to access. The variables available are model
dependent. For summation type, it supports multiple variables by comma
separated strings. E.g. “ina”, "AdEx.V_M, v", "i_membrane, IClamp".)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run = R"doc(Parameters defining global simulation settings for spike reports)doc";

Expand All @@ -900,14 +909,18 @@ static const char *__doc_bbp_sonata_SimulationConfig_Run_SpikeLocation_soma = R"

static const char *__doc_bbp_sonata_SimulationConfig_Run_dt = R"doc(Integration step duration in milliseconds)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run_forwardSkip =
R"doc(Run without Stimulus or Reports for given duration prior to t=0 using
a timestep computed as dt=0.1*forward_skip. Default = None)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run_integrationMethod =
R"doc(Selects the NEURON/CoreNEURON integration method. This parameter sets
the NEURON global variable h.secondorder. Default 0 ('euler'))doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run_ionchannelSeed =
R"doc(A non-negative integer used for seeding stochastic ion channels,
default is 0.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run_minisSeed =
R"doc(A non-negative integer used for seeding the Poisson processes that
drives the minis, default is 0.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run_randomSeed = R"doc(Random seed)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run_spikeLocation =
Expand All @@ -916,6 +929,14 @@ is 'soma')doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run_spikeThreshold = R"doc(The spike detection threshold. Default is -30mV)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run_stimulusSeed =
R"doc(A non-negative integer used for seeding noise stimuli and any other
future stochastic stimuli, default is 0.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run_synapseSeed =
R"doc(A non-negative integer used for seeding stochastic synapses, default
is 0.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Run_tstop = R"doc(Biological simulation end time in milliseconds)doc";

static const char *__doc_bbp_sonata_SimulationConfig_SimulationConfig =
Expand Down
33 changes: 31 additions & 2 deletions python/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,10 @@ def test_basic(self):
self.assertEqual(self.config.run.spike_threshold, -30)
self.assertEqual(self.config.run.spike_location, Run.SpikeLocation.AIS)
self.assertEqual(self.config.run.integration_method, Run.IntegrationMethod.nicholson_ion)
self.assertEqual(self.config.run.forward_skip, 500)
self.assertEqual(self.config.run.stimulus_seed, 111)
self.assertEqual(self.config.run.ionchannel_seed, 222)
self.assertEqual(self.config.run.minis_seed, 333)
self.assertEqual(self.config.run.synapse_seed, 444)

self.assertEqual(self.config.output.output_dir,
os.path.abspath(os.path.join(PATH, 'config/some/path/output')))
Expand All @@ -714,7 +717,6 @@ def test_basic(self):
self.assertEqual(self.config.conditions.v_init, -80)
self.assertEqual(self.config.conditions.synapses_init_depleted, False)
self.assertEqual(self.config.conditions.extracellular_calcium, None)
self.assertEqual(self.config.conditions.minis_single_vesicle, False)
self.assertEqual(self.config.conditions.randomize_gaba_rise_time, False)
self.assertEqual(self.config.conditions.mechanisms, {'ProbAMPANMDA_EMS': {'property2': -1,
'property1': False},
Expand Down Expand Up @@ -849,6 +851,9 @@ def test_basic(self):
self.assertEqual(self.config.input('ex_rel_OU').mean_percent, 70)
self.assertEqual(self.config.input('ex_rel_OU').sd_percent, 10)

self.assertEqual(self.config.input('ex_seclamp').voltage, 1.1)
self.assertEqual(self.config.input('ex_seclamp').series_resistance, 0.5)

self.assertEqual(self.config.list_connection_override_names, {"ConL3Exc-Uni", "GABAB_erev"})
self.assertEqual(self.config.connection_override('ConL3Exc-Uni').source, 'Excitatory')
self.assertEqual(self.config.connection_override('ConL3Exc-Uni').target, 'Mosaic')
Expand All @@ -858,11 +863,15 @@ def test_basic(self):
self.assertEqual(self.config.connection_override('ConL3Exc-Uni').delay, 0.5)
self.assertEqual(self.config.connection_override('ConL3Exc-Uni').synapse_delay_override, None)
self.assertEqual(self.config.connection_override('ConL3Exc-Uni').synapse_configure, None)
self.assertEqual(self.config.connection_override('ConL3Exc-Uni').neuromodulation_dtc, None)
self.assertEqual(self.config.connection_override('ConL3Exc-Uni').neuromodulation_strength, None)
self.assertEqual(self.config.connection_override('GABAB_erev').spont_minis, None)
self.assertEqual(self.config.connection_override('GABAB_erev').synapse_delay_override, 0.5)
self.assertEqual(self.config.connection_override('GABAB_erev').delay, 0)
self.assertEqual(self.config.connection_override('GABAB_erev').modoverride, None)
self.assertEqual(self.config.connection_override('GABAB_erev').synapse_configure, '%s.e_GABAA = -82.0 tau_d_GABAB_ProbGABAAB_EMS = 77')
self.assertEqual(self.config.connection_override('GABAB_erev').neuromodulation_dtc, 100)
self.assertEqual(self.config.connection_override('GABAB_erev').neuromodulation_strength, 0.75)

self.assertEqual(self.config.metadata, {'sim_version': '1', 'note': 'first attempt of simulation'})
self.assertEqual(self.config.beta_features, {'v_str': 'abcd', 'v_int': 10, 'v_float': 0.5, 'v_bool': False})
Expand All @@ -871,6 +880,26 @@ def test_expanded_json(self):
config = json.loads(self.config.expanded_json)
self.assertEqual(config['output']['output_dir'], 'some/path/output')

def test_run(self):
contents = """
{
"manifest": {
"$CIRCUIT_DIR": "./circuit"
},
"network": "$CIRCUIT_DIR/circuit_config.json",
"run": {
"random_seed": 12345,
"dt": 0.05,
"tstop": 1000
}
}
"""
conf = SimulationConfig(contents, "./")
self.assertEqual(conf.run.stimulus_seed, 0)
self.assertEqual(conf.run.ionchannel_seed, 0)
self.assertEqual(conf.run.minis_seed, 0)
self.assertEqual(conf.run.synapse_seed, 0)


if __name__ == '__main__':
unittest.main()
16 changes: 12 additions & 4 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ SimulationConfig::Input parseInputModule(const nlohmann::json& valueIt,
SimulationConfig::InputSeclamp ret;
parseCommon(ret);
parseMandatory(valueIt, "voltage", debugStr, ret.voltage);
parseOptional(valueIt, "series_resistance", ret.seriesResistance, {0.01});
return ret;
}
case Module::ornstein_uhlenbeck: {
Expand Down Expand Up @@ -840,7 +841,10 @@ class SimulationConfig::Parser
"integration_method",
result.integrationMethod,
{Run::IntegrationMethod::euler});
parseOptional(*runIt, "forward_skip", result.forwardSkip);
parseOptional(*runIt, "stimulus_seed", result.stimulusSeed, {0});
parseOptional(*runIt, "ionchannel_seed", result.ionchannelSeed, {0});
parseOptional(*runIt, "minis_seed", result.minisSeed, {0});
parseOptional(*runIt, "synapse_seed", result.synapseSeed, {0});
return result;
}

Expand Down Expand Up @@ -878,7 +882,6 @@ class SimulationConfig::Parser
result.synapsesInitDepleted,
{false});
parseOptional(*conditionsIt, "extracellular_calcium", result.extracellularCalcium);
parseOptional(*conditionsIt, "minis_single_vesicle", result.minisSingleVesicle, {false});
parseOptional(*conditionsIt,
"randomize_gaba_rise_time",
result.randomizeGabaRiseTime,
Expand Down Expand Up @@ -917,8 +920,11 @@ class SimulationConfig::Parser
parseOptional(valueIt, "file_name", report.fileName, {it.key() + "_SONATA.h5"});
parseOptional(valueIt, "enabled", report.enabled, {true});

// Validate comma separated strings
const std::regex expr(R"(\w+(?:\s*,\s*\w+)*)");
// variable names can look like:
// `v`, or `i_clamp`, or `Foo.bar` but not `..asdf`, or `asdf..` or `asdf.asdf.asdf`
const char* const varName = R"(\w+(?:\.?\w+)?)";
// variable names are separated by `,` with any amount of whitespace separating them
const std::regex expr(fmt::format(R"({}(?:\s*,\s*{})*)", varName, varName));
if (!std::regex_match(report.variableName, expr)) {
throw SonataError(fmt::format("Invalid comma separated variable names '{}'",
report.variableName));
Expand Down Expand Up @@ -1064,6 +1070,8 @@ class SimulationConfig::Parser
parseOptional(valueIt, "modoverride", connect.modoverride);
parseOptional(valueIt, "synapse_delay_override", connect.synapseDelayOverride);
parseOptional(valueIt, "delay", connect.delay);
parseOptional(valueIt, "neuromodulation_dtc", connect.neuromodulationDtc);
parseOptional(valueIt, "neuromodulation_strength", connect.neuromodulationStrength);
}
return result;
}
Expand Down
Loading

0 comments on commit 24e7484

Please sign in to comment.