diff --git a/mechanisms/mod/exp2syn.mod b/mechanisms/mod/exp2syn.mod index da2d2ae639143b1732b714b20f5ce0c2cf1f2216..ea0cf025e9228216b4699161a2e574ca1d1dda6e 100755 --- a/mechanisms/mod/exp2syn.mod +++ b/mechanisms/mod/exp2syn.mod @@ -1,5 +1,5 @@ NEURON { - POINT_PROCESS Exp2Syn + POINT_PROCESS exp2syn RANGE tau1, tau2, e NONSPECIFIC_CURRENT i } @@ -11,8 +11,8 @@ UNITS { } PARAMETER { - tau1=.1 (ms) : <1e-9,1e9> - tau2 = 10 (ms) : <1e-9,1e9> + tau1 = .5 (ms) : <1e-9,1e9> + tau2 = 2 (ms) : <1e-9,1e9> e=0 (mV) } diff --git a/mechanisms/mod/expsyn.mod b/mechanisms/mod/expsyn.mod index db1f6d6ed61a8b563141ea2516658b8f87a35637..16d10c5cf856cd87e50252dca2163d844588e2b9 100644 --- a/mechanisms/mod/expsyn.mod +++ b/mechanisms/mod/expsyn.mod @@ -1,5 +1,5 @@ NEURON { - POINT_PROCESS ExpSyn + POINT_PROCESS expsyn RANGE tau, e NONSPECIFIC_CURRENT i } diff --git a/miniapp/miniapp.cpp b/miniapp/miniapp.cpp index dfff77fa544cb68be9f0454dec8380c99aa530f8..ea5207dc732c69a42b3e66f1aa525a08cf69abca 100644 --- a/miniapp/miniapp.cpp +++ b/miniapp/miniapp.cpp @@ -425,8 +425,9 @@ mc::cell make_cell(int compartments_per_segment, int num_synapses) { auto distribution = std::uniform_real_distribution<float>(0.f, 1.0f); // distribute the synapses at random locations the terminal dendrites in a // round robin manner + nest::mc::parameter_list syn_default("expsyn"); for (auto i=0; i<num_synapses; ++i) { - cell.add_synapse({2+(i%2), distribution(gen)}); + cell.add_synapse({2+(i%2), distribution(gen)}, syn_default); } // add probes: diff --git a/src/cell.cpp b/src/cell.cpp index 3a2d5672a12bb74e2e484765e16b93e870b2bd4b..01d681a7e080c8c0444fe0299820181d5154028e 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -201,16 +201,6 @@ std::vector<int> const& cell::segment_parents() const return parents_; } -void cell::add_synapse(segment_location loc) -{ - synapses_.push_back(loc); -} - -const std::vector<segment_location>& cell::synapses() const -{ - return synapses_; -} - // Rough and ready comparison of two cells. // We don't use an operator== because equality of two cells is open to // interpretation. For example, it is possible to have two viable representations diff --git a/src/cell.hpp b/src/cell.hpp index 744c9970e26af7f439f9cee7cfb2f88c96014624..1cb9b9f65dedbdcc4476c2b447eed1d1dea243ca 100644 --- a/src/cell.hpp +++ b/src/cell.hpp @@ -52,6 +52,11 @@ public: using index_type = int; using value_type = double; using point_type = point<value_type>; + + struct synapse_instance { + segment_location location; + parameter_list mechanism; + }; struct probe_instance { segment_location location; probeKind kind; @@ -138,9 +143,13 @@ public: ////////////////// // synapses ////////////////// - void add_synapse(segment_location loc); - - const std::vector<segment_location>& synapses() const; + void add_synapse(segment_location loc, parameter_list p) + { + synapses_.push_back(synapse_instance{loc, std::move(p)}); + } + const std::vector<synapse_instance>& synapses() const { + return synapses_; + } ////////////////// // spike detectors @@ -180,7 +189,7 @@ private: std::vector<stimulus_instance> stimulii_; // the synapses - std::vector<segment_location> synapses_; + std::vector<synapse_instance> synapses_; // the sensors std::vector<detector_instance> spike_detectors_; diff --git a/src/fvm_cell.hpp b/src/fvm_cell.hpp index 25c0ae9a0c67dd42e7bcf680a9b32a0c6070290b..05bce5bd02b57c8d8fe9a9c3e90962eeee8188b3 100644 --- a/src/fvm_cell.hpp +++ b/src/fvm_cell.hpp @@ -20,8 +20,6 @@ #include <profiling/profiler.hpp> #include <vector/include/Vector.hpp> -#include <mechanisms/expsyn.hpp> - namespace nest { namespace mc { @@ -185,10 +183,12 @@ private: /// the potential in mV in each CV vector_type voltage_; +#if 0 /// synapses using synapse_type = mechanisms::ExpSyn::mechanism_ExpSyn<value_type, size_type>; - std::size_t synapse_index_; +#endif + std::size_t synapse_index_; // synapses at the end of mechanisms_, from here /// the set of mechanisms present in the cell std::vector<mechanism_type> mechanisms_; @@ -342,6 +342,52 @@ fvm_cell<T, I>::fvm_cell(nest::mc::cell const& cell) ); } + synapse_index_ = mechanisms_.size(); + + std::multimap<std::string, int> syn_map; + for (const auto& syn: cell.synapses()) { + syn_map.insert({syn.mechanism.name(), find_compartment_index(syn.location, graph)}); + } + + auto syn_i = syn_map.begin(); + while (syn_i!=syn_map.end()) { + const auto& mech_name = syn_i->first; + auto& helper = nest::mc::mechanisms::get_mechanism_helper(mech_name); + + auto span = syn_map.equal_range(mech_name); + auto num_comp = std::distance(span.first, span.second); + + index_type compartment_index(num_comp); + for (auto p = compartment_index.data(); syn_i!=span.second; ++p, ++syn_i) { + *p = syn_i->second; + } + + auto mech = helper->new_mechanism(voltage_, current_, compartment_index); + mech->set_areas(cv_areas_); + mechanisms_.push_back(std::move(mech)); + } + +#if 0 + // add the synapses + std::vector<size_type> synapse_indexes; + synapse_indexes.reserve(cell.synapses().size()); + for(auto loc : cell.synapses()) { + synapse_indexes.push_back( + find_compartment_index(loc, graph) + ); + } + + mechanisms_.push_back( + mechanisms::make_mechanism<synapse_type>( + voltage_, current_, index_view(synapse_indexes) + ) + ); + synapse_index_ = mechanisms_.size()-1; + // don't forget to give point processes access to cv_areas_ + mechanisms_[synapse_index_]->set_areas(cv_areas_); +#endif + + ///////////////////////////////////////////// // build the ion species ///////////////////////////////////////////// @@ -398,24 +444,6 @@ fvm_cell<T, I>::fvm_cell(nest::mc::cell const& cell) stimulii_.push_back( {idx, stim.clamp} ); } - // add the synapses - std::vector<size_type> synapse_indexes; - synapse_indexes.reserve(cell.synapses().size()); - for(auto loc : cell.synapses()) { - synapse_indexes.push_back( - find_compartment_index(loc, graph) - ); - } - - mechanisms_.push_back( - mechanisms::make_mechanism<synapse_type>( - voltage_, current_, index_view(synapse_indexes) - ) - ); - synapse_index_ = mechanisms_.size()-1; - // don't forget to give point processes access to cv_areas_ - mechanisms_[synapse_index_]->set_areas(cv_areas_); - // record probe locations by index into corresponding state vector for (auto probe : cell.probes()) { uint32_t comp = find_compartment_index(probe.location, graph); diff --git a/src/mechanism_interface.cpp b/src/mechanism_interface.cpp index f44d1f561d3efcc51b262b5bb32e0a95084bbcb5..680e8739d11ee0dad16890bb1088a1a7d4b774b5 100644 --- a/src/mechanism_interface.cpp +++ b/src/mechanism_interface.cpp @@ -6,6 +6,8 @@ #include <mechanisms/hh.hpp> #include <mechanisms/pas.hpp> +#include <mechanisms/expsyn.hpp> +#include <mechanisms/exp2syn.hpp> namespace nest { @@ -24,6 +26,16 @@ void setup_mechanism_helpers() { make_mechanism_helper< mechanisms::hh::helper<value_type, index_type> >(); + + mechanism_helpers["expsyn"] = + make_mechanism_helper< + mechanisms::expsyn::helper<value_type, index_type> + >(); + + mechanism_helpers["exp2syn"] = + make_mechanism_helper< + mechanisms::exp2syn::helper<value_type, index_type> + >(); } mechanism_helper_ptr<value_type, index_type>& diff --git a/tests/unit/test_mechanisms.cpp b/tests/unit/test_mechanisms.cpp index aef84890275263ca7ef9570c1017864736a6f331..2e31f1139d25cb3e36bc1ff0b32a3ec8a4316a4b 100644 --- a/tests/unit/test_mechanisms.cpp +++ b/tests/unit/test_mechanisms.cpp @@ -6,7 +6,7 @@ TEST(mechanisms, helpers) { nest::mc::mechanisms::setup_mechanism_helpers(); - EXPECT_EQ(nest::mc::mechanisms::mechanism_helpers.size(), 2u); + EXPECT_EQ(nest::mc::mechanisms::mechanism_helpers.size(), 4u); // verify that the hh and pas channels are available EXPECT_EQ(nest::mc::mechanisms::get_mechanism_helper("hh")->name(), "hh"); diff --git a/tests/unit/test_synapses.cpp b/tests/unit/test_synapses.cpp index ff79c1e6488a2534a03303aa30f05403bd4acdf9..9ad68c2444ef17d6f2b2355e3c388f76ca9220e6 100644 --- a/tests/unit/test_synapses.cpp +++ b/tests/unit/test_synapses.cpp @@ -3,6 +3,8 @@ #include <cell.hpp> #include <fvm_cell.hpp> +#include <mechanisms/expsyn.hpp> +#include <mechanisms/exp2syn.hpp> // compares results with those generated by nrn/ball_and_stick.py TEST(synapses, add_to_cell) @@ -18,29 +20,37 @@ TEST(synapses, add_to_cell) auto soma = cell.add_soma(12.6157/2.0); soma->add_mechanism(hh_parameters()); - cell.add_synapse({0, 0.1}); - cell.add_synapse({1, 0.2}); - cell.add_synapse({0, 0.3}); + parameter_list exp_default("expsyn"); + parameter_list exp2_default("exp2syn"); + + cell.add_synapse({0, 0.1}, exp_default); + cell.add_synapse({1, 0.2}, exp2_default); + cell.add_synapse({0, 0.3}, exp_default); EXPECT_EQ(3u, cell.synapses().size()); - EXPECT_EQ(cell.synapses()[0].segment, 0); - EXPECT_EQ(cell.synapses()[0].position, 0.1); - EXPECT_EQ(cell.synapses()[1].segment, 1); - EXPECT_EQ(cell.synapses()[1].position, 0.2); - EXPECT_EQ(cell.synapses()[2].segment, 0); - EXPECT_EQ(cell.synapses()[2].position, 0.3); + const auto& syns = cell.synapses(); + + EXPECT_EQ(syns[0].location.segment, 0); + EXPECT_EQ(syns[0].location.position, 0.1); + EXPECT_EQ(syns[0].mechanism.name(), "expsyn"); + + EXPECT_EQ(syns[1].location.segment, 1); + EXPECT_EQ(syns[1].location.position, 0.2); + EXPECT_EQ(syns[1].mechanism.name(), "exp2syn"); + + EXPECT_EQ(syns[2].location.segment, 0); + EXPECT_EQ(syns[2].location.position, 0.3); + EXPECT_EQ(syns[2].mechanism.name(), "expsyn"); } // compares results with those generated by nrn/ball_and_stick.py -TEST(synapses, basic_state) +TEST(synapses, expsyn_basic_state) { using namespace nest::mc; - // setup global state for the mechanisms - nest::mc::mechanisms::setup_mechanism_helpers(); - - using synapse_type = mechanisms::ExpSyn::mechanism_ExpSyn<double, int>; + using synapse_type = mechanisms::expsyn::mechanism_expsyn<double, int>; auto num_syn = 4; + synapse_type::index_type indexes(num_syn); synapse_type::vector_type voltage(num_syn, -65.0); synapse_type::vector_type current(num_syn, 1.0); @@ -81,3 +91,54 @@ TEST(synapses, basic_state) EXPECT_EQ(ptr->g[1], 3.14); EXPECT_EQ(ptr->g[3], 1.04); } + +TEST(synapses, exp2syn_basic_state) +{ + using namespace nest::mc; + + using synapse_type = mechanisms::exp2syn::mechanism_exp2syn<double, int>; + auto num_syn = 4; + + synapse_type::index_type indexes(num_syn); + synapse_type::vector_type voltage(num_syn, -65.0); + synapse_type::vector_type current(num_syn, 1.0); + auto mech = mechanisms::make_mechanism<synapse_type>( voltage, current, indexes ); + + auto ptr = dynamic_cast<synapse_type*>(mech.get()); + + // parameters initialized to default values + for(auto e : ptr->e) { + EXPECT_EQ(e, 0.); + } + for(auto tau1: ptr->tau1) { + EXPECT_EQ(tau1, 0.5); + } + for(auto tau2: ptr->tau2) { + EXPECT_EQ(tau2, 2.0); + } + + // should be initialized to NaN + for(auto factor: ptr->factor) { + EXPECT_NE(factor, factor); + } + + // initialize state then check factor has sane (positive) value + // and A and B are zero + ptr->nrn_init(); + for(auto factor: ptr->factor) { + EXPECT_GT(factor, 0.); + } + for(auto A: ptr->A) { + EXPECT_EQ(A, 0.); + } + for(auto B: ptr->B) { + EXPECT_EQ(B, 0.); + } + + // call net_receive on two of the synapses + ptr->net_receive(1, 3.14); + ptr->net_receive(3, 1.04); + + EXPECT_NEAR(ptr->A[1], ptr->factor[1]*3.14, 1e-6); + EXPECT_NEAR(ptr->B[3], ptr->factor[3]*1.04, 1e-6); +} diff --git a/tests/validation/validate_synapses.cpp b/tests/validation/validate_synapses.cpp index 694887ce1cab4e27a322d48789200d5e07493608..42ace29c3393bb177b878ab3e8c6eb6de42d8676 100644 --- a/tests/validation/validate_synapses.cpp +++ b/tests/validation/validate_synapses.cpp @@ -46,7 +46,7 @@ struct result { }; // compares results with those generated by nrn/simple_synapse.py -TEST(simple_synapse, neuron_baseline) +void run_neuron_baseline(const char* syn_type, const char* data_file) { using namespace nest::mc; using namespace nlohmann; @@ -67,10 +67,11 @@ TEST(simple_synapse, neuron_baseline) dendrite->mechanism("membrane").set("r_L", 100); soma->mechanism("membrane").set("r_L", 100); - // add stimulus - cell.add_synapse({1, 0.5}); + // add synapse + parameter_list syn_default(syn_type); + cell.add_synapse({1, 0.5}, syn_default); - // add porbes + // 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); @@ -82,7 +83,7 @@ TEST(simple_synapse, neuron_baseline) }; // load data from file - auto cell_data = testing::g_validation_data.load("simple_exp_synapse.json"); + auto cell_data = testing::g_validation_data.load(data_file); EXPECT_TRUE(cell_data.size()>0); if(cell_data.size()==0) return; @@ -164,3 +165,12 @@ TEST(simple_synapse, neuron_baseline) } } +TEST(simple_synapse, expsyn_neuron_baseline) { + SCOPED_TRACE("expsyn"); + run_neuron_baseline("expsyn","simple_exp_synapse.json"); +} + +TEST(simple_synapse, exp2syn_neuron_baseline) { + SCOPED_TRACE("exp2syn"); + run_neuron_baseline("exp2syn","simple_exp2_synapse.json"); +}