diff --git a/miniapp/CMakeLists.txt b/miniapp/CMakeLists.txt index a5957854ea21feafa89eb63abcf1eb6410739ecc..682adefe1d04b057cb330dc9468485b276b797b2 100644 --- a/miniapp/CMakeLists.txt +++ b/miniapp/CMakeLists.txt @@ -4,8 +4,6 @@ set(MINIAPP_SOURCES io.cpp miniapp.cpp miniapp_recipes.cpp - model.cpp - trace_sampler.cpp ) add_executable(miniapp.exe ${MINIAPP_SOURCES} ${HEADERS}) diff --git a/miniapp/miniapp.cpp b/miniapp/miniapp.cpp index 32c8bc2c53d71e12b787a06a0abe2e8e8becf9c2..1a3065ec1c8d3178ccd0a2374a51948d2bc7be65 100644 --- a/miniapp/miniapp.cpp +++ b/miniapp/miniapp.cpp @@ -1,13 +1,17 @@ #include <cmath> #include <exception> #include <iostream> +#include <fstream> #include <memory> +#include <json/src/json.hpp> + #include <catypes.hpp> #include <cell.hpp> #include <cell_group.hpp> #include <fvm_cell.hpp> #include <mechanism_catalogue.hpp> +#include <model.hpp> #include <threading/threading.hpp> #include <profiling/profiler.hpp> #include <communication/communicator.hpp> @@ -17,17 +21,24 @@ #include "io.hpp" #include "miniapp_recipes.hpp" -#include "model.hpp" +#include "trace_sampler.hpp" using namespace nest::mc; using global_policy = communication::global_policy; using communicator_type = communication::communicator<global_policy>; +using lowered_cell = fvm::fvm_cell<double, cell_local_size_type>; +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<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); +void write_trace_json(const sample_trace_type& trace, const std::string& prefix = "trace_"); + int main(int argc, char** argv) { nest::mc::communication::global_policy_guard global_guard(argc, argv); @@ -47,7 +58,7 @@ int main(int argc, char** argv) { auto cell_range = distribute_cells(recipe->num_cells()); // build model from recipe - model m(*recipe, cell_range.first, cell_range.second, 0.1); + model_type m(*recipe, cell_range.first, cell_range.second); // inject some artificial spikes, 1 per 20 neurons. cell_gid_type spike_cell = 20*((cell_range.first+19)/20); @@ -55,13 +66,24 @@ int main(int argc, char** argv) { m.add_artificial_spike({spike_cell,0u}); } + // attach samplers to all probes + std::vector<std::unique_ptr<sample_trace_type>> traces; + const model_type::time_type sample_dt = 0.1; + for (auto probe: m.probes()) { + traces.push_back(make_trace(probe.id, probe.probe)); + m.attach_sampler(probe.id, make_trace_sampler(traces.back().get(),sample_dt)); + } + // run model m.run(options.tfinal, options.dt); util::profiler_output(0.001); std::cout << "there were " << m.num_spikes() << " spikes\n"; - m.write_traces(); + // save traces + for (const auto& trace: traces) { + write_trace_json(*trace.get()); + } } catch (io::usage_error& e) { // only print usage/startup errors on master @@ -109,3 +131,46 @@ std::unique_ptr<recipe> make_recipe(const io::cl_options& options) { return make_basic_rgraph_recipe(options.cells, p); } } + +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"; + units = "mV"; + break; + case probeKind::membrane_current: + name = "i"; + units = "mA/cm²"; + break; + default: ; + } + name += probe.location.segment? "dend" : "soma"; + + return util::make_unique<sample_trace_type>(probe_id, name, units); +} + +void write_trace_json(const sample_trace_type& trace, const std::string& prefix) { + auto path = prefix + std::to_string(trace.probe_id.gid) + + "." + std::to_string(trace.probe_id.index) + "_" + trace.name + ".json"; + + nlohmann::json jrep; + jrep["name"] = trace.name; + jrep["units"] = trace.units; + jrep["cell"] = trace.probe_id.gid; + jrep["probe"] = trace.probe_id.index; + + auto& jt = jrep["data"]["time"]; + auto& jy = jrep["data"][trace.name]; + + for (const auto& sample: trace.samples) { + jt.push_back(sample.time); + jy.push_back(sample.value); + } + std::ofstream file(path); + file << std::setw(1) << jrep << std::endl; +} + + diff --git a/miniapp/miniapp_recipes.cpp b/miniapp/miniapp_recipes.cpp index 322090332b3a27f88371959b8b7c2f0d0dd37688..f472f60c9d66e0157b17fedc7ae96feb024cd659 100644 --- a/miniapp/miniapp_recipes.cpp +++ b/miniapp/miniapp_recipes.cpp @@ -74,10 +74,10 @@ public: 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); + 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); + cell.add_probe({{i, i? 0.5: 0.0}, mc::probeKind::membrane_current}); } } EXPECTS(cell.probes().size()==cc.num_probes); diff --git a/miniapp/model.cpp b/miniapp/model.cpp deleted file mode 100644 index a7dca18ccc7bdbc05272f0bca0b52fdd4a3f4d3e..0000000000000000000000000000000000000000 --- a/miniapp/model.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include <cstdlib> -#include <vector> - -#include <catypes.hpp> -#include <cell.hpp> -#include <cell_group.hpp> -#include <communication/communicator.hpp> -#include <communication/global_policy.hpp> -#include <fvm_cell.hpp> -#include <profiling/profiler.hpp> -#include <recipe.hpp> -#include <threading/threading.hpp> - -#include "model.hpp" -#include "trace_sampler.hpp" - -namespace nest { -namespace mc { - -model::model(const recipe &rec, cell_gid_type cell_from, cell_gid_type cell_to, time_type sample_dt) { - // construct cell groups (one cell per group) and attach samplers - cell_groups_ = std::vector<cell_group_type>{cell_to-cell_from}; - samplers_.resize(cell_to-cell_from); - - threading::parallel_for::apply(cell_from, cell_to, - [&](cell_gid_type i) { - PE("setup", "cells"); - auto cell = rec.get_cell(i); - auto idx = i-cell_from; - cell_groups_[idx] = cell_group_type(i, cell); - - cell_local_index_type j = 0; - for (const auto& probe: cell.probes()) { - cell_member_type probe_id{i,j++}; - samplers_[idx].emplace_back(probe_id, probe.kind, probe.location, sample_dt); - const auto &sampler = samplers_[idx].back(); - cell_groups_[idx].add_sampler(probe_id, sampler, sampler.next_sample_t()); - } - PL(2); - }); - - // initialise communicator - communicator_ = communicator_type(cell_from, cell_to); -} - -void model::reset() { - t_ = 0.; - // otherwise unimplemented - std::abort(); -} - -model::time_type model::run(time_type tfinal, time_type dt) { - time_type min_delay = communicator_.min_delay(); - while (t_<tfinal) { - auto tuntil = std::min(t_+min_delay, tfinal); - threading::parallel_for::apply( - 0u, cell_groups_.size(), - [&](unsigned i) { - auto &group = cell_groups_[i]; - - PE("stepping","events"); - group.enqueue_events(communicator_.queue(i)); - PL(); - - group.advance(tuntil, dt); - - PE("events"); - communicator_.add_spikes(group.spikes()); - group.clear_spikes(); - PL(2); - }); - - PE("stepping", "exchange"); - communicator_.exchange(); - PL(2); - - t_ = tuntil; - } - return t_; -} - -void model::write_traces() const { - for (auto& gid_samplers: samplers_) { - for (auto& s: gid_samplers) { - s.write_trace(); - } - } -} - -void model::add_artificial_spike(cell_member_type source, time_type tspike) { - communicator_.add_spike({source, tspike}); -} - -} // namespace mc -} // namespace nest diff --git a/miniapp/model.hpp b/miniapp/model.hpp deleted file mode 100644 index 8388ffb4eada65fab9d1f8d288bd70abdf25bbe3..0000000000000000000000000000000000000000 --- a/miniapp/model.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#include <cstdlib> -#include <vector> - -#include <catypes.hpp> -#include <cell_group.hpp> -#include <communication/communicator.hpp> -#include <communication/global_policy.hpp> -#include <fvm_cell.hpp> -#include <recipe.hpp> - -#include "trace_sampler.hpp" - -namespace nest { -namespace mc { - -struct model { - using cell_group_type = cell_group<fvm::fvm_cell<double, cell_local_size_type>>; - using time_type = cell_group_type::time_type; - using communicator_type = communication::communicator<communication::global_policy>; - - model(const recipe &rec, cell_gid_type cell_from, cell_gid_type cell_to, time_type sample_dt); - - void reset(); - - time_type run(time_type tfinal, time_type dt); - - void write_traces() const; - - void add_artificial_spike(cell_member_type source) { - add_artificial_spike(source, t_); - } - - void add_artificial_spike(cell_member_type source, time_type tspike); - - std::size_t num_spikes() const { return communicator_.num_spikes(); } - -private: - time_type t_ = 0.; - std::vector<cell_group_type> cell_groups_; - std::vector<std::vector<sample_to_trace>> samplers_; - communicator_type communicator_; -}; - -} // namespace mc -} // namespace nest diff --git a/miniapp/trace_sampler.cpp b/miniapp/trace_sampler.cpp deleted file mode 100644 index 079adda8be19dc26cfb1f18696c2d5c98e414312..0000000000000000000000000000000000000000 --- a/miniapp/trace_sampler.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include <fstream> -#include <string> - -#include <json/src/json.hpp> - -#include "trace_sampler.hpp" - -namespace nest { -namespace mc { - -sample_to_trace::sample_to_trace(cell_member_type probe_id, - const std::string &name, - const std::string &units, - float dt, - float t_start): - trace_{name, units, probe_id.gid, probe_id.index}, - sample_dt_(dt), - t_next_sample_(t_start) -{} - -sample_to_trace::sample_to_trace(cell_member_type probe_id, - probeKind kind, - segment_location loc, - float dt, - float t_start): - sample_to_trace(probe_id, "", "", dt, t_start) -{ - std::string name = ""; - std::string units = ""; - - switch (kind) { - case probeKind::membrane_voltage: - name = "v"; - units = "mV"; - break; - case probeKind::membrane_current: - name = "i"; - units = "mA/cm^2"; - break; - default: ; - } - - trace_.name = name + (loc.segment? "dend": "soma"); - trace_.units = units; -} - -void sample_to_trace::write_trace(const std::string& prefix) const { - auto path = prefix + std::to_string(trace_.cell_gid) + - "." + std::to_string(trace_.probe_index) + ".json"; - - nlohmann::json jrep; - jrep["name"] = trace_.name; - jrep["units"] = trace_.units; - jrep["cell"] = trace_.cell_gid; - jrep["probe"] = trace_.probe_index; - - auto& jt = jrep["data"]["time"]; - auto& jy = jrep["data"][trace_.name]; - - for (const auto& sample: trace_.samples) { - jt.push_back(sample.time); - jy.push_back(sample.value); - } - std::ofstream file(path); - file << std::setw(1) << jrep << std::endl; -} - -} // namespace mc -} // namespace nest diff --git a/miniapp/trace_sampler.hpp b/miniapp/trace_sampler.hpp index e62c93cb1380787899ed09c54ecbd2902a52a1ed..b0ea4dcb01a44294c409bed1ea2cd4dbd7eeafa6 100644 --- a/miniapp/trace_sampler.hpp +++ b/miniapp/trace_sampler.hpp @@ -7,58 +7,65 @@ #include <cell.hpp> #include <util/optional.hpp> +#include <iostream> + namespace nest { namespace mc { // move sampler code to another source file... +template <typename TimeT=float, typename ValueT=double> struct sample_trace { + using time_type = TimeT; + using value_type = ValueT; + struct sample_type { - float time; - double value; + time_type time; + value_type value; }; std::string name; std::string units; - cell_gid_type cell_gid; - cell_local_index_type probe_index; + cell_member_type probe_id; std::vector<sample_type> samples; + + sample_trace() =default; + sample_trace(cell_member_type probe_id, const std::string &name, const std::string &units): + name(name), units(units), probe_id(probe_id) + {} }; -struct sample_to_trace { +template <typename TimeT=float, typename ValueT=double> +struct trace_sampler { + using time_type = TimeT; + using value_type = ValueT; + float next_sample_t() const { return t_next_sample_; } - util::optional<float> operator()(float t, double v) { + util::optional<time_type> operator()(time_type t, value_type v) { if (t<t_next_sample_) { return t_next_sample_; } - trace_.samples.push_back({t,v}); + trace_->samples.push_back({t,v}); return t_next_sample_+=sample_dt_; } - sample_to_trace(cell_member_type probe_id, - const std::string &name, - const std::string &units, - float dt, - float t_start=0); - - sample_to_trace(cell_member_type probe_id, - probeKind kind, - segment_location loc, - float dt, - float t_start=0); - - void write_trace(const std::string& prefix = "trace_") const; - - const sample_trace& trace() const { return trace_; } + trace_sampler(sample_trace<time_type, value_type> *trace, time_type sample_dt, time_type tfrom=0): + trace_(trace), sample_dt_(sample_dt), t_next_sample_(tfrom) + {} private: - sample_trace trace_; - - float sample_dt_; - float t_next_sample_; + sample_trace<time_type, value_type> *trace_; + time_type sample_dt_; + time_type t_next_sample_; }; +// with type deduction ... +template <typename TimeT, typename ValueT> +trace_sampler<TimeT, ValueT> make_trace_sampler(sample_trace<TimeT, ValueT> *trace, TimeT sample_dt, TimeT tfrom=0) { + return trace_sampler<TimeT, ValueT>(trace, sample_dt, tfrom); +} + } // namespace mc } // namespace nest diff --git a/src/cell.hpp b/src/cell.hpp index 137ea339eaaeef83a2a3b26206c98a017e87a181..5d01241c5d3d002daff5662d8cd68db6da650bd1 100644 --- a/src/cell.hpp +++ b/src/cell.hpp @@ -45,6 +45,11 @@ enum class probeKind { membrane_current }; +struct probe_spec { + segment_location location; + probeKind kind; +}; + /// high-level abstract representation of a cell and its segments class cell { public: @@ -59,14 +64,12 @@ public: segment_location location; parameter_list mechanism; }; - struct probe_instance { - segment_location location; - probeKind kind; - }; + struct stimulus_instance { segment_location location; i_clamp clamp; }; + struct detector_instance { segment_location location; double threshold; @@ -171,12 +174,12 @@ public: ////////////////// // probes ////////////////// - index_type add_probe(segment_location loc, probeKind kind) { - probes_.push_back({loc, kind}); + index_type add_probe(probe_spec p) { + probes_.push_back(p); return probes_.size()-1; } - const std::vector<probe_instance>& + const std::vector<probe_spec>& probes() const { return probes_; } private: @@ -197,7 +200,7 @@ private: std::vector<detector_instance> spike_detectors_; // the probes - std::vector<probe_instance> probes_; + std::vector<probe_spec> probes_; }; // Checks that two cells have the same diff --git a/src/cell_group.hpp b/src/cell_group.hpp index 10212123728e00492d6861241947aa6af92de019..37e97d43376b44e5d795b2216eef7288351eac6f 100644 --- a/src/cell_group.hpp +++ b/src/cell_group.hpp @@ -1,6 +1,7 @@ #pragma once #include <cstdint> +#include <functional> #include <vector> #include <catypes.hpp> @@ -37,8 +38,7 @@ public: cell_group(cell_gid_type gid, const cell& c) : gid_base_{gid}, cell_{c} { - cell_.voltage()(memory::all) = -65.; - cell_.initialize(); + initialize_cells(); source_id_type source_id={gid_base_,0}; for (auto& d : c.detectors()) { @@ -49,6 +49,14 @@ public: } } + void reset() { + remove_samplers(); + initialize_cells(); + for (auto& spike_source: spike_sources) { + spike_source.source.reset(cell_, 0.f); + } + } + void advance(time_type tfinal, time_type dt) { while (cell_.time()<tfinal) { // take any pending samples @@ -132,7 +140,17 @@ public: sample_events_.push({sampler_index, start_time}); } + void remove_samplers() { + sample_events_.clear(); + samplers_.clear(); + } + private: + void initialize_cells() { + cell_.voltage()(memory::all) = -65.; + cell_.initialize(); + } + /// gid of first cell in group cell_gid_type gid_base_; diff --git a/src/event_queue.hpp b/src/event_queue.hpp index 792fed34da681b9a4e4a3e1b8058eed860f2588b..8d04f9db0a1ecddaf24680c2e75ce00b56a31590 100644 --- a/src/event_queue.hpp +++ b/src/event_queue.hpp @@ -67,6 +67,11 @@ public : } } + // clear everything + void clear() { + queue_ = decltype(queue_){}; + } + private: struct event_greater { bool operator()(const Event &a, const Event &b) { diff --git a/src/model.hpp b/src/model.hpp new file mode 100644 index 0000000000000000000000000000000000000000..83ca129895571408d059ceb13fabb0c21b6206f8 --- /dev/null +++ b/src/model.hpp @@ -0,0 +1,123 @@ +#include <cstdlib> +#include <vector> + +#include <catypes.hpp> +#include <cell.hpp> +#include <cell_group.hpp> +#include <communication/communicator.hpp> +#include <communication/global_policy.hpp> +#include <fvm_cell.hpp> +#include <recipe.hpp> +#include <profiling/profiler.hpp> + +#include "trace_sampler.hpp" + +namespace nest { +namespace mc { + +template <typename Cell> +struct model { + using cell_group_type = cell_group<Cell>; + using time_type = typename cell_group_type::time_type; + using value_type = typename cell_group_type::value_type; + using communicator_type = communication::communicator<communication::global_policy>; + using sampler_function = typename cell_group_type::sampler_function; + + struct probe_record { + cell_member_type id; + probe_spec probe; + }; + + model(const recipe &rec, cell_gid_type cell_from, cell_gid_type cell_to): + cell_from_(cell_from), cell_to_(cell_to) + { + cell_groups_ = std::vector<cell_group_type>{cell_to_-cell_from_}; + + threading::parallel_vector<probe_record> probes; + threading::parallel_for::apply(cell_from_, cell_to_, + [&](cell_gid_type i) { + PE("setup", "cells"); + auto cell = rec.get_cell(i); + auto idx = i-cell_from_; + cell_groups_[idx] = cell_group_type(i, cell); + + cell_local_index_type j = 0; + for (const auto& probe: cell.probes()) { + cell_member_type probe_id{i,j++}; + probes.push_back({probe_id, probe}); + } + PL(2); + }); + + probes_.assign(probes.begin(), probes.end()); + communicator_ = communicator_type(cell_from_, cell_to_); + } + + void reset() { + t_ = 0.; + for (auto& group: cell_groups_) { + group.reset(); + } + } + + time_type run(time_type tfinal, time_type dt) { + time_type min_delay = communicator_.min_delay(); + while (t_<tfinal) { + auto tuntil = std::min(t_+min_delay, tfinal); + threading::parallel_for::apply( + 0u, cell_groups_.size(), + [&](unsigned i) { + auto &group = cell_groups_[i]; + + PE("stepping","events"); + group.enqueue_events(communicator_.queue(i)); + PL(); + + group.advance(tuntil, dt); + + PE("events"); + communicator_.add_spikes(group.spikes()); + group.clear_spikes(); + PL(2); + }); + + PE("stepping", "exchange"); + communicator_.exchange(); + PL(2); + + t_ = tuntil; + } + return t_; + } + + void add_artificial_spike(cell_member_type source) { + add_artificial_spike(source, t_); + } + + void add_artificial_spike(cell_member_type source, time_type tspike) { + communicator_.add_spike({source, tspike}); + } + + void attach_sampler(cell_member_type probe_id, sampler_function f, time_type tfrom = 0) { + // TODO: translate probe_id.gid to appropriate group, but for now 1-1. + if (probe_id.gid<cell_from_ || probe_id.gid>=cell_to_) { + return; + } + cell_groups_[probe_id.gid-cell_from_].add_sampler(probe_id, f, tfrom); + } + + const std::vector<probe_record>& probes() const { return probes_; } + + std::size_t num_spikes() const { return communicator_.num_spikes(); } + +private: + cell_gid_type cell_from_; + cell_gid_type cell_to_; + time_type t_ = 0.; + std::vector<cell_group_type> cell_groups_; + communicator_type communicator_; + std::vector<probe_record> probes_; +}; + +} // namespace mc +} // namespace nest diff --git a/src/spike_source.hpp b/src/spike_source.hpp index 95099cb547de24e76386c2253960b8fffe4bf569..0537b6800a19534d23aedd7de2edae3d022b53e6 100644 --- a/src/spike_source.hpp +++ b/src/spike_source.hpp @@ -13,13 +13,11 @@ class spike_detector public: using cell_type = Cell; - spike_detector( const cell_type& cell, segment_location loc, double thresh, float t_init) : + spike_detector(const cell_type& cell, segment_location loc, double thresh, float t_init) : location_(loc), - threshold_(thresh), - previous_t_(t_init) + threshold_(thresh) { - previous_v_ = cell.voltage(location_); - is_spiking_ = previous_v_ >= thresh ? true : false; + reset(cell, t_init); } util::optional<float> test(const cell_type& cell, float t) { @@ -58,6 +56,12 @@ public: float v() const { return previous_v_; } + void reset(const cell_type& cell, float t_init) { + previous_t_ = t_init; + previous_v_ = cell.voltage(location_); + is_spiking_ = previous_v_ >= threshold_; + } + private: // parameters/data diff --git a/src/threading/serial.hpp b/src/threading/serial.hpp index fb66e6e2ff78ec7eb638091ded2ac874583227e6..297f8266410ef334327856178346edb8a0d66607 100644 --- a/src/threading/serial.hpp +++ b/src/threading/serial.hpp @@ -56,6 +56,10 @@ struct parallel_for { } }; +template <typename T> +using parallel_vector = std::vector<T>; + + inline std::string description() { return "serial"; } diff --git a/src/threading/tbb.hpp b/src/threading/tbb.hpp index eae6b112bdb75b697709379b41f00cfbc249a3b1..8e0086741cac1d51e02e9fa148e9eaa3f3f837a3 100644 --- a/src/threading/tbb.hpp +++ b/src/threading/tbb.hpp @@ -46,6 +46,9 @@ struct timer { constexpr bool multithreaded() { return true; } +template <typename T> +using parallel_vector = tbb::concurrent_vector<T>; + } // threading } // mc } // nest diff --git a/tests/unit/test_probe.cpp b/tests/unit/test_probe.cpp index 289e5929c909d19732e9d7bae7ba43a05b2ccdcb..888e710eec377143b6ac6684e41cc222d0b0c107 100644 --- a/tests/unit/test_probe.cpp +++ b/tests/unit/test_probe.cpp @@ -13,8 +13,8 @@ TEST(probe, instantiation) segment_location loc1{0, 0}; segment_location loc2{1, 0.6}; - auto p1 = c1.add_probe(loc1, probeKind::membrane_voltage); - auto p2 = c1.add_probe(loc2, probeKind::membrane_current); + auto p1 = c1.add_probe({loc1, probeKind::membrane_voltage}); + auto p2 = c1.add_probe({loc2, probeKind::membrane_current}); // expect locally provided probe ids to be numbered sequentially from zero. @@ -49,9 +49,9 @@ TEST(probe, fvm_cell) segment_location loc1{1, 1}; segment_location loc2{1, 0.5}; - auto pv0 = bs.add_probe(loc0, probeKind::membrane_voltage); - auto pv1 = bs.add_probe(loc1, probeKind::membrane_voltage); - auto pi2 = bs.add_probe(loc2, probeKind::membrane_current); + auto pv0 = bs.add_probe({loc0, probeKind::membrane_voltage}); + auto pv1 = bs.add_probe({loc1, probeKind::membrane_voltage}); + auto pi2 = bs.add_probe({loc2, probeKind::membrane_current}); i_clamp stim(0, 100, 0.3); bs.add_stimulus({1, 1}, stim); diff --git a/tests/validation/validate_synapses.cpp b/tests/validation/validate_synapses.cpp index 9607f416a9c49a9344a45ffd5c1a4366241738fc..3dbf7fbb62efc44d128f58222b22f3f2ae437eaf 100644 --- a/tests/validation/validate_synapses.cpp +++ b/tests/validation/validate_synapses.cpp @@ -71,8 +71,8 @@ void run_neuron_baseline(const char* syn_type, const char* data_file) cell.add_synapse({1, 0.5}, syn_default); // add probes - auto probe_soma = cell.add_probe({0,0}, probeKind::membrane_voltage); - auto probe_dend = cell.add_probe({1,0.5}, probeKind::membrane_voltage); + auto probe_soma = cell.add_probe({{0,0}, probeKind::membrane_voltage}); + auto probe_dend = cell.add_probe({{1,0.5}, probeKind::membrane_voltage}); // injected spike events postsynaptic_spike_event synthetic_events[] = {