diff --git a/miniapp/io.cpp b/miniapp/io.cpp index 6664cf47e4ddbf1fcd33cd4589553a29cb967255..ac7573ccec32a4036f49c515b80047ccb602a1e0 100644 --- a/miniapp/io.cpp +++ b/miniapp/io.cpp @@ -1,13 +1,37 @@ -#include <fstream> #include <exception> +#include <fstream> +#include <istream> #include <tclap/CmdLine.h> #include <json/src/json.hpp> +#include <util/optional.hpp> + #include "io.hpp" +// Let TCLAP understand value arguments that are of an optional type. + +template <typename V> +struct TCLAP::ArgTraits<nest::mc::util::optional<V>> { + using ValueCategory = ValueLike; +}; + namespace nest { namespace mc { + +// Using static here because we do not want external linkage for this operator + +namespace util { + template <typename V> + static std::istream& operator>>(std::istream& I, optional<V>& v) { + V u; + if (I >> u) { + v = u; + } + return I; + } +} + namespace io { /// read simulation options from json file with name fname @@ -17,7 +41,8 @@ namespace io { cl_options read_options(int argc, char** argv) { // set default options - const cl_options defopts{"", 1000, 500, "expsyn", 100, 100., 0.025, false}; + const cl_options defopts{"", 1000, 500, "expsyn", 100, 100., 0.025, false, + false, 1.0, "trace_", util::nothing}; cl_options options; // parse command line arguments @@ -47,6 +72,17 @@ cl_options read_options(int argc, char** argv) { false, defopts.dt, "positive real number", cmd); TCLAP::SwitchArg all_to_all_arg( "m","alltoall","all to all network", cmd, false); + TCLAP::ValueArg<double> probe_ratio_arg( + "p", "probe-ratio", "proportion of cells to probe", + false, defopts.probe_ratio, "real number in [0,1]", cmd); + TCLAP::SwitchArg probe_soma_only_arg( + "X", "probe-soma-only", "only probe cell somas, not dendrites", cmd, false); + TCLAP::ValueArg<std::string> trace_prefix_arg( + "P", "trace-prefix", "write traces to files with this prefix", + false, defopts.trace_prefix, "stringr", cmd); + TCLAP::ValueArg<util::optional<unsigned>> trace_max_gid_arg( + "T", "trace-max-gid", "only trace probes on cells up to this gid", + false, defopts.trace_max_gid, "unisgned integer", cmd); cmd.parse(argc, argv); @@ -58,6 +94,10 @@ cl_options read_options(int argc, char** argv) { options.tfinal = tfinal_arg.getValue(); options.dt = dt_arg.getValue(); options.all_to_all = all_to_all_arg.getValue(); + options.probe_ratio = probe_ratio_arg.getValue(); + options.probe_soma_only = probe_soma_only_arg.getValue(); + options.trace_prefix = trace_prefix_arg.getValue(); + options.trace_max_gid = trace_max_gid_arg.getValue(); } // catch any exceptions in command line handling catch (TCLAP::ArgException& e) { @@ -100,6 +140,14 @@ std::ostream& operator<<(std::ostream& o, const cl_options& options) { o << " simulation time : " << options.tfinal << "\n"; o << " dt : " << options.dt << "\n"; o << " all to all network : " << (options.all_to_all ? "yes" : "no") << "\n"; + o << " probe ratio : " << options.probe_ratio << "\n"; + o << " probe soma only : " << (options.probe_soma_only ? "yes" : "no") << "\n"; + o << " trace prefix : " << options.trace_prefix << "\n"; + o << " trace max gid : "; + if (options.trace_max_gid) { + o << *options.trace_max_gid; + } + o << "\n"; o << " input file name : " << options.ifname << "\n"; return o; diff --git a/miniapp/io.hpp b/miniapp/io.hpp index dab584fe2a132f289bb9a2f1ae02711aa29ef5a4..71af61810670d7a1f226d3eec2dabfd2f38ff20e 100644 --- a/miniapp/io.hpp +++ b/miniapp/io.hpp @@ -6,6 +6,8 @@ #include <stdexcept> #include <utility> +#include <util/optional.hpp> + namespace nest { namespace mc { namespace io { @@ -20,6 +22,10 @@ struct cl_options { double tfinal; double dt; bool all_to_all; + bool probe_soma_only; + double probe_ratio; + std::string trace_prefix; + util::optional<unsigned> trace_max_gid; }; class usage_error: public std::runtime_error { diff --git a/miniapp/miniapp.cpp b/miniapp/miniapp.cpp index 9b26ff86ef37f829667161afca27a129791de3ed..3e9d4dd227efbb90823b99db2fedd00cc94e4f81 100644 --- a/miniapp/miniapp.cpp +++ b/miniapp/miniapp.cpp @@ -32,7 +32,7 @@ using model_type = model<lowered_cell>; using sample_trace_type = sample_trace<model_type::time_type, model_type::value_type>; void banner(); -std::unique_ptr<recipe> make_recipe(const io::cl_options&); +std::unique_ptr<recipe> make_recipe(const io::cl_options&, const probe_distribution&); std::unique_ptr<sample_trace_type> make_trace(cell_member_type probe_id, probe_spec probe); std::pair<cell_gid_type, cell_gid_type> distribute_cells(cell_size_type ncells); @@ -53,7 +53,12 @@ int main(int argc, char** argv) { << std::ceil(options.tfinal / options.dt) << " steps of " << options.dt << " ms" << std::endl; - auto recipe = make_recipe(options); + // determine what to attach probes to + probe_distribution pdist; + pdist.proportion = options.probe_ratio; + pdist.all_segments = !options.probe_soma_only; + + auto recipe = make_recipe(options, pdist); auto cell_range = distribute_cells(recipe->num_cells()); // build model from recipe @@ -69,6 +74,10 @@ int main(int argc, char** argv) { std::vector<std::unique_ptr<sample_trace_type>> traces; const model_type::time_type sample_dt = 0.1; for (auto probe: m.probes()) { + if (options.trace_max_gid && probe.id.gid>*options.trace_max_gid) { + continue; + } + traces.push_back(make_trace(probe.id, probe.probe)); m.attach_sampler(probe.id, make_trace_sampler(traces.back().get(),sample_dt)); } @@ -81,7 +90,7 @@ int main(int argc, char** argv) { // save traces for (const auto& trace: traces) { - write_trace_json(*trace.get()); + write_trace_json(*trace.get(), options.trace_prefix); } } catch (io::usage_error& e) { @@ -119,7 +128,7 @@ void banner() { std::cout << "====================\n"; } -std::unique_ptr<recipe> make_recipe(const io::cl_options& options) { +std::unique_ptr<recipe> make_recipe(const io::cl_options& options, const probe_distribution& pdist) { basic_recipe_param p; p.num_compartments = options.compartments_per_segment; @@ -127,17 +136,17 @@ std::unique_ptr<recipe> make_recipe(const io::cl_options& options) { p.synapse_type = options.syn_type; if (options.all_to_all) { - return make_basic_kgraph_recipe(options.cells, p); + return make_basic_kgraph_recipe(options.cells, p, pdist); } else { - return make_basic_rgraph_recipe(options.cells, p); + return make_basic_rgraph_recipe(options.cells, p, pdist); } } std::unique_ptr<sample_trace_type> make_trace(cell_member_type probe_id, probe_spec probe) { std::string name = ""; std::string units = ""; - + switch (probe.kind) { case probeKind::membrane_voltage: name = "v"; diff --git a/miniapp/miniapp_recipes.cpp b/miniapp/miniapp_recipes.cpp index 22c59bd851a049e448784b9cfdd635d7e7a96970..742951dff6df83cb13c2f13af6e2d1ace2ae97eb 100644 --- a/miniapp/miniapp_recipes.cpp +++ b/miniapp/miniapp_recipes.cpp @@ -76,13 +76,15 @@ public: EXPECTS(cell.detectors().size()==cc.num_sources); // add probes - unsigned n_probe_segs = pdist_.all_segments? basic_cell_segments: 1u; - for (unsigned i = 0; i<n_probe_segs; ++i) { - if (pdist_.membrane_voltage) { - cell.add_probe({{i, i? 0.5: 0.0}, mc::probeKind::membrane_voltage}); - } - if (pdist_.membrane_current) { - cell.add_probe({{i, i? 0.5: 0.0}, mc::probeKind::membrane_current}); + if (cc.num_probes) { + unsigned n_probe_segs = pdist_.all_segments? basic_cell_segments: 1u; + for (unsigned i = 0; i<n_probe_segs; ++i) { + if (pdist_.membrane_voltage) { + cell.add_probe({{i, i? 0.5: 0.0}, mc::probeKind::membrane_voltage}); + } + if (pdist_.membrane_current) { + cell.add_probe({{i, i? 0.5: 0.0}, mc::probeKind::membrane_current}); + } } } EXPECTS(cell.probes().size()==cc.num_probes);