diff --git a/arbor/include/arbor/simulation.hpp b/arbor/include/arbor/simulation.hpp index b5de7b4a5cd3f416ddceddd541fa8f2904f3d280..86e30e104f1b0d44ff90deb38f83831522bb11ff 100644 --- a/arbor/include/arbor/simulation.hpp +++ b/arbor/include/arbor/simulation.hpp @@ -85,11 +85,6 @@ public: // start of the simulation. void set_epoch_callback(epoch_function = epoch_function{}); - // Add events directly to targets. - // Must be called before calling simulation::run, and must contain events that - // are to be delivered at or after the current simulation time. - void inject_events(const cse_vector& events); - // If remote connections are present, export only the spikes for which this // predicate returns true. void set_remote_spike_filter(const spike_predicate&); diff --git a/arbor/include/arbor/spike_event.hpp b/arbor/include/arbor/spike_event.hpp index d44cd7cd449b7b113a5c6e6e503758b51466190e..7e1fc637e82e99448dc24131a4f4df1a93b84ce7 100644 --- a/arbor/include/arbor/spike_event.hpp +++ b/arbor/include/arbor/spike_event.hpp @@ -29,13 +29,6 @@ ARB_DEFINE_LEXICOGRAPHIC_ORDERING(spike_event,(a.time,a.target,a.weight),(b.time using pse_vector = std::vector<spike_event>; -struct cell_spike_events { - cell_gid_type target; - pse_vector events; -}; - -using cse_vector = std::vector<cell_spike_events>; - ARB_ARBOR_API std::ostream& operator<<(std::ostream&, const spike_event&); } // namespace arb diff --git a/arbor/simulation.cpp b/arbor/simulation.cpp index 95963e85fd13f6067d271003d16d1dc9322fc079..55c027710a92c8892e7f568daabc561d91c608a8 100644 --- a/arbor/simulation.cpp +++ b/arbor/simulation.cpp @@ -108,8 +108,6 @@ public: void set_remote_spike_filter(const spike_predicate& p) { return communicator_.set_remote_spike_filter(p); } - void inject_events(const cse_vector& events); - time_type min_delay() { return communicator_.min_delay(); } spike_export_function global_export_callback_; @@ -560,22 +558,6 @@ std::vector<probe_metadata> simulation_state::get_probe_metadata(const cell_addr } } -void simulation_state::inject_events(const cse_vector& events) { - // Push all events that are to be delivered to local cells into the - // pending event list for the event's target cell. - for (auto& [gid, pse_vector]: events) { - for (auto& e: pse_vector) { - if (e.time < epoch_.t1) { - throw bad_event_time(e.time, epoch_.t1); - } - // gid_to_local_ maps gid to index in local cells and of corresponding cell group. - if (auto lidx = util::value_by_key(gid_to_local_, gid)) { - pending_events_[lidx->cell_index].push_back(e); - } - } - } -} - // Simulation class implementations forward to implementation class. simulation_builder simulation::create(recipe const & rec) { return {rec}; }; @@ -639,10 +621,6 @@ void simulation::set_epoch_callback(epoch_function epoch_callback) { impl_->epoch_callback_ = std::move(epoch_callback); } -void simulation::inject_events(const cse_vector& events) { - impl_->inject_events(events); -} - simulation::simulation(simulation&&) = default; simulation::~simulation() = default; diff --git a/doc/cpp/simulation.rst b/doc/cpp/simulation.rst index 6edca840e4ff6c7d1c3774d437dbfb3f2e73ba4f..23f8ccd040b6d95a62624463a9091550d279ebb9 100644 --- a/doc/cpp/simulation.rst +++ b/doc/cpp/simulation.rst @@ -100,14 +100,6 @@ Class documentation Returns a builder object to which the constructor arguments can be passed selectively (see also example above). - **Experimental inputs:** - - .. cpp:function:: void inject_events(const pse_vector& events) - - Add events directly to targets. - Must be called before calling :cpp:func:`run`, and must contain events that - are to be delivered at or after the current simulation time. - **Updating Model State:** .. cpp:function:: void reset() diff --git a/example/single/single.cpp b/example/single/single.cpp index 200ad24a6ab1a222973843aef0d734864b623549..53b05855ef970b367fba613ae778fd1287731964 100644 --- a/example/single/single.cpp +++ b/example/single/single.cpp @@ -32,8 +32,10 @@ options parse_options(int argc, char** argv); arborio::loaded_morphology default_morphology(); struct single_recipe: public arb::recipe { - explicit single_recipe(arborio::loaded_morphology m, arb::cv_policy pol): - morpho(std::move(m.morphology)) { + explicit single_recipe(arborio::loaded_morphology m, arb::cv_policy pol, float w): + morpho(std::move(m.morphology)), + syn_weight{w} + { gprop.default_parameters = arb::neuron_parameter_defaults; gprop.default_parameters.discretization = pol; } @@ -74,15 +76,21 @@ struct single_recipe: public arb::recipe { return arb::cable_cell(morpho, decor, dict); } + std::vector<arb::event_generator> event_generators(arb::cell_gid_type) const override { + return {arb::explicit_generator_from_milliseconds({"synapse"}, syn_weight, std::vector{1.0})}; + } + arb::morphology morpho; arb::cable_cell_global_properties gprop; + float syn_weight; }; int main(int argc, char** argv) { try { options opt = parse_options(argc, argv); single_recipe R(opt.swc_file.empty() ? default_morphology() : arborio::load_swc_arbor(opt.swc_file), - opt.policy); + opt.policy, + opt.syn_weight); arb::simulation sim(R); @@ -92,12 +100,6 @@ int main(int argc, char** argv) { arb::regular_schedule(0.1*arb::units::ms), arb::make_simple_sampler(traces)); - // Trigger the single synapse (target is gid 0, index 0) at t = 1 ms - // with the given weight. - arb::spike_event spike = {0, 1., opt.syn_weight}; - arb::cell_spike_events cell_spikes = {0, {spike}}; - sim.inject_events({cell_spikes}); - sim.run(opt.t_end*arb::units::ms, opt.dt*arb::units::ms); for (auto entry: traces.at(0)) { diff --git a/example/v_clamp/v-clamp.cpp b/example/v_clamp/v-clamp.cpp index 9068065cd6111535201e88b9d1f5f3d345640b14..86f4441c3ff1aa034ab455a7c7fee0aefeb4c4d8 100644 --- a/example/v_clamp/v-clamp.cpp +++ b/example/v_clamp/v-clamp.cpp @@ -1,7 +1,5 @@ #include <any> -#include <fstream> #include <iostream> -#include <stdexcept> #include <string> #include <vector> @@ -33,7 +31,10 @@ options parse_options(int argc, char** argv); arborio::loaded_morphology default_morphology(); struct single_recipe: public arb::recipe { - explicit single_recipe(arborio::loaded_morphology m, arb::cv_policy pol): morpho(std::move(m.morphology)) { + explicit single_recipe(arborio::loaded_morphology m, arb::cv_policy pol, float w): + morpho(std::move(m.morphology)), + syn_weight(w) + { gprop.default_parameters = arb::neuron_parameter_defaults; gprop.default_parameters.discretization = pol; } @@ -75,15 +76,22 @@ struct single_recipe: public arb::recipe { return arb::cable_cell(morpho, decor, dict); } + std::vector<arb::event_generator> event_generators(arb::cell_gid_type) const override { + return {arb::explicit_generator_from_milliseconds({"synapse"}, syn_weight, std::vector{1.0})}; + } + std::optional<double> voltage_clamp; arb::morphology morpho; arb::cable_cell_global_properties gprop; + float syn_weight; }; int main(int argc, char** argv) { try { options opt = parse_options(argc, argv); - single_recipe R(opt.swc_file.empty()? default_morphology(): arborio::load_swc_arbor(opt.swc_file), opt.policy); + single_recipe R(opt.swc_file.empty()? default_morphology(): arborio::load_swc_arbor(opt.swc_file), + opt.policy, + opt.syn_weight); R.voltage_clamp = opt.voltage; arb::simulation sim(R); @@ -92,13 +100,6 @@ int main(int argc, char** argv) { arb::trace_vector<double> traces; sim.add_sampler(arb::all_probes, arb::regular_schedule(0.1*arb::units::ms), arb::make_simple_sampler(traces)); - // Trigger the single synapse (target is gid 0, index 0) at t = 1 ms with - // the given weight. - - arb::spike_event spike = {0, 1., opt.syn_weight}; - arb::cell_spike_events cell_spikes = {0, {spike}}; - sim.inject_events({cell_spikes}); - sim.run(opt.t_end*arb::units::ms, opt.dt*arb::units::ms); for (auto entry: traces.at(0)) { diff --git a/python/example/single_cell_bluepyopt_l5pc.py b/python/example/single_cell_bluepyopt_l5pc.py index 90e0e31adc558f1f822ea0a8a8d856a196c81541..ec305b0e35b0b7f0f1733b4a5b5b5bb2bfa97973 100755 --- a/python/example/single_cell_bluepyopt_l5pc.py +++ b/python/example/single_cell_bluepyopt_l5pc.py @@ -69,7 +69,7 @@ class single_recipe(arbor.recipe): def num_cells(self): return 1 - # (6.3) Override the num_targets method + # (6.3) Override the cell_kind method def cell_kind(self, gid): return arbor.cell_kind.cable diff --git a/test/unit/test_event_delivery.cpp b/test/unit/test_event_delivery.cpp index 8800224e249e6669f65d0ca9c28b01e65547ec6e..b5985eabea0240abf98f0b6eee0bff7ac1def74e 100644 --- a/test/unit/test_event_delivery.cpp +++ b/test/unit/test_event_delivery.cpp @@ -25,6 +25,8 @@ using namespace arb; using n_cable_cell_recipe = homogeneous_recipe<cell_kind::cable, cable_cell>; +constexpr time_type ev_delta_t = 0.2; + struct test_recipe: public n_cable_cell_recipe { explicit test_recipe(int n): n_cable_cell_recipe(n, test_cell()) {} @@ -43,6 +45,10 @@ struct test_recipe: public n_cable_cell_recipe { return c; } + + std::vector<arb::event_generator> event_generators(arb::cell_gid_type gid) const override { + return {arb::explicit_generator_from_milliseconds({"synapse"}, 1.0f, std::vector{gid*ev_delta_t})}; + } }; using gid_vector = std::vector<cell_gid_type>; @@ -66,14 +72,6 @@ std::vector<cell_gid_type> run_test_sim(const recipe& R, const group_gids_type& spikes.insert(spikes.end(), ss.begin(), ss.end()); }); - constexpr time_type ev_delta_t = 0.2; - - cse_vector cell_events; - for (unsigned i = 0; i<n; ++i) { - cell_events.push_back({i, {{0u, i*ev_delta_t, 1.f}}}); - } - - sim.inject_events(cell_events); sim.run((n+1)*ev_delta_t*arb::units::ms, 0.01*arb::units::ms); std::vector<cell_gid_type> spike_gids; diff --git a/test/unit/test_lif_cell_group.cpp b/test/unit/test_lif_cell_group.cpp index 8e13b222faa0b5b1e9bd153cd00c943110b9b124..72d79d858aa27a47b658348997d8170f8303c197 100644 --- a/test/unit/test_lif_cell_group.cpp +++ b/test/unit/test_lif_cell_group.cpp @@ -101,6 +101,16 @@ public: return cell; } + std::vector<arb::event_generator> event_generators(arb::cell_gid_type gid) const override { + if (gid != 0) return {}; + return {arb::explicit_generator_from_milliseconds({"tgt"}, + 1000.0, // use a large weight to trigger spikes + std::vector{ 1.0, // First event to trigger the spike + 1.1, // inside refractory period; should be ignored + 50.0 // long after previous event; should trigger new spike + })}; + } + private: cell_size_type ncells_; float weight_, delay_; @@ -177,20 +187,6 @@ TEST(lif_cell_group, spikes) { auto decomp = partition_load_balance(recipe, context); simulation sim(recipe, context, decomp); - cse_vector events; - - // First event to trigger the spike (first neuron). - events.push_back({0, {{0, 1, 1000}}}); - - // This event happens inside the refractory period of the previous - // event, thus, should be ignored (first neuron) - events.push_back({0, {{0, 1.1, 1000}}}); - - // This event happens long after the refractory period of the previous - // event, should thus trigger new spike (first neuron). - events.push_back({0, {{0, 50, 1000}}}); - - sim.inject_events(events); sim.run(100*U::ms, 0.01*U::ms); // we expect 4 spikes: 2 by both neurons