Skip to content

Commit

Permalink
Initial simulation config implementation (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
NadirRoGue authored Nov 30, 2021
1 parent 0776f58 commit 148a9eb
Show file tree
Hide file tree
Showing 8 changed files with 608 additions and 11 deletions.
107 changes: 107 additions & 0 deletions include/bbp/sonata/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,5 +175,112 @@ class SONATA_API CircuitConfig
std::unordered_map<std::string, PopulationProperties> _edgePopulationProperties;
};

/**
* Read access to a SONATA simulation config file.
*/
class SONATA_API SimulationConfig
{
public:
/**
* Parameters defining global simulation settings for spike reports
*/
struct Run {
/// Biological simulation end time in milliseconds
float tstop{};
/// Integration step duration in milliseconds
float dt{};
};
/**
* Parameters to override simulator output for spike reports
*/
struct Output {
/// Spike report file output directory. Default is "output"
std::string outputDir;
/// Spike report file name. Default is "out.h5"
std::string spikesFile;
};
/**
* List of report parameters collected during the simulation
*/
struct Report {
/// Node sets on which to report
std::string cells;
/// Report type. Possible values: "compartment", "summation", "synapse"
std::string type;
/// Interval between reporting steps in milliseconds
float dt{};
/// Time to step reporting in milliseconds
float startTime{};
/// Time to stop reporting in milliseconds
float endTime{};
/// Report filename. Default is "<report name>_SONATA.h5"
std::string fileName;
};

/**
* Parses a SONATA JSON simulation configuration file.
*
* \throws SonataError on:
* - Ill-formed JSON
* - Missing mandatory entries (in any depth)
*/
SimulationConfig(const std::string& content, const std::string& basePath);

/**
* Loads a SONATA JSON simulation config file from disk and returns a CircuitConfig object
* which parses it.
*
* \throws SonataError on:
* - Non accesible file (does not exists / does not have read access)
* - Ill-formed JSON
* - Missing mandatory entries (in any depth)
*/
static SimulationConfig fromFile(const std::string& path);

/**
* Returns the base path of the simulation config file
*/
const std::string& getBasePath() const noexcept;

/**
* Returns the JSON content of the simulation config file
*/
const std::string& getJSON() const noexcept;

/**
* Returns the Run section of the simulation configuration.
*/
const Run& getRun() const noexcept;

/**
* Returns the Output section of the simulation configuration.
*/
const Output& getOutput() const noexcept;

/**
* Returns the given report parameters.
*
* \throws SonataError if the given report name does not correspond with any existing
* report.
*/
const Report& getReport(const std::string& name) const;

private:
// JSON string
const std::string _jsonContent;
// Base path of the simulation config file
const std::string _basePath;

// Run section
Run _run;
// Output section
Output _output;
// List of reports
std::unordered_map<std::string, Report> _reports;

class Parser;
friend class Parser;
};

} // namespace sonata
} // namespace bbp
45 changes: 45 additions & 0 deletions python/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,51 @@ PYBIND11_MODULE(_libsonata, m) {
.def("edge_population_properties", &CircuitConfig::getEdgePopulationProperties, "name"_a)
.def_property_readonly("expanded_json", &CircuitConfig::getExpandedJSON);

py::class_<SimulationConfig::Run>(m,
"Run",
"Stores parameters defining global simulation settings")
.def_readonly("tstop",
&SimulationConfig::Run::tstop,
"Biological simulation end time in milliseconds")
.def_readonly("dt",
&SimulationConfig::Run::dt,
"Simulation integration step in milliseconds");

py::class_<SimulationConfig::Output>(m,
"Output",
"Stores overriden parameters of simulation output")
.def_readonly("output_dir",
&SimulationConfig::Output::outputDir,
"Simulation output directory")
.def_readonly("spikes_file",
&SimulationConfig::Output::spikesFile,
"Spike report filename");

py::class_<SimulationConfig::Report>(m, "Report", "List of parameters of a report")
.def_readonly("cells", &SimulationConfig::Report::cells, "Node sets on which to report")
.def_readonly("type",
&SimulationConfig::Report::type,
"Report type. Possible values are 'compartment', 'summation', 'synapse")
.def_readonly("dt",
&SimulationConfig::Report::dt,
"Interval between reporting steps in milliseconds")
.def_readonly("start_time",
&SimulationConfig::Report::startTime,
"Time to start reporting, in milliseconds")
.def_readonly("end_time",
&SimulationConfig::Report::endTime,
"Time to stop reporting in milliseconds")
.def_readonly("file_name", &SimulationConfig::Report::fileName, "Report file name");

py::class_<SimulationConfig>(m, "SimulationConfig", "")
.def(py::init<const std::string&, const std::string&>())
.def_static("from_file",
[](py::object path) { return SimulationConfig::fromFile(py::str(path)); })
.def_property_readonly("base_path", &SimulationConfig::getBasePath)
.def_property_readonly("json", &SimulationConfig::getJSON)
.def_property_readonly("run", &SimulationConfig::getRun)
.def_property_readonly("output", &SimulationConfig::getOutput)
.def("report", &SimulationConfig::getReport, "name"_a);

bindPopulationClass<EdgePopulation>(
m, "EdgePopulation", "Collection of edges with attributes and connectivity index")
Expand Down
71 changes: 71 additions & 0 deletions python/generated/docstrings.h
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,77 @@ static const char *__doc_bbp_sonata_Selection_ranges = R"doc(Get a list of range

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

static const char *__doc_bbp_sonata_SimulationConfig = R"doc(Read access to a SONATA simulation config file.)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_outputDir = R"doc(Spike report file output directory. Default is "output")doc";

static const char *__doc_bbp_sonata_SimulationConfig_Output_spikesFile = R"doc(Spike report file name. Default is "out.h5")doc";

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

static const char *__doc_bbp_sonata_SimulationConfig_Report = R"doc(List of report parameters collected during the simulation)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Report_cells = R"doc(Node sets on which to report)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Report_dt = R"doc(Interval between reporting steps in milliseconds)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Report_endTime = R"doc(Time to stop reporting in milliseconds)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Report_fileName = R"doc(Report filename. Default is "<report name>_SONATA.h5")doc";

static const char *__doc_bbp_sonata_SimulationConfig_Report_startTime = R"doc(Time to step reporting in milliseconds)doc";

static const char *__doc_bbp_sonata_SimulationConfig_Report_type = R"doc(Report type. Possible values: "compartment", "summation", "synapse")doc";

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

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_tstop = R"doc(Biological simulation end time in milliseconds)doc";

static const char *__doc_bbp_sonata_SimulationConfig_SimulationConfig =
R"doc(Parses a SONATA JSON simulation configuration file.
Throws:
s SonataError on: - Ill-formed JSON - Missing mandatory entries
(in any depth))doc";

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

static const char *__doc_bbp_sonata_SimulationConfig_fromFile =
R"doc(Loads a SONATA JSON simulation config file from disk and returns a
CircuitConfig object which parses it.
Throws:
s SonataError on: - Non accesible file (does not exists / does not
have read access) - Ill-formed JSON - Missing mandatory entries
(in any depth))doc";

static const char *__doc_bbp_sonata_SimulationConfig_getBasePath = R"doc(Returns the base path of the simulation config file)doc";

static const char *__doc_bbp_sonata_SimulationConfig_getJSON = R"doc(Returns the JSON content of the simulation config file)doc";

static const char *__doc_bbp_sonata_SimulationConfig_getOutput = R"doc(Returns the Output section of the simulation configuration.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_getReport =
R"doc(Returns the given report parameters.
Throws:
s SonataError if the given report name does not correspond with
any existing report.)doc";

static const char *__doc_bbp_sonata_SimulationConfig_getRun = R"doc(Returns the Run section of the simulation configuration.)doc";

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

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

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

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

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

static const char *__doc_bbp_sonata_SonataError_SonataError = R"doc()doc";
Expand Down
1 change: 1 addition & 0 deletions python/libsonata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from libsonata._libsonata import (
CircuitConfig,
SimulationConfig,
EdgePopulation,
EdgeStorage,
ElementDataFrame,
Expand Down
30 changes: 29 additions & 1 deletion python/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
SomaReportReader, SomaReportPopulation,
ElementReportReader, ElementReportPopulation,
NodeSets,
CircuitConfig
CircuitConfig, SimulationConfig
)


Expand Down Expand Up @@ -540,5 +540,33 @@ def test_get_population_properties(self):
self.assertTrue(edge_prop.biophysical_neuron_models_dir.endswith('biophysical_neuron_models'))
self.assertEqual(edge_prop.alternate_morphology_formats, {})


class TestSimulationConfig(unittest.TestCase):
def setUp(self):
self.config = SimulationConfig.from_file(
os.path.join(PATH, 'config/simulation_config.json'))

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.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('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)

def test_json(self):
temp_config = json.loads(self.config.json)
self.assertEqual(temp_config['run']['tstop'], 1000)

if __name__ == '__main__':
unittest.main()
Loading

0 comments on commit 148a9eb

Please sign in to comment.