From 025bed06b6297a1dd7de32f6a19a3e1d11c52927 Mon Sep 17 00:00:00 2001 From: Ben Cumming <bcumming@cscs.ch> Date: Thu, 29 Aug 2019 11:41:00 +0200 Subject: [PATCH] Consistent source naming and layout for examples (#848) Refactor the example code so that all examples have a single C++ source file, and the source file, source path and executable all have the same name. Fixes #847. --- example/bench/CMakeLists.txt | 2 +- example/bench/bench.cpp | 171 ++++++++++- example/bench/parameters.cpp | 81 ------ example/bench/parameters.hpp | 43 --- example/bench/readme.md | 2 +- example/bench/recipe.cpp | 72 ----- example/bench/recipe.hpp | 22 -- example/brunel/CMakeLists.txt | 8 +- .../brunel/{brunel_miniapp.cpp => brunel.cpp} | 265 ++++++++++++++++-- example/brunel/io.cpp | 207 -------------- example/brunel/io.hpp | 56 ---- example/brunel/readme.md | 2 +- example/dryrun/dryrun.cpp | 71 ++++- example/dryrun/parameters.hpp | 81 ------ example/gap_junctions/CMakeLists.txt | 2 +- example/gap_junctions/gap_junctions.cpp | 58 +++- example/gap_junctions/parameters.hpp | 65 ----- example/generators/CMakeLists.txt | 6 +- .../{event_gen.cpp => generators.cpp} | 0 example/ring/parameters.hpp | 81 ------ example/ring/ring.cpp | 76 ++++- 21 files changed, 622 insertions(+), 749 deletions(-) delete mode 100644 example/bench/parameters.cpp delete mode 100644 example/bench/parameters.hpp delete mode 100644 example/bench/recipe.cpp delete mode 100644 example/bench/recipe.hpp rename example/brunel/{brunel_miniapp.cpp => brunel.cpp} (53%) delete mode 100644 example/brunel/io.cpp delete mode 100644 example/brunel/io.hpp delete mode 100644 example/dryrun/parameters.hpp delete mode 100644 example/gap_junctions/parameters.hpp rename example/generators/{event_gen.cpp => generators.cpp} (100%) delete mode 100644 example/ring/parameters.hpp diff --git a/example/bench/CMakeLists.txt b/example/bench/CMakeLists.txt index aa23ea36..3db3345f 100644 --- a/example/bench/CMakeLists.txt +++ b/example/bench/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(bench EXCLUDE_FROM_ALL bench.cpp recipe.cpp parameters.cpp) +add_executable(bench EXCLUDE_FROM_ALL bench.cpp) add_dependencies(examples bench) target_link_libraries(bench PRIVATE arbor arborenv arbor-sup ext-tclap ext-json) diff --git a/example/bench/bench.cpp b/example/bench/bench.cpp index af985c66..bd530d1f 100644 --- a/example/bench/bench.cpp +++ b/example/bench/bench.cpp @@ -9,6 +9,7 @@ #include <nlohmann/json.hpp> #include <arbor/profile/meter_manager.hpp> +#include <arbor/benchmark_cell.hpp> #include <arbor/context.hpp> #include <arbor/domain_decomposition.hpp> #include <arbor/load_balance.hpp> @@ -23,14 +24,123 @@ #include <sup/ioutil.hpp> #include <sup/json_meter.hpp> +#include <sup/json_params.hpp> #ifdef ARB_MPI_ENABLED #include <mpi.h> #include <arborenv/with_mpi.hpp> #endif -#include "parameters.hpp" -#include "recipe.hpp" +struct bench_params { + struct cell_params { + double spike_freq_hz = 10; // Frequency in hz that cell will generate (poisson) spikes. + double realtime_ratio = 0.1; // Integration speed relative to real time, e.g. 10 implies + // that a cell is integrated 10 times slower than real time. + }; + struct network_params { + unsigned fan_in = 5000; // Number of incoming connections on each cell. + double min_delay = 10; // Used as the delay on all connections. + }; + std::string name = "default"; // Name of the model. + unsigned num_cells = 1000; // Number of cells in model. + arb::time_type duration = 100; // Simulation duration in ms. + + cell_params cell; // Cell parameters for all cells in model. + network_params network; // Description of the network. + + // Expected simulation performance properties based on model parameters. + + // Time to finish simulation if only cell overheads are counted. + double expected_advance_time() const { + return cell.realtime_ratio * duration*1e-3 * num_cells; + } + // Total expected number of spikes generated by simulation. + unsigned expected_spikes() const { + return num_cells * duration*1e-3 * cell.spike_freq_hz; + } + // Expected number of spikes generated per min_delay/2 interval. + unsigned expected_spikes_per_interval() const { + return num_cells * network.min_delay*1e-3/2 * cell.spike_freq_hz; + } + // Expected number of post-synaptic events delivered over simulation. + unsigned expected_events() const { + return expected_spikes() * network.fan_in; + } + // Expected number of post-synaptic events delivered per min_delay/2 interval. + unsigned expected_events_per_interval() const { + return expected_spikes_per_interval() * network.fan_in; + } +}; + +bench_params read_options(int argc, char** argv); +std::ostream& operator<<(std::ostream& o, const bench_params& p); + +class bench_recipe: public arb::recipe { + bench_params params_; + +public: + bench_recipe(bench_params p): params_(std::move(p)) {} + + arb::cell_size_type num_cells() const override { + return params_.num_cells; + } + + arb::util::unique_any get_cell_description(arb::cell_gid_type gid) const override { + std::mt19937_64 rng(gid); + arb::benchmark_cell cell; + cell.realtime_ratio = params_.cell.realtime_ratio; + + // The time_sequence of the cell produces the series of time points at + // which it will spike. We use a poisson_schedule with a random sequence + // seeded with the gid. In this way, a cell's random stream depends only + // on its gid, and will hence give reproducable results when run with + // different MPI ranks and threads. + cell.time_sequence = arb::poisson_schedule(1e-3*params_.cell.spike_freq_hz, rng); + return std::move(cell); + } + + arb::cell_kind get_cell_kind(arb::cell_gid_type gid) const override { + return arb::cell_kind::benchmark; + } + + arb::cell_size_type num_targets(arb::cell_gid_type gid) const override { + // Only one target, to which all incoming connections connect. + // This could be parameterized, in which case the connections + // generated in connections_on should end on random cell-local targets. + return 1; + } + + arb::cell_size_type num_sources(arb::cell_gid_type gid) const override { + return 1; + } + + std::vector<arb::cell_connection> connections_on(arb::cell_gid_type gid) const override { + const auto n = params_.network.fan_in; + std::vector<arb::cell_connection> cons; + cons.reserve(n); + using rng_type = std::mt19937_64; + rng_type rng(gid); + + // Generate n incoming connections on this cell with random sources, where + // the source can't equal gid (i.e. no self-connections). + // We want a random distribution that will uniformly draw values from the + // union of the two ranges: [0, gid-1] AND [gid+1, num_cells-1]. + // To do this, we draw random values in the range [0, num_cells-2], then + // add 1 to values ≥ gid. + + std::uniform_int_distribution<arb::cell_gid_type> dist(0, params_.num_cells-2); + for (unsigned i=0; i<n; ++i) { + // Draw random source and adjust to avoid self-connections if neccesary. + arb::cell_gid_type src = dist(rng); + if (src>=gid) ++src; + // Note: target is {gid, 0}, i.e. the first (and only) target on the cell. + arb::cell_connection con({src, 0}, {gid, 0}, 1.f, params_.network.min_delay); + cons.push_back(con); + } + + return cons; + } +}; namespace profile = arb::profile; @@ -105,3 +215,60 @@ int main(int argc, char** argv) { std::cerr << "exception caught running benchmark miniapp:\n" << e.what() << std::endl; } } + +std::ostream& operator<<(std::ostream& o, const bench_params& p) { + o << "benchmark parameters:\n" + << " name: " << p.name << "\n" + << " num cells: " << p.num_cells << "\n" + << " duration: " << p.duration << " ms\n" + << " fan in: " << p.network.fan_in << " connections/cell\n" + << " min delay: " << p.network.min_delay << " ms\n" + << " spike freq: " << p.cell.spike_freq_hz << " Hz\n" + << " cell overhead: " << p.cell.realtime_ratio << " ms to advance 1 ms\n"; + o << "expected:\n" + << " cell advance: " << p.expected_advance_time() << " s\n" + << " spikes: " << p.expected_spikes() << "\n" + << " events: " << p.expected_events() << "\n" + << " spikes: " << p.expected_spikes_per_interval() << " per interval\n" + << " events: " << p.expected_events_per_interval()/p.num_cells << " per cell per interval"; + return o; +} + +bench_params read_options(int argc, char** argv) { + using sup::param_from_json; + + bench_params params; + if (argc<2) { + std::cout << "Using default parameters.\n"; + return params; + } + if (argc>2) { + throw std::runtime_error("More than command line one option not permitted."); + } + + std::string fname = argv[1]; + std::cout << "Loading parameters from file: " << fname << "\n"; + std::ifstream f(fname); + + if (!f.good()) { + throw std::runtime_error("Unable to open input parameter file: "+fname); + } + + nlohmann::json json; + json << f; + + param_from_json(params.name, "name", json); + param_from_json(params.num_cells, "num-cells", json); + param_from_json(params.duration, "duration", json); + param_from_json(params.network.min_delay, "min-delay", json); + param_from_json(params.network.fan_in, "fan-in", json); + param_from_json(params.cell.realtime_ratio, "realtime-ratio", json); + param_from_json(params.cell.spike_freq_hz, "spike-frequency", json); + + for (auto it=json.begin(); it!=json.end(); ++it) { + std::cout << " Warning: unused input parameter: \"" << it.key() << "\"\n"; + } + std::cout << "\n"; + + return params; +} diff --git a/example/bench/parameters.cpp b/example/bench/parameters.cpp deleted file mode 100644 index d2a42621..00000000 --- a/example/bench/parameters.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include <exception> -#include <fstream> -#include <iostream> -#include <string> - -#include <sup/json_params.hpp> - -#include "parameters.hpp" - -double bench_params::expected_advance_time() const { - return cell.realtime_ratio * duration*1e-3 * num_cells; -} -unsigned bench_params::expected_spikes() const { - return num_cells * duration*1e-3 * cell.spike_freq_hz; -} -unsigned bench_params::expected_spikes_per_interval() const { - return num_cells * network.min_delay*1e-3/2 * cell.spike_freq_hz; -} -unsigned bench_params::expected_events() const { - return expected_spikes() * network.fan_in; -} -unsigned bench_params::expected_events_per_interval() const { - return expected_spikes_per_interval() * network.fan_in; -} - -std::ostream& operator<<(std::ostream& o, const bench_params& p) { - o << "benchmark parameters:\n" - << " name: " << p.name << "\n" - << " num cells: " << p.num_cells << "\n" - << " duration: " << p.duration << " ms\n" - << " fan in: " << p.network.fan_in << " connections/cell\n" - << " min delay: " << p.network.min_delay << " ms\n" - << " spike freq: " << p.cell.spike_freq_hz << " Hz\n" - << " cell overhead: " << p.cell.realtime_ratio << " ms to advance 1 ms\n"; - o << "expected:\n" - << " cell advance: " << p.expected_advance_time() << " s\n" - << " spikes: " << p.expected_spikes() << "\n" - << " events: " << p.expected_events() << "\n" - << " spikes: " << p.expected_spikes_per_interval() << " per interval\n" - << " events: " << p.expected_events_per_interval()/p.num_cells << " per cell per interval"; - return o; -} - -bench_params read_options(int argc, char** argv) { - using sup::param_from_json; - - bench_params params; - if (argc<2) { - std::cout << "Using default parameters.\n"; - return params; - } - if (argc>2) { - throw std::runtime_error("More than command line one option not permitted."); - } - - std::string fname = argv[1]; - std::cout << "Loading parameters from file: " << fname << "\n"; - std::ifstream f(fname); - - if (!f.good()) { - throw std::runtime_error("Unable to open input parameter file: "+fname); - } - - nlohmann::json json; - json << f; - - param_from_json(params.name, "name", json); - param_from_json(params.num_cells, "num-cells", json); - param_from_json(params.duration, "duration", json); - param_from_json(params.network.min_delay, "min-delay", json); - param_from_json(params.network.fan_in, "fan-in", json); - param_from_json(params.cell.realtime_ratio, "realtime-ratio", json); - param_from_json(params.cell.spike_freq_hz, "spike-frequency", json); - - for (auto it=json.begin(); it!=json.end(); ++it) { - std::cout << " Warning: unused input parameter: \"" << it.key() << "\"\n"; - } - std::cout << "\n"; - - return params; -} diff --git a/example/bench/parameters.hpp b/example/bench/parameters.hpp deleted file mode 100644 index 9f6fdc9f..00000000 --- a/example/bench/parameters.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include <ostream> -#include <string> - -#include <arbor/common_types.hpp> - -using arb::time_type; - -struct bench_params { - struct cell_params { - double spike_freq_hz = 10; // Frequency in hz that cell will generate (poisson) spikes. - double realtime_ratio = 0.1; // Integration speed relative to real time, e.g. 10 implies - // that a cell is integrated 10 times slower than real time. - }; - struct network_params { - unsigned fan_in = 5000; // Number of incoming connections on each cell. - double min_delay = 10; // Used as the delay on all connections. - }; - std::string name = "default"; // Name of the model. - unsigned num_cells = 1000; // Number of cells in model. - time_type duration = 100; // Simulation duration in ms. - - cell_params cell; // Cell parameters for all cells in model. - network_params network; // Description of the network. - - // Expected simulation performance properties based on model parameters. - - // Time to finish simulation if only cell overheads are counted. - double expected_advance_time() const; - // Total expected number of spikes generated by simulation. - unsigned expected_spikes() const; - // Expected number of spikes generated per min_delay/2 interval. - unsigned expected_spikes_per_interval() const; - // Expected number of post-synaptic events delivered over simulation. - unsigned expected_events() const; - // Expected number of post-synaptic events delivered per min_delay/2 interval. - unsigned expected_events_per_interval() const; -}; - -bench_params read_options(int argc, char** argv); - -std::ostream& operator<<(std::ostream& o, const bench_params& p); diff --git a/example/bench/readme.md b/example/bench/readme.md index c6dbc2f9..b862132e 100644 --- a/example/bench/readme.md +++ b/example/bench/readme.md @@ -21,7 +21,7 @@ pattern are varied, without having to tweak parameters on a model that uses The model can be configured using a json configuration file: ``` -./bench.exe params.json +./bench params.json ``` An example parameter file is: diff --git a/example/bench/recipe.cpp b/example/bench/recipe.cpp deleted file mode 100644 index aa9c94b8..00000000 --- a/example/bench/recipe.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include <random> - -#include <arbor/benchmark_cell.hpp> -#include <arbor/common_types.hpp> -#include <arbor/schedule.hpp> - -#include "recipe.hpp" - -using arb::cell_gid_type; -using arb::cell_size_type; -using arb::cell_kind; - -cell_size_type bench_recipe::num_cells() const { - return params_.num_cells; -} - -arb::util::unique_any bench_recipe::get_cell_description(cell_gid_type gid) const { - std::mt19937_64 rng(gid); - arb::benchmark_cell cell; - cell.realtime_ratio = params_.cell.realtime_ratio; - - // The time_sequence of the cell produces the series of time points at - // which it will spike. We use a poisson_schedule with a random sequence - // seeded with the gid. In this way, a cell's random stream depends only - // on its gid, and will hence give reproducable results when run with - // different MPI ranks and threads. - cell.time_sequence = arb::poisson_schedule(1e-3*params_.cell.spike_freq_hz, rng); - return std::move(cell); -} - -cell_kind bench_recipe::get_cell_kind(cell_gid_type gid) const { - return cell_kind::benchmark; -} - -std::vector<arb::cell_connection> bench_recipe::connections_on(cell_gid_type gid) const { - const auto n = params_.network.fan_in; - std::vector<arb::cell_connection> cons; - cons.reserve(n); - using rng_type = std::mt19937_64; - rng_type rng(gid); - - // Generate n incoming connections on this cell with random sources, where - // the source can't equal gid (i.e. no self-connections). - // We want a random distribution that will uniformly draw values from the - // union of the two ranges: [0, gid-1] AND [gid+1, num_cells-1]. - // To do this, we draw random values in the range [0, num_cells-2], then - // add 1 to values ≥ gid. - - std::uniform_int_distribution<cell_gid_type> dist(0, params_.num_cells-2); - for (unsigned i=0; i<n; ++i) { - // Draw random source and adjust to avoid self-connections if neccesary. - cell_gid_type src = dist(rng); - if (src>=gid) ++src; - // Note: target is {gid, 0}, i.e. the first (and only) target on the cell. - arb::cell_connection con({src, 0}, {gid, 0}, 1.f, params_.network.min_delay); - cons.push_back(con); - } - - return cons; -} - -cell_size_type bench_recipe::num_targets(cell_gid_type gid) const { - // Only one target, to which all incoming connections connect. - // This could be parameterized, in which case the connections - // generated in connections_on should end on random cell-local targets. - return 1; -} - -// one spike source per cell -cell_size_type bench_recipe::num_sources(cell_gid_type gid) const { - return 1; -} diff --git a/example/bench/recipe.hpp b/example/bench/recipe.hpp deleted file mode 100644 index e95f6077..00000000 --- a/example/bench/recipe.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include <arbor/common_types.hpp> -#include <arbor/recipe.hpp> -#include <arbor/util/unique_any.hpp> - -#include "parameters.hpp" - -class bench_recipe: public arb::recipe { -private: - bench_params params_; - -public: - bench_recipe(bench_params p): params_(std::move(p)) {} - arb::cell_size_type num_cells() const override; - arb::util::unique_any get_cell_description(arb::cell_gid_type gid) const override; - arb::cell_kind get_cell_kind(arb::cell_gid_type gid) const override; - arb::cell_size_type num_targets(arb::cell_gid_type gid) const override; - arb::cell_size_type num_sources(arb::cell_gid_type gid) const override; - std::vector<arb::cell_connection> connections_on(arb::cell_gid_type) const override; -}; - diff --git a/example/brunel/CMakeLists.txt b/example/brunel/CMakeLists.txt index 99b26743..79b68394 100644 --- a/example/brunel/CMakeLists.txt +++ b/example/brunel/CMakeLists.txt @@ -1,6 +1,4 @@ -add_executable(brunel-miniapp EXCLUDE_FROM_ALL - brunel_miniapp.cpp - io.cpp) -add_dependencies(examples brunel-miniapp) +add_executable(brunel EXCLUDE_FROM_ALL brunel.cpp) +add_dependencies(examples brunel) -target_link_libraries(brunel-miniapp PRIVATE arbor arborenv arbor-sup ext-tclap) +target_link_libraries(brunel PRIVATE arbor arborenv arbor-sup ext-tclap) diff --git a/example/brunel/brunel_miniapp.cpp b/example/brunel/brunel.cpp similarity index 53% rename from example/brunel/brunel_miniapp.cpp rename to example/brunel/brunel.cpp index 131f2730..22a49674 100644 --- a/example/brunel/brunel_miniapp.cpp +++ b/example/brunel/brunel.cpp @@ -7,6 +7,8 @@ #include <set> #include <vector> +#include <tclap/CmdLine.h> + #include <arbor/context.hpp> #include <arbor/common_types.hpp> #include <arbor/domain_decomposition.hpp> @@ -17,6 +19,7 @@ #include <arbor/profile/profiler.hpp> #include <arbor/recipe.hpp> #include <arbor/simulation.hpp> +#include <arbor/util/optional.hpp> #include <arbor/version.hpp> #include <arborenv/concurrency.hpp> @@ -32,26 +35,46 @@ #include <arborenv/with_mpi.hpp> #endif -#include "io.hpp" - using namespace arb; +// Holds the options for a simulation run. +// Default constructor gives default options. +struct cl_options { + // Cell parameters: + uint32_t nexc = 400; + uint32_t ninh = 100; + uint32_t next = 40; + double syn_per_cell_prop = 0.05; + float weight = 1.2; + float delay = 0.1; + float rel_inh_strength = 1; + double poiss_lambda = 1; + + // Simulation running parameters: + double tfinal = 100.; + double dt = 1; + uint32_t group_size = 10; + uint32_t seed = 42; + + // Parameters for spike output. + bool spike_file_output = false; + + // Turn on/off profiling output for all ranks. + bool profile_only_zero = false; + + // Be more verbose with informational messages. + bool verbose = false; +}; + +std::ostream& operator<<(std::ostream& o, const cl_options& opt); + +cl_options read_options(int argc, char** argv); + void banner(const context& ctx); // Samples m unique values in interval [start, end) - gid. // We exclude gid because we don't want self-loops. -std::vector<cell_gid_type> sample_subset(cell_gid_type gid, cell_gid_type start, cell_gid_type end, unsigned m) { - std::set<cell_gid_type> s; - std::mt19937 gen(gid + 42); - std::uniform_int_distribution<cell_gid_type> dis(start, end - 1); - while (s.size() < m) { - auto val = dis(gen); - if (val != gid) { - s.insert(val); - } - } - return {s.begin(), s.end()}; -} +std::vector<cell_gid_type> sample_subset(cell_gid_type gid, cell_gid_type start, cell_gid_type end, unsigned m); /* A Brunel network consists of nexc excitatory LIF neurons and ninh inhibitory LIF neurons. @@ -214,7 +237,7 @@ int main(int argc, char** argv) { meters.start(context); // read parameters - io::cl_options options = io::read_options(argc, argv); + cl_options options = read_options(argc, argv); std::fstream spike_out; if (options.spike_file_output && root) { @@ -296,16 +319,12 @@ int main(int argc, char** argv) { fid << std::setw(1) << sup::to_json(report) << "\n"; } } - catch (io::usage_error& e) { - // only print usage/startup errors on master + catch (std::exception& e) { + // only print errors on master std::cerr << sup::mask_stream(root); std::cerr << e.what() << "\n"; return 1; } - catch (std::exception& e) { - std::cerr << e.what() << "\n"; - return 2; - } return 0; } @@ -318,3 +337,207 @@ void banner(const context& ctx) { std::cout << " - gpus : " << (arb::has_gpu(ctx)? "yes": "no") << "\n"; std::cout << "==========================================\n"; } + +std::vector<cell_gid_type> sample_subset(cell_gid_type gid, cell_gid_type start, cell_gid_type end, unsigned m) { + std::set<cell_gid_type> s; + std::mt19937 gen(gid + 42); + std::uniform_int_distribution<cell_gid_type> dis(start, end - 1); + while (s.size() < m) { + auto val = dis(gen); + if (val != gid) { + s.insert(val); + } + } + return {s.begin(), s.end()}; +} + +// Let TCLAP understand value arguments that are of an optional type. +namespace TCLAP { + template <typename V> + struct ArgTraits<arb::util::optional<V>> { + using ValueCategory = ValueLike; + }; +} // namespace TCLAP + +namespace arb { + namespace util { + // Using static here because we do not want external linkage for this operator. + template <typename V> + static std::istream& operator>>(std::istream& I, optional<V>& v) { + V u; + if (I >> u) { + v = u; + } + return I; + } + } +} + +// Override annoying parameters listed back-to-front behaviour. +// +// TCLAP argument creation _prepends_ its arguments to the internal +// list (_argList), where standard options --help etc. are already +// pre-inserted. +// +// reorder_arguments() reverses the arguments to restore ordering, +// and moves the standard options to the end. +class CustomCmdLine: public TCLAP::CmdLine { +public: + CustomCmdLine(const std::string &message, const std::string &version = "none"): + TCLAP::CmdLine(message, ' ', version, true) + {} + + void reorder_arguments() { + _argList.reverse(); + for (auto opt: {"help", "version", "ignore_rest"}) { + auto i = std::find_if( + _argList.begin(), _argList.end(), + [&opt](TCLAP::Arg* a) { return a->getName()==opt; }); + + if (i!=_argList.end()) { + auto a = *i; + _argList.erase(i); + _argList.push_back(a); + } + } + } +}; + +// Update an option value from command line argument if set. +template < + typename T, + typename Arg, + typename = std::enable_if_t<std::is_base_of<TCLAP::Arg, Arg>::value> +> +static void update_option(T& opt, Arg& arg) { + if (arg.isSet()) { + opt = arg.getValue(); + } +} + +// Read options from (optional) json file and command line arguments. +cl_options read_options(int argc, char** argv) { + cl_options options; + + // Parse command line arguments. + try { + cl_options defopts; + + CustomCmdLine cmd("nest brunel miniapp harness", "0.1"); + + TCLAP::ValueArg<uint32_t> nexc_arg + ("n", "n-excitatory", "total number of cells in the excitatory population", + false, defopts.nexc, "integer", cmd); + + TCLAP::ValueArg<uint32_t> ninh_arg + ("m", "n-inhibitory", "total number of cells in the inhibitory population", + false, defopts.ninh, "integer", cmd); + + TCLAP::ValueArg<uint32_t> next_arg + ("e", "n-external", "total number of incoming Poisson (external) connections per cell.", + false, defopts.ninh, "integer", cmd); + + TCLAP::ValueArg<double> syn_prop_arg + ("p", "in-degree-prop", "the proportion of connections both the excitatory and inhibitory populations that each neuron receives", + false, defopts.syn_per_cell_prop, "double", cmd); + + TCLAP::ValueArg<float> weight_arg + ("w", "weight", "the weight of all excitatory connections", + false, defopts.weight, "float", cmd); + + TCLAP::ValueArg<float> delay_arg + ("d", "delay", "the delay of all connections", + false, defopts.delay, "float", cmd); + + TCLAP::ValueArg<float> rel_inh_strength_arg + ("g", "rel-inh-w", "relative strength of inhibitory synapses with respect to the excitatory ones", + false, defopts.rel_inh_strength, "float", cmd); + + TCLAP::ValueArg<double> poiss_lambda_arg + ("l", "lambda", "Expected number of spikes from a single poisson cell per ms", + false, defopts.poiss_lambda, "double", cmd); + + TCLAP::ValueArg<double> tfinal_arg + ("t", "tfinal", "length of the simulation period [ms]", + false, defopts.tfinal, "time", cmd); + + TCLAP::ValueArg<double> dt_arg + ("s", "delta-t", "simulation time step [ms] (this parameter is ignored)", + false, defopts.dt, "time", cmd); + + TCLAP::ValueArg<uint32_t> group_size_arg + ("G", "group-size", "number of cells per cell group", + false, defopts.group_size, "integer", cmd); + + TCLAP::ValueArg<uint32_t> seed_arg + ("S", "seed", "seed for poisson spike generators", + false, defopts.seed, "integer", cmd); + + TCLAP::SwitchArg spike_output_arg + ("f","spike-file-output","save spikes to file", cmd, false); + + TCLAP::SwitchArg profile_only_zero_arg + ("z", "profile-only-zero", "Only output profile information for rank 0", + cmd, false); + + TCLAP::SwitchArg verbose_arg + ("v", "verbose", "Present more verbose information to stdout", cmd, false); + + cmd.reorder_arguments(); + cmd.parse(argc, argv); + + // Handle verbosity separately from other options: it is not considered part + // of the saved option state. + options.verbose = verbose_arg.getValue(); + update_option(options.nexc, nexc_arg); + update_option(options.ninh, ninh_arg); + update_option(options.next, next_arg); + update_option(options.syn_per_cell_prop, syn_prop_arg); + update_option(options.weight, weight_arg); + update_option(options.delay, delay_arg); + update_option(options.rel_inh_strength, rel_inh_strength_arg); + update_option(options.poiss_lambda, poiss_lambda_arg); + update_option(options.tfinal, tfinal_arg); + update_option(options.dt, dt_arg); + update_option(options.group_size, group_size_arg); + update_option(options.seed, seed_arg); + update_option(options.spike_file_output, spike_output_arg); + update_option(options.profile_only_zero, profile_only_zero_arg); + + if (options.group_size < 1) { + throw std::runtime_error("minimum of one cell per group"); + } + + if (options.rel_inh_strength <= 0 || options.rel_inh_strength > 1) { + throw std::runtime_error("relative strength of inhibitory connections must be in the interval (0, 1]."); + } + } + catch (TCLAP::ArgException& e) { + throw std::runtime_error("error parsing command line argument "+e.argId()+": "+e.error()); + } + + // If verbose output requested, emit option summary. + if (options.verbose) { + std::cout << options << "\n"; + } + + return options; +} + +std::ostream& operator<<(std::ostream& o, const cl_options& options) { + o << "simulation options:\n"; + o << " excitatory cells : " << options.nexc << "\n"; + o << " inhibitory cells : " << options.ninh << "\n"; + o << " Poisson connections per cell : " << options.next << "\n"; + o << " proportion of synapses/cell from each population : " << options.syn_per_cell_prop << "\n"; + o << " weight of excitatory synapses : " << options.weight << "\n"; + o << " relative strength of inhibitory synapses : " << options.rel_inh_strength << "\n"; + o << " delay of all synapses : " << options.delay << "\n"; + o << " expected number of spikes from a single poisson cell per ms: " << options.poiss_lambda << "\n"; + o << "\n"; + o << " simulation time : " << options.tfinal << "\n"; + o << " dt : " << options.dt << "\n"; + o << " group size : " << options.group_size << "\n"; + o << " seed : " << options.seed << "\n"; + return o; +} diff --git a/example/brunel/io.cpp b/example/brunel/io.cpp deleted file mode 100644 index 72b6ca81..00000000 --- a/example/brunel/io.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#include <algorithm> -#include <exception> -#include <fstream> -#include <iostream> -#include <memory> -#include <sstream> -#include <string> -#include <type_traits> - -#include <tclap/CmdLine.h> - -#include <arbor/util/optional.hpp> - -#include "io.hpp" - -// Let TCLAP understand value arguments that are of an optional type. -namespace TCLAP { - template <typename V> - struct ArgTraits<arb::util::optional<V>> { - using ValueCategory = ValueLike; - }; -} // namespace TCLAP - -namespace arb { - namespace util { - // Using static here because we do not want external linkage for this operator. - template <typename V> - static std::istream& operator>>(std::istream& I, optional<V>& v) { - V u; - if (I >> u) { - v = u; - } - return I; - } - } -} - -namespace io { - // Override annoying parameters listed back-to-front behaviour. - // - // TCLAP argument creation _prepends_ its arguments to the internal - // list (_argList), where standard options --help etc. are already - // pre-inserted. - // - // reorder_arguments() reverses the arguments to restore ordering, - // and moves the standard options to the end. - class CustomCmdLine: public TCLAP::CmdLine { - public: - CustomCmdLine(const std::string &message, const std::string &version = "none"): - TCLAP::CmdLine(message, ' ', version, true) - {} - - void reorder_arguments() { - _argList.reverse(); - for (auto opt: {"help", "version", "ignore_rest"}) { - auto i = std::find_if( - _argList.begin(), _argList.end(), - [&opt](TCLAP::Arg* a) { return a->getName()==opt; }); - - if (i!=_argList.end()) { - auto a = *i; - _argList.erase(i); - _argList.push_back(a); - } - } - } - }; - - // Update an option value from command line argument if set. - template < - typename T, - typename Arg, - typename = std::enable_if_t<std::is_base_of<TCLAP::Arg, Arg>::value> - > - static void update_option(T& opt, Arg& arg) { - if (arg.isSet()) { - opt = arg.getValue(); - } - } - - // Read options from (optional) json file and command line arguments. - cl_options read_options(int argc, char** argv) { - cl_options options; - - // Parse command line arguments. - try { - cl_options defopts; - - CustomCmdLine cmd("nest brunel miniapp harness", "0.1"); - - TCLAP::ValueArg<uint32_t> nexc_arg - ("n", "n-excitatory", "total number of cells in the excitatory population", - false, defopts.nexc, "integer", cmd); - - TCLAP::ValueArg<uint32_t> ninh_arg - ("m", "n-inhibitory", "total number of cells in the inhibitory population", - false, defopts.ninh, "integer", cmd); - - TCLAP::ValueArg<uint32_t> next_arg - ("e", "n-external", "total number of incoming Poisson (external) connections per cell.", - false, defopts.ninh, "integer", cmd); - - TCLAP::ValueArg<double> syn_prop_arg - ("p", "in-degree-prop", "the proportion of connections both the excitatory and inhibitory populations that each neuron receives", - false, defopts.syn_per_cell_prop, "double", cmd); - - TCLAP::ValueArg<float> weight_arg - ("w", "weight", "the weight of all excitatory connections", - false, defopts.weight, "float", cmd); - - TCLAP::ValueArg<float> delay_arg - ("d", "delay", "the delay of all connections", - false, defopts.delay, "float", cmd); - - TCLAP::ValueArg<float> rel_inh_strength_arg - ("g", "rel-inh-w", "relative strength of inhibitory synapses with respect to the excitatory ones", - false, defopts.rel_inh_strength, "float", cmd); - - TCLAP::ValueArg<double> poiss_lambda_arg - ("l", "lambda", "Expected number of spikes from a single poisson cell per ms", - false, defopts.poiss_lambda, "double", cmd); - - TCLAP::ValueArg<double> tfinal_arg - ("t", "tfinal", "length of the simulation period [ms]", - false, defopts.tfinal, "time", cmd); - - TCLAP::ValueArg<double> dt_arg - ("s", "delta-t", "simulation time step [ms] (this parameter is ignored)", - false, defopts.dt, "time", cmd); - - TCLAP::ValueArg<uint32_t> group_size_arg - ("G", "group-size", "number of cells per cell group", - false, defopts.group_size, "integer", cmd); - - TCLAP::ValueArg<uint32_t> seed_arg - ("S", "seed", "seed for poisson spike generators", - false, defopts.seed, "integer", cmd); - - TCLAP::SwitchArg spike_output_arg - ("f","spike-file-output","save spikes to file", cmd, false); - - TCLAP::SwitchArg profile_only_zero_arg - ("z", "profile-only-zero", "Only output profile information for rank 0", - cmd, false); - - TCLAP::SwitchArg verbose_arg - ("v", "verbose", "Present more verbose information to stdout", cmd, false); - - cmd.reorder_arguments(); - cmd.parse(argc, argv); - - // Handle verbosity separately from other options: it is not considered part - // of the saved option state. - options.verbose = verbose_arg.getValue(); - update_option(options.nexc, nexc_arg); - update_option(options.ninh, ninh_arg); - update_option(options.next, next_arg); - update_option(options.syn_per_cell_prop, syn_prop_arg); - update_option(options.weight, weight_arg); - update_option(options.delay, delay_arg); - update_option(options.rel_inh_strength, rel_inh_strength_arg); - update_option(options.poiss_lambda, poiss_lambda_arg); - update_option(options.tfinal, tfinal_arg); - update_option(options.dt, dt_arg); - update_option(options.group_size, group_size_arg); - update_option(options.seed, seed_arg); - update_option(options.spike_file_output, spike_output_arg); - update_option(options.profile_only_zero, profile_only_zero_arg); - - if (options.group_size < 1) { - throw usage_error("minimum of one cell per group"); - } - - if (options.rel_inh_strength <= 0 || options.rel_inh_strength > 1) { - throw usage_error("relative strength of inhibitory connections must be in the interval (0, 1]."); - } - } - catch (TCLAP::ArgException& e) { - throw usage_error("error parsing command line argument "+e.argId()+": "+e.error()); - } - - // If verbose output requested, emit option summary. - if (options.verbose) { - std::cout << options << "\n"; - } - - return options; - } - - std::ostream& operator<<(std::ostream& o, const cl_options& options) { - o << "simulation options:\n"; - o << " excitatory cells : " << options.nexc << "\n"; - o << " inhibitory cells : " << options.ninh << "\n"; - o << " Poisson connections per cell : " << options.next << "\n"; - o << " proportion of synapses/cell from each population : " << options.syn_per_cell_prop << "\n"; - o << " weight of excitatory synapses : " << options.weight << "\n"; - o << " relative strength of inhibitory synapses : " << options.rel_inh_strength << "\n"; - o << " delay of all synapses : " << options.delay << "\n"; - o << " expected number of spikes from a single poisson cell per ms: " << options.poiss_lambda << "\n"; - o << "\n"; - o << " simulation time : " << options.tfinal << "\n"; - o << " dt : " << options.dt << "\n"; - o << " group size : " << options.group_size << "\n"; - o << " seed : " << options.seed << "\n"; - return o; - } -} // namespace io diff --git a/example/brunel/io.hpp b/example/brunel/io.hpp deleted file mode 100644 index 28c76bdb..00000000 --- a/example/brunel/io.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include <stdexcept> -#include <string> -#include <utility> -#include <vector> - -#include <arbor/common_types.hpp> -#include <arbor/util/optional.hpp> - -namespace io { - // Holds the options for a simulation run. - // Default constructor gives default options. - struct cl_options { - // Cell parameters: - uint32_t nexc = 400; - uint32_t ninh = 100; - uint32_t next = 40; - double syn_per_cell_prop = 0.05; - float weight = 1.2; - float delay = 0.1; - float rel_inh_strength = 1; - double poiss_lambda = 1; - - // Simulation running parameters: - double tfinal = 100.; - double dt = 1; - uint32_t group_size = 10; - uint32_t seed = 42; - - // Parameters for spike output. - bool spike_file_output = false; - - // Turn on/off profiling output for all ranks. - bool profile_only_zero = false; - - // Be more verbose with informational messages. - bool verbose = false; - }; - - class usage_error: public std::runtime_error { - public: - template <typename S> - usage_error(S&& whatmsg): std::runtime_error(std::forward<S>(whatmsg)) {} - }; - - class model_description_error: public std::runtime_error { - public: - template <typename S> - model_description_error(S&& whatmsg): std::runtime_error(std::forward<S>(whatmsg)) {} - }; - - std::ostream& operator<<(std::ostream& o, const cl_options& opt); - - cl_options read_options(int argc, char** argv); -} // namespace io diff --git a/example/brunel/readme.md b/example/brunel/readme.md index 46b7fc52..8168b6fe 100644 --- a/example/brunel/readme.md +++ b/example/brunel/readme.md @@ -31,5 +31,5 @@ The parameters that can be passed as command-line arguments are the following: For example, we could run the miniapp as follows: ``` -./example/brunel_miniapp.exe -n 400 -m 100 -e 20 -p 0.1 -w 1.2 -d 1 -g 0.5 -l 5 -t 100 -s 1 -G 50 -S 123 -f +./brunel -n 400 -m 100 -e 20 -p 0.1 -w 1.2 -d 1 -g 0.5 -l 5 -t 100 -s 1 -G 50 -S 123 -f ``` diff --git a/example/dryrun/dryrun.cpp b/example/dryrun/dryrun.cpp index b9e5619e..42b4ca7e 100644 --- a/example/dryrun/dryrun.cpp +++ b/example/dryrun/dryrun.cpp @@ -24,14 +24,38 @@ #include <sup/ioutil.hpp> #include <sup/json_meter.hpp> - -#include "parameters.hpp" +#include <sup/json_params.hpp> #ifdef ARB_MPI_ENABLED #include <mpi.h> #include <arborenv/with_mpi.hpp> #endif +// Parameters used to generate the random cell morphologies. +struct cell_parameters { + // Maximum number of levels in the cell (not including the soma) + unsigned max_depth = 5; + + // The following parameters are described as ranges. + // The first value is at the soma, and the last value is used on the last level. + // Values at levels in between are found by linear interpolation. + std::array<double,2> branch_probs = {1.0, 0.5}; // Probability of a branch occuring. + std::array<unsigned,2> compartments = {20, 2}; // Compartment count on a branch. + std::array<double,2> lengths = {200, 20}; // Length of branch in μm. +}; + +struct run_params { + std::string name = "default"; + bool dry_run = false; + unsigned num_cells_per_rank = 10; + unsigned num_ranks = 1; + double min_delay = 10; + double duration = 100; + cell_parameters cell; +}; + +run_params read_options(int argc, char** argv); + using arb::cell_gid_type; using arb::cell_lid_type; using arb::cell_size_type; @@ -360,3 +384,46 @@ arb::cable_cell branch_cell(arb::cell_gid_type gid, const cell_parameters& param return cell; } +run_params read_options(int argc, char** argv) { + using sup::param_from_json; + + run_params params; + if (argc<2) { + std::cout << "Using default parameters.\n"; + return params; + } + if (argc>2) { + throw std::runtime_error("More than command line one option not permitted."); + } + + std::string fname = argv[1]; + std::cout << "Loading parameters from file: " << fname << "\n"; + std::ifstream f(fname); + + if (!f.good()) { + throw std::runtime_error("Unable to open input parameter file: "+fname); + } + + nlohmann::json json; + json << f; + + param_from_json(params.name, "name", json); + param_from_json(params.dry_run, "dry-run", json); + param_from_json(params.num_cells_per_rank, "num-cells-per-rank", json); + param_from_json(params.num_ranks, "num-ranks", json); + param_from_json(params.duration, "duration", json); + param_from_json(params.min_delay, "min-delay", json); + param_from_json(params.cell.max_depth, "depth", json); + param_from_json(params.cell.branch_probs, "branch-probs", json); + param_from_json(params.cell.compartments, "compartments", json); + param_from_json(params.cell.lengths, "lengths", json); + + if (!json.empty()) { + for (auto it=json.begin(); it!=json.end(); ++it) { + std::cout << " Warning: unused input parameter: \"" << it.key() << "\"\n"; + } + std::cout << "\n"; + } + + return params; +} diff --git a/example/dryrun/parameters.hpp b/example/dryrun/parameters.hpp deleted file mode 100644 index e355fcf8..00000000 --- a/example/dryrun/parameters.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#include <iostream> - -#include <array> -#include <cmath> -#include <fstream> -#include <random> - -#include <arbor/cable_cell.hpp> - -#include <sup/json_params.hpp> - -// Parameters used to generate the random cell morphologies. -struct cell_parameters { - cell_parameters() = default; - - // Maximum number of levels in the cell (not including the soma) - unsigned max_depth = 5; - - // The following parameters are described as ranges. - // The first value is at the soma, and the last value is used on the last level. - // Values at levels in between are found by linear interpolation. - std::array<double,2> branch_probs = {1.0, 0.5}; // Probability of a branch occuring. - std::array<unsigned,2> compartments = {20, 2}; // Compartment count on a branch. - std::array<double,2> lengths = {200, 20}; // Length of branch in μm. -}; - -struct run_params { - run_params() = default; - - std::string name = "default"; - bool dry_run = false; - unsigned num_cells_per_rank = 10; - unsigned num_ranks = 1; - double min_delay = 10; - double duration = 100; - cell_parameters cell; -}; - -run_params read_options(int argc, char** argv) { - using sup::param_from_json; - - run_params params; - if (argc<2) { - std::cout << "Using default parameters.\n"; - return params; - } - if (argc>2) { - throw std::runtime_error("More than command line one option not permitted."); - } - - std::string fname = argv[1]; - std::cout << "Loading parameters from file: " << fname << "\n"; - std::ifstream f(fname); - - if (!f.good()) { - throw std::runtime_error("Unable to open input parameter file: "+fname); - } - - nlohmann::json json; - json << f; - - param_from_json(params.name, "name", json); - param_from_json(params.dry_run, "dry-run", json); - param_from_json(params.num_cells_per_rank, "num-cells-per-rank", json); - param_from_json(params.num_ranks, "num-ranks", json); - param_from_json(params.duration, "duration", json); - param_from_json(params.min_delay, "min-delay", json); - param_from_json(params.cell.max_depth, "depth", json); - param_from_json(params.cell.branch_probs, "branch-probs", json); - param_from_json(params.cell.compartments, "compartments", json); - param_from_json(params.cell.lengths, "lengths", json); - - if (!json.empty()) { - for (auto it=json.begin(); it!=json.end(); ++it) { - std::cout << " Warning: unused input parameter: \"" << it.key() << "\"\n"; - } - std::cout << "\n"; - } - - return params; -} diff --git a/example/gap_junctions/CMakeLists.txt b/example/gap_junctions/CMakeLists.txt index 60a68d61..abd78ebe 100644 --- a/example/gap_junctions/CMakeLists.txt +++ b/example/gap_junctions/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(gap_junctions EXCLUDE_FROM_ALL gap_junctions.cpp parameters.hpp) +add_executable(gap_junctions EXCLUDE_FROM_ALL gap_junctions.cpp) add_dependencies(examples gap_junctions) target_link_libraries(gap_junctions PRIVATE arbor arborenv arbor-sup ext-json) diff --git a/example/gap_junctions/gap_junctions.cpp b/example/gap_junctions/gap_junctions.cpp index 4a633a77..f3e1e26e 100644 --- a/example/gap_junctions/gap_junctions.cpp +++ b/example/gap_junctions/gap_junctions.cpp @@ -10,6 +10,7 @@ #include <nlohmann/json.hpp> #include <arbor/assert_macro.hpp> +#include <arbor/cable_cell.hpp> #include <arbor/common_types.hpp> #include <arbor/context.hpp> #include <arbor/load_balance.hpp> @@ -26,14 +27,26 @@ #include <sup/ioutil.hpp> #include <sup/json_meter.hpp> - -#include "parameters.hpp" +#include <sup/json_params.hpp> #ifdef ARB_MPI_ENABLED #include <mpi.h> #include <arborenv/with_mpi.hpp> #endif +struct gap_params { + std::string name = "default"; + unsigned n_cables = 3; + unsigned n_cells_per_cable = 5; + double stim_duration = 30; + double event_min_delay = 10; + double event_weight = 0.05; + double sim_duration = 100; + bool print_all = true; +}; + +gap_params read_options(int argc, char** argv); + using arb::cell_gid_type; using arb::cell_lid_type; using arb::cell_size_type; @@ -371,3 +384,44 @@ arb::cable_cell gj_cell(cell_gid_type gid, unsigned ncell, double stim_duration) return cell; } +gap_params read_options(int argc, char** argv) { + using sup::param_from_json; + + gap_params params; + if (argc<2) { + std::cout << "Using default parameters.\n"; + return params; + } + if (argc>2) { + throw std::runtime_error("More than command line one option not permitted."); + } + + std::string fname = argv[1]; + std::cout << "Loading parameters from file: " << fname << "\n"; + std::ifstream f(fname); + + if (!f.good()) { + throw std::runtime_error("Unable to open input parameter file: "+fname); + } + + nlohmann::json json; + json << f; + + param_from_json(params.name, "name", json); + param_from_json(params.n_cables, "n-cables", json); + param_from_json(params.n_cells_per_cable, "n-cells-per-cable", json); + param_from_json(params.stim_duration, "stim-duration", json); + param_from_json(params.event_min_delay, "event-min-delay", json); + param_from_json(params.event_weight, "event-weight", json); + param_from_json(params.sim_duration, "sim-duration", json); + param_from_json(params.print_all, "print-all", json); + + if (!json.empty()) { + for (auto it=json.begin(); it!=json.end(); ++it) { + std::cout << " Warning: unused input parameter: \"" << it.key() << "\"\n"; + } + std::cout << "\n"; + } + + return params; +} diff --git a/example/gap_junctions/parameters.hpp b/example/gap_junctions/parameters.hpp deleted file mode 100644 index f68ddfd2..00000000 --- a/example/gap_junctions/parameters.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#include <iostream> - -#include <array> -#include <cmath> -#include <fstream> -#include <random> - -#include <arbor/cable_cell.hpp> - -#include <sup/json_params.hpp> - -struct gap_params { - gap_params() = default; - - std::string name = "default"; - unsigned n_cables = 3; - unsigned n_cells_per_cable = 5; - double stim_duration = 30; - double event_min_delay = 10; - double event_weight = 0.05; - double sim_duration = 100; - bool print_all = true; -}; - -gap_params read_options(int argc, char** argv) { - using sup::param_from_json; - - gap_params params; - if (argc<2) { - std::cout << "Using default parameters.\n"; - return params; - } - if (argc>2) { - throw std::runtime_error("More than command line one option not permitted."); - } - - std::string fname = argv[1]; - std::cout << "Loading parameters from file: " << fname << "\n"; - std::ifstream f(fname); - - if (!f.good()) { - throw std::runtime_error("Unable to open input parameter file: "+fname); - } - - nlohmann::json json; - json << f; - - param_from_json(params.name, "name", json); - param_from_json(params.n_cables, "n-cables", json); - param_from_json(params.n_cells_per_cable, "n-cells-per-cable", json); - param_from_json(params.stim_duration, "stim-duration", json); - param_from_json(params.event_min_delay, "event-min-delay", json); - param_from_json(params.event_weight, "event-weight", json); - param_from_json(params.sim_duration, "sim-duration", json); - param_from_json(params.print_all, "print-all", json); - - if (!json.empty()) { - for (auto it=json.begin(); it!=json.end(); ++it) { - std::cout << " Warning: unused input parameter: \"" << it.key() << "\"\n"; - } - std::cout << "\n"; - } - - return params; -} diff --git a/example/generators/CMakeLists.txt b/example/generators/CMakeLists.txt index 5b917bad..7bfaca9f 100644 --- a/example/generators/CMakeLists.txt +++ b/example/generators/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(event-gen EXCLUDE_FROM_ALL event_gen.cpp) -add_dependencies(examples event-gen) +add_executable(generators EXCLUDE_FROM_ALL generators.cpp) +add_dependencies(examples generators) -target_link_libraries(event-gen PRIVATE arbor arbor-sup ext-json) +target_link_libraries(generators PRIVATE arbor arbor-sup ext-json) diff --git a/example/generators/event_gen.cpp b/example/generators/generators.cpp similarity index 100% rename from example/generators/event_gen.cpp rename to example/generators/generators.cpp diff --git a/example/ring/parameters.hpp b/example/ring/parameters.hpp deleted file mode 100644 index 6343cb3c..00000000 --- a/example/ring/parameters.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#include <iostream> - -#include <array> -#include <cmath> -#include <fstream> -#include <random> - -#include <arbor/cable_cell.hpp> - -#include <sup/json_params.hpp> - -// Parameters used to generate the random cell morphologies. -struct cell_parameters { - cell_parameters() = default; - - // Maximum number of levels in the cell (not including the soma) - unsigned max_depth = 5; - - // The following parameters are described as ranges. - // The first value is at the soma, and the last value is used on the last level. - // Values at levels in between are found by linear interpolation. - std::array<double,2> branch_probs = {1.0, 0.5}; // Probability of a branch occuring. - std::array<unsigned,2> compartments = {20, 2}; // Compartment count on a branch. - std::array<double,2> lengths = {200, 20}; // Length of branch in μm. - - // The number of synapses per cell. - unsigned synapses = 1; -}; - -struct ring_params { - ring_params() = default; - - std::string name = "default"; - unsigned num_cells = 10; - double min_delay = 10; - double duration = 100; - cell_parameters cell; -}; - -ring_params read_options(int argc, char** argv) { - using sup::param_from_json; - - ring_params params; - if (argc<2) { - std::cout << "Using default parameters.\n"; - return params; - } - if (argc>2) { - throw std::runtime_error("More than command line one option not permitted."); - } - - std::string fname = argv[1]; - std::cout << "Loading parameters from file: " << fname << "\n"; - std::ifstream f(fname); - - if (!f.good()) { - throw std::runtime_error("Unable to open input parameter file: "+fname); - } - - nlohmann::json json; - json << f; - - param_from_json(params.name, "name", json); - param_from_json(params.num_cells, "num-cells", json); - param_from_json(params.duration, "duration", json); - param_from_json(params.min_delay, "min-delay", json); - param_from_json(params.cell.max_depth, "depth", json); - param_from_json(params.cell.branch_probs, "branch-probs", json); - param_from_json(params.cell.compartments, "compartments", json); - param_from_json(params.cell.lengths, "lengths", json); - param_from_json(params.cell.synapses, "synapses", json); - - if (!json.empty()) { - for (auto it=json.begin(); it!=json.end(); ++it) { - std::cout << " Warning: unused input parameter: \"" << it.key() << "\"\n"; - } - std::cout << "\n"; - } - - return params; -} diff --git a/example/ring/ring.cpp b/example/ring/ring.cpp index 55c4cea2..6f426032 100644 --- a/example/ring/ring.cpp +++ b/example/ring/ring.cpp @@ -11,6 +11,7 @@ #include <arbor/assert_macro.hpp> #include <arbor/common_types.hpp> +#include <arbor/cable_cell.hpp> #include <arbor/context.hpp> #include <arbor/load_balance.hpp> #include <arbor/cable_cell.hpp> @@ -26,14 +27,42 @@ #include <sup/ioutil.hpp> #include <sup/json_meter.hpp> - -#include "parameters.hpp" +#include <sup/json_params.hpp> #ifdef ARB_MPI_ENABLED #include <mpi.h> #include <arborenv/with_mpi.hpp> #endif +// Parameters used to generate the random cell morphologies. +struct cell_parameters { + cell_parameters() = default; + + // Maximum number of levels in the cell (not including the soma) + unsigned max_depth = 5; + + // The following parameters are described as ranges. + // The first value is at the soma, and the last value is used on the last level. + // Values at levels in between are found by linear interpolation. + std::array<double,2> branch_probs = {1.0, 0.5}; // Probability of a branch occuring. + std::array<unsigned,2> compartments = {20, 2}; // Compartment count on a branch. + std::array<double,2> lengths = {200, 20}; // Length of branch in μm. + + // The number of synapses per cell. + unsigned synapses = 1; +}; + +struct ring_params { + ring_params() = default; + + std::string name = "default"; + unsigned num_cells = 10; + double min_delay = 10; + double duration = 100; + cell_parameters cell; +}; + +ring_params read_options(int argc, char** argv); using arb::cell_gid_type; using arb::cell_lid_type; using arb::cell_size_type; @@ -364,3 +393,46 @@ arb::cable_cell branch_cell(arb::cell_gid_type gid, const cell_parameters& param return cell; } +ring_params read_options(int argc, char** argv) { + using sup::param_from_json; + + ring_params params; + if (argc<2) { + std::cout << "Using default parameters.\n"; + return params; + } + if (argc>2) { + throw std::runtime_error("More than command line one option not permitted."); + } + + std::string fname = argv[1]; + std::cout << "Loading parameters from file: " << fname << "\n"; + std::ifstream f(fname); + + if (!f.good()) { + throw std::runtime_error("Unable to open input parameter file: "+fname); + } + + nlohmann::json json; + json << f; + + param_from_json(params.name, "name", json); + param_from_json(params.num_cells, "num-cells", json); + param_from_json(params.duration, "duration", json); + param_from_json(params.min_delay, "min-delay", json); + param_from_json(params.cell.max_depth, "depth", json); + param_from_json(params.cell.branch_probs, "branch-probs", json); + param_from_json(params.cell.compartments, "compartments", json); + param_from_json(params.cell.lengths, "lengths", json); + param_from_json(params.cell.synapses, "synapses", json); + + if (!json.empty()) { + for (auto it=json.begin(); it!=json.end(); ++it) { + std::cout << " Warning: unused input parameter: \"" << it.key() << "\"\n"; + } + std::cout << "\n"; + } + + return params; +} + -- GitLab