diff --git a/include/bbp/sonata/config.h b/include/bbp/sonata/config.h index f6efb300..16eb137f 100644 --- a/include/bbp/sonata/config.h +++ b/include/bbp/sonata/config.h @@ -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 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 @@ -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 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; @@ -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; @@ -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 { @@ -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 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 neuromodulationStrength{nonstd::nullopt}; }; using ConnectionMap = std::unordered_map; diff --git a/python/bindings.cpp b/python/bindings.cpp index 76306d50..ceb8f9e4 100644 --- a/python/bindings.cpp +++ b/python/bindings.cpp @@ -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_(run, "SpikeLocation") .value("soma", SimulationConfig::Run::SpikeLocation::soma) @@ -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)) @@ -734,7 +740,10 @@ PYBIND11_MODULE(_libsonata, m) { py::class_(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_(m, "Noise") .def_readonly("mean", @@ -910,14 +919,16 @@ PYBIND11_MODULE(_libsonata, m) { DOC_SIMULATIONCONFIG(ConnectionOverride, synapseDelayOverride)) .def_readonly("delay", &SimulationConfig::ConnectionOverride::delay, - DOC_SIMULATIONCONFIG(ConnectionOverride, delay)); - - py::enum_(inputBase, "SimulatorType") - .value("NEURON", SimulationConfig::SimulatorType::NEURON) - .value("CORENEURON", SimulationConfig::SimulatorType::CORENEURON); - - py::class_(m, "SimulationConfig", "") - .def(py::init()) + 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_ simConf(m, "SimulationConfig", ""); + simConf.def(py::init()) .def_static( "from_file", [](py::object path) { return SimulationConfig::fromFile(py::str(path)); }, @@ -969,6 +980,10 @@ PYBIND11_MODULE(_libsonata, m) { &SimulationConfig::getBetaFeatures, DOC_SIMULATIONCONFIG(getBetaFeatures)); + py::enum_(simConf, "SimulatorType") + .value("NEURON", SimulationConfig::SimulatorType::NEURON) + .value("CORENEURON", SimulationConfig::SimulatorType::CORENEURON); + bindPopulationClass( m, "EdgePopulation", "Collection of edges with attributes and connectivity index") .def_property_readonly("source", &EdgePopulation::source, DOC_POP_EDGE(source)) diff --git a/python/generated/docstrings.h b/python/generated/docstrings.h index 2b6b8fb0..a012dd79 100644 --- a/python/generated/docstrings.h +++ b/python/generated/docstrings.h @@ -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"; @@ -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 = @@ -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"; @@ -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"; @@ -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 = @@ -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 = diff --git a/python/tests/test.py b/python/tests/test.py index f0d978aa..20e6ff9b 100644 --- a/python/tests/test.py +++ b/python/tests/test.py @@ -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'))) @@ -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}, @@ -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') @@ -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}) @@ -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() diff --git a/src/config.cpp b/src/config.cpp index 47324394..7ea6590a 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -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: { @@ -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; } @@ -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, @@ -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)); @@ -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; } diff --git a/tests/data/config/simulation_config.json b/tests/data/config/simulation_config.json index e6f12c05..40c7712d 100644 --- a/tests/data/config/simulation_config.json +++ b/tests/data/config/simulation_config.json @@ -18,6 +18,10 @@ "tstop": 1000, "dt": 0.025, "random_seed": 201506, + "stimulus_seed": 111, + "ionchannel_seed": 222, + "minis_seed": 333, + "synapse_seed": 444, "spike_location": "AIS", "integration_method" : 2, "forward_skip": 500 @@ -102,7 +106,8 @@ "delay": 0, "duration": 1000, "node_set": "L5E", - "voltage": 1.1 + "voltage": 1.1, + "series_resistance": 0.5 }, "ex_noise_meanpercent": { "input_type": "current_clamp", @@ -123,18 +128,6 @@ "duration": 5000.0, "node_set": "Rt_RC" }, - "ex_shotnoise": { - "input_type": "current_clamp", - "module": "shot_noise", - "delay": 0, - "duration": 1000, - "decay_time": 4, - "rise_time": 0.4, - "amp_mean": 70, - "amp_var": 40, - "rate": 4, - "node_set": "L5E" - }, "ex_rel_shotnoise": { "input_type": "current_clamp", "module": "relative_shot_noise", @@ -159,21 +152,6 @@ "sigma": 5, "node_set": "L5E" }, - "ex_hyperpolarizing": { - "input_type": "current_clamp", - "module": "hyperpolarizing", - "delay": 0, - "duration": 1000, - "node_set": "L5E" - }, - "ex_seclamp": { - "input_type": "voltage_clamp", - "module": "seclamp", - "delay": 0, - "duration": 1000, - "node_set": "L5E", - "voltage": 1.1 - }, "ex_replay": { "input_type": "spikes", "module": "synapse_replay", @@ -227,7 +205,9 @@ "target": "Mosaic", "weight": 1.0, "synapse_delay_override": 0.5, - "synapse_configure": "%s.e_GABAA = -82.0 tau_d_GABAB_ProbGABAAB_EMS = 77" + "synapse_configure": "%s.e_GABAA = -82.0 tau_d_GABAB_ProbGABAAB_EMS = 77", + "neuromodulation_dtc": 100, + "neuromodulation_strength": 0.75 } }, "reports": { @@ -257,7 +237,7 @@ "cells": "Mosaic", "sections": "axon", "type": "compartment", - "variable_name": "v", + "variable_name": "AdEx.V_M,v", "unit": "mV", "compartments": "center", "scaling": "none", diff --git a/tests/test_config.cpp b/tests/test_config.cpp index b591336c..92af9a20 100644 --- a/tests/test_config.cpp +++ b/tests/test_config.cpp @@ -307,7 +307,10 @@ TEST_CASE("SimulationConfig") { CHECK(config.getRun().spikeThreshold == -30); CHECK(config.getRun().spikeLocation == SimulationConfig::Run::SpikeLocation::AIS); CHECK(config.getRun().integrationMethod == SimulationConfig::Run::IntegrationMethod::nicholson_ion); - CHECK(config.getRun().forwardSkip == 500); + CHECK(config.getRun().stimulusSeed == 111); + CHECK(config.getRun().ionchannelSeed == 222); + CHECK(config.getRun().minisSeed == 333); + CHECK(config.getRun().synapseSeed == 444); namespace fs = ghc::filesystem; const auto basePath = fs::absolute( @@ -325,7 +328,6 @@ TEST_CASE("SimulationConfig") { CHECK(config.getConditions().vInit == -80); CHECK(config.getConditions().synapsesInitDepleted == false); CHECK(config.getConditions().extracellularCalcium == nonstd::nullopt); - CHECK(config.getConditions().minisSingleVesicle == false); CHECK(config.getConditions().randomizeGabaRiseTime == false); CHECK(config.getConditions().mechanisms.size() == 2); auto itr = config.getConditions().mechanisms.find("ProbAMPANMDA_EMS"); @@ -489,6 +491,7 @@ TEST_CASE("SimulationConfig") { CHECK(input.duration == 1000.); CHECK(input.nodeSet == "L5E"); CHECK(input.voltage == 1.1); + CHECK(input.seriesResistance == 0.5); } { const auto input = nonstd::get( @@ -546,18 +549,23 @@ TEST_CASE("SimulationConfig") { CHECK(config.getConnectionOverride("ConL3Exc-Uni").delay == 0.5); CHECK(config.getConnectionOverride("ConL3Exc-Uni").synapseDelayOverride == nonstd::nullopt); CHECK(config.getConnectionOverride("ConL3Exc-Uni").synapseConfigure == nonstd::nullopt); + CHECK(config.getConnectionOverride("ConL3Exc-Uni").neuromodulationDtc == nonstd::nullopt); + CHECK(config.getConnectionOverride("ConL3Exc-Uni").neuromodulationStrength == + nonstd::nullopt); CHECK(config.getConnectionOverride("GABAB_erev").spontMinis == nonstd::nullopt); CHECK(config.getConnectionOverride("GABAB_erev").synapseDelayOverride == 0.5); CHECK(config.getConnectionOverride("GABAB_erev").delay == 0); CHECK(config.getConnectionOverride("GABAB_erev").synapseConfigure == "%s.e_GABAA = -82.0 tau_d_GABAB_ProbGABAAB_EMS = 77"); CHECK(config.getConnectionOverride("GABAB_erev").modoverride == nonstd::nullopt); + CHECK(config.getConnectionOverride("GABAB_erev").neuromodulationDtc == 100); + CHECK(config.getConnectionOverride("GABAB_erev").neuromodulationStrength == 0.75); CHECK(config.getMetaData().size() == 2); CHECK(config.getBetaFeatures().size() == 4); } - SECTION("manifest_network") { + SECTION("manifest_network_run") { auto contents = R"({ "manifest": { "$CIRCUIT_DIR": "./circuit" @@ -577,6 +585,10 @@ TEST_CASE("SimulationConfig") { CHECK(config.getTargetSimulator() == SimulationConfig::SimulatorType::NEURON); // default CHECK(config.getNodeSetsFile() == ""); // network file is not readable so default empty CHECK(config.getNodeSet() == nonstd::nullopt); // default + CHECK(config.getRun().stimulusSeed == 0); + CHECK(config.getRun().ionchannelSeed == 0); + CHECK(config.getRun().minisSeed == 0); + CHECK(config.getRun().synapseSeed == 0); } SECTION("Exception") { @@ -684,6 +696,7 @@ TEST_CASE("SimulationConfig") { { // No variable_name in a report object auto contents = R"({ "run": { + "random_seed": 12345, "dt": 0.05, "tstop": 1000 }, @@ -699,9 +712,10 @@ TEST_CASE("SimulationConfig") { })"; CHECK_THROWS_AS(SimulationConfig(contents, "./"), SonataError); } - { // Wrong variable_name in a report object + { // Wrong variable_name in a report object: no variable after ',' auto contents = R"({ "run": { + "random_seed": 12345, "dt": 0.05, "tstop": 1000 }, @@ -718,6 +732,66 @@ TEST_CASE("SimulationConfig") { })"; CHECK_THROWS_AS(SimulationConfig(contents, "./"), SonataError); } + { // Wrong variable_name in a report object: leading '.' + auto contents = R"({ + "run": { + "random_seed": 12345, + "dt": 0.05, + "tstop": 1000 + }, + "reports": { + "test": { + "cells": "nodesetstring", + "variable_name": ".V_M, V", + "type": "compartment", + "dt": 0.05, + "start_time": 0, + "end_time": 500 + } + } + })"; + CHECK_THROWS_AS(SimulationConfig(contents, "./"), SonataError); + } + { // Wrong variable_name in a report object: more than one '.' in a name + auto contents = R"({ + "run": { + "random_seed": 12345, + "dt": 0.05, + "tstop": 1000 + }, + "reports": { + "test": { + "cells": "nodesetstring", + "variable_name": "AdEx..foo, V", + "type": "compartment", + "dt": 0.05, + "start_time": 0, + "end_time": 500 + } + } + })"; + CHECK_THROWS_AS(SimulationConfig(contents, "./"), SonataError); + } + { // Wrong variable_name in a report object: more than one '.' in a name + auto contents = R"({ + "run": { + "random_seed": 12345, + "dt": 0.05, + "tstop": 1000 + }, + "reports": { + "test": { + "cells": "nodesetstring", + "variable_name": "AdEx.V_M.foo, V", + "type": "compartment", + "dt": 0.05, + "start_time": 0, + "end_time": 500 + } + } + })"; + CHECK_THROWS_AS(SimulationConfig(contents, "./"), SonataError); + } { // No dt in a report object auto contents = R"({ "run": {