diff --git a/miniapp/miniapp.cpp b/miniapp/miniapp.cpp index fec0e995d56903f50a6b743b63df9eb01e428011..f8c54b9772ca542b3c3e3542cc5329a93b3e832b 100644 --- a/miniapp/miniapp.cpp +++ b/miniapp/miniapp.cpp @@ -2,23 +2,24 @@ #include <fstream> #include <sstream> -#include <cell.hpp> -#include <cell_group.hpp> -#include <fvm_cell.hpp> -#include <mechanism_interface.hpp> - -#include "io.hpp" +#include "catypes.hpp" +#include "cell.hpp" +#include "cell_group.hpp" +#include "fvm_cell.hpp" +#include "mechanism_catalogue.hpp" #include "threading/threading.hpp" #include "profiling/profiler.hpp" #include "communication/communicator.hpp" #include "communication/global_policy.hpp" #include "util/optional.hpp" +#include "io.hpp" + using namespace nest; using real_type = double; -using index_type = int; -using id_type = uint32_t; +using index_type = mc::cell_gid_type; +using id_type = mc::cell_gid_type; using numeric_cell = mc::fvm::fvm_cell<real_type, index_type>; using cell_group = mc::cell_group<numeric_cell>; @@ -112,7 +113,7 @@ struct model { }; std::string name; std::string units; - index_type id; + mc::cell_gid_type id; std::vector<sample_type> samples; }; @@ -140,10 +141,10 @@ struct model { }; mc::sampler make_simple_sampler( - index_type probe_gid, const std::string& name, const std::string& units, index_type id, float dt) + mc::cell_member_type probe_id, const std::string& name, const std::string& units, float dt) { - traces.push_back(trace_data{name, units, id}); - return {probe_gid, simple_sampler_functor(traces, traces.size()-1, dt)}; + traces.push_back(trace_data{name, units, probe_id.gid}); + return {probe_id, simple_sampler_functor(traces, traces.size()-1, dt)}; } void reset_traces() { @@ -161,10 +162,10 @@ struct model { jrep["name"] = trace.name; jrep["units"] = trace.units; jrep["id"] = trace.id; - + 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); @@ -363,18 +364,18 @@ void all_to_all_model(nest::mc::io::cl_options& options, model& m) { } auto lid = m.communicator.group_lid(gid); - auto probe_soma = m.cell_groups[lid].probe_gid_range().first; - auto probe_dend = probe_soma+1; - auto probe_dend_current = probe_soma+2; + mc::cell_member_type probe_soma = {gid, m.cell_groups[lid].probe_gid_range().first}; + mc::cell_member_type probe_dend = {gid, probe_soma.index+1}; + mc::cell_member_type probe_dend_current = {gid, probe_soma.index+2}; m.cell_groups[lid].add_sampler( - m.make_simple_sampler(probe_soma, "vsoma", "mV", gid, sample_dt) + m.make_simple_sampler(probe_soma, "vsoma", "mV", sample_dt) ); m.cell_groups[lid].add_sampler( - m.make_simple_sampler(probe_dend, "vdend", "mV", gid, sample_dt) + m.make_simple_sampler(probe_dend, "vdend", "mV", sample_dt) ); m.cell_groups[lid].add_sampler( - m.make_simple_sampler(probe_dend_current, "idend", "mA/cm²", gid, sample_dt) + m.make_simple_sampler(probe_dend_current, "idend", "mA/cm²", sample_dt) ); } @@ -394,9 +395,6 @@ void setup() { std::cout << " - communication policy: " << global_policy::name() << "\n"; std::cout << "====================\n"; } - - // setup global state for the mechanisms - mc::mechanisms::setup_mechanism_helpers(); } // make a high level cell description for use in simulation @@ -446,4 +444,3 @@ mc::cell make_cell(int compartments_per_segment, int num_synapses, const std::st cell_group make_lowered_cell(int cell_index, const mc::cell& c) { return cell_group(c); } - diff --git a/miniapp/recipes.cpp b/miniapp/recipes.cpp index df8fbce47ae4b9e71a9e522c40c1fa6a45b40e02..9c3f748def206e65f3f821589302e2461a1d680b 100644 --- a/miniapp/recipes.cpp +++ b/miniapp/recipes.cpp @@ -11,92 +11,67 @@ * For now, abstract base class while working out the api. */ -#include <cstddef> #include <cmath> #include <random> #include <vector> -#include <stdexcept> #include <utility> #include <cell.hpp> #include <util/debug.hpp> +#include "recipes.hpp" + namespace nest { namespace mc { -using cell_id_type = std::size_t; - -struct cell_count_info { - std::size_t num_sources; - std::size_t num_targets; - std::size_t num_probes; -}; +// TODO: split cell description into separate morphology, stimulus, probes, mechanisms etc. +// description for greater data reuse. -class invalid_recipe_error: public std::runtime_error { -public: - invalid_recipe_error(std::string whatstr): std::runtime_error(std::move(whatstr)) {} -}; +template <typename RNG> +mc::cell make_basic_cell(unsigned compartments_per_segment, unsigned num_synapses, const std::string& syn_type, RNG& rng) { + nest::mc::cell cell; -/* recipe descriptions are cell-oriented: in order that the building - * phase can be done distributedly and in order that the recipe - * description can be built indepdently of any runtime execution - * environment, connection end-points are represented by pairs - * (cell index, source/target index on cell). - */ - -struct cell_connection_endpoint { - cell_id_type cell; - unsigned endpoint_index; -}; - -struct cell_connection { - cell_connection_endpoint source; - cell_connection_endpoint dest; - - float weight; - float delay; -}; + // Soma with diameter 12.6157 um and HH channel + auto soma = cell.add_soma(12.6157/2.0); + soma->add_mechanism(mc::hh_parameters()); -class recipe { -public: - virtual cell_id_type num_cells() const =0; + // add dendrite of length 200 um and diameter 1 um with passive channel + std::vector<mc::cable_segment*> dendrites; + dendrites.push_back(cell.add_cable(0, mc::segmentKind::dendrite, 0.5, 0.5, 200)); + dendrites.push_back(cell.add_cable(1, mc::segmentKind::dendrite, 0.5, 0.25,100)); + dendrites.push_back(cell.add_cable(1, mc::segmentKind::dendrite, 0.5, 0.25,100)); - virtual cell get_cell(cell_id_type) const =0; - virtual cell_count_info get_cell_count_info(cell_id_type) const =0; - virtual std::vector<cell_connection> connections_on(cell_id_type) const =0; -}; + for (auto d : dendrites) { + d->add_mechanism(mc::pas_parameters()); + d->set_compartments(compartments_per_segment); + d->mechanism("membrane").set("r_L", 100); + } -// move miniapp's make_cell() into here, but use hashing rng or similar -// to get repeatable recipes -template <typename Rng> -cell make_basic_cell(int compartments_per_segment, int num_synapses, const std::string& syn_type, Rng &); + cell.add_detector({0,0}, 20); -struct probe_distribution { - float proportion = 1.f; // what proportion of cells should get probes? - bool all_segments = true; // false => soma only - bool membrane_voltage = true; - bool membrane_current = true; -}; + 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(syn_type); + for (unsigned i=0; i<num_synapses; ++i) { + cell.add_synapse({2+(i%2), distribution(rng)}, syn_default); + } -struct basic_recipe_param { - unsigned num_compartments = 1; - unsigned num_synapses = 1; - std::string synapse_type = "expsyn"; - float min_connection_delay_ms = 20.0; - float mean_connection_delay_ms = 20.75; - float syn_weight_per_cell = 0.3; -}; + return cell; +} class basic_cell_recipe: public recipe { public: - basic_cell_recipe(cell_id_type ncell, basic_recipe_param param, probe_distribution pdist): + basic_cell_recipe(cell_gid_type ncell, basic_recipe_param param, probe_distribution pdist): ncell_(ncell), param_(std::move(param)), pdist_(std::move(pdist)) { delay_distribution_param = exp_param{param_.mean_connection_delay_ms - param_.min_connection_delay_ms}; } - cell get_cell(cell_id_type i) const override { + cell_size_type num_cells() const { return ncell_; } + + cell get_cell(cell_gid_type i) const override { auto gen = std::mt19937(i); // replace this with hashing generator... auto cc = get_cell_count_info(i); @@ -109,8 +84,8 @@ public: EXPECTS(cell.detectors().size()==cc.num_sources); // add probes - int n_probe_segs = pdist_.all_segments? basic_cell_segments: 1; - for (int i = 0; i<n_probe_segs; ++i) { + 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); } @@ -122,8 +97,8 @@ public: return cell; } - cell_count_info get_cell_count_info(cell_id_type i) const override { - cell_count_info cc = {1, std::size_t(param_.num_synapses), 0 }; + cell_count_info get_cell_count_info(cell_gid_type i) const override { + cell_count_info cc = {1, param_.num_synapses, 0 }; // probe this cell? if (std::floor(i*pdist_.proportion)!=std::floor((i-1.0)*pdist_.proportion)) { @@ -139,15 +114,15 @@ public: } protected: - template <typename Rng> - cell_connection draw_connection_params(Rng& rng) const { + template <typename RNG> + cell_connection draw_connection_params(RNG& rng) const { std::exponential_distribution<float> delay_dist(delay_distribution_param); float delay = param_.min_connection_delay_ms + delay_dist(rng); float weight = param_.syn_weight_per_cell/param_.num_synapses; return cell_connection{{0, 0}, {0, 0}, weight, delay}; } - cell_id_type ncell_; + cell_gid_type ncell_; basic_recipe_param param_; probe_distribution pdist_; static constexpr int basic_cell_segments = 3; @@ -158,16 +133,16 @@ protected: class basic_ring_recipe: public basic_cell_recipe { public: - basic_ring_recipe(cell_id_type ncell, + basic_ring_recipe(cell_gid_type ncell, basic_recipe_param param, probe_distribution pdist = probe_distribution{}): basic_cell_recipe(ncell, std::move(param), std::move(pdist)) {} - std::vector<cell_connection> connections_on(cell_id_type i) const override { + std::vector<cell_connection> connections_on(cell_gid_type i) const override { std::vector<cell_connection> conns; auto gen = std::mt19937(i); // replace this with hashing generator... - cell_id_type prev = i==0? ncell_-1: i-1; + cell_gid_type prev = i==0? ncell_-1: i-1; for (unsigned t=0; t<param_.num_synapses; ++t) { cell_connection cc = draw_connection_params(gen); cc.source = {prev, 0}; @@ -179,20 +154,29 @@ public: } }; +std::unique_ptr<recipe> make_basic_ring_recipe( + cell_gid_type ncell, + basic_recipe_param param, + probe_distribution pdist) +{ + return std::unique_ptr<recipe>(new basic_ring_recipe(ncell, param, pdist)); +} + + class basic_rgraph_recipe: public basic_cell_recipe { public: - basic_rgraph_recipe(cell_id_type ncell, + basic_rgraph_recipe(cell_gid_type ncell, basic_recipe_param param, std::size_t cell_fan_in, probe_distribution pdist = probe_distribution{}): basic_cell_recipe(ncell, std::move(param), std::move(pdist)) {} - std::vector<cell_connection> connections_on(cell_id_type i) const override { + std::vector<cell_connection> connections_on(cell_gid_type i) const override { std::vector<cell_connection> conns; auto conn_param_gen = std::mt19937(i); // replace this with hashing generator... auto source_gen = std::mt19937(i*123+457); // ditto - std::uniform_int_distribution<cell_id_type> source_distribution(0, ncell_-2); + std::uniform_int_distribution<cell_gid_type> source_distribution(0, ncell_-2); for (unsigned t=0; t<param_.num_synapses; ++t) { auto source = source_distribution(source_gen); @@ -208,9 +192,18 @@ public: } }; +std::unique_ptr<recipe> make_basic_rgraph_recipe( + cell_gid_type ncell, + basic_recipe_param param, + cell_size_type cell_fan_in, + probe_distribution pdist) +{ + return std::unique_ptr<recipe>(new basic_rgraph_recipe(ncell, param, cell_fan_in, pdist)); +} + class basic_kgraph_recipe: public basic_cell_recipe { public: - basic_kgraph_recipe(cell_id_type ncell, + basic_kgraph_recipe(cell_gid_type ncell, basic_recipe_param param, probe_distribution pdist = probe_distribution{}): basic_cell_recipe(ncell, std::move(param), std::move(pdist)) @@ -221,12 +214,12 @@ public: } } - std::vector<cell_connection> connections_on(cell_id_type i) const override { + std::vector<cell_connection> connections_on(cell_gid_type i) const override { std::vector<cell_connection> conns; auto conn_param_gen = std::mt19937(i); // replace this with hashing generator... for (unsigned t=0; t<param_.num_synapses; ++t) { - cell_id_type source = t>=i? t+1: t; + cell_gid_type source = t>=i? t+1: t; EXPECTS(source<ncell_); cell_connection cc = draw_connection_params(conn_param_gen); @@ -239,5 +232,13 @@ public: } }; +std::unique_ptr<recipe> make_basic_kgraph_recipe( + cell_gid_type ncell, + basic_recipe_param param, + probe_distribution pdist) +{ + return std::unique_ptr<recipe>(new basic_kgraph_recipe(ncell, param, pdist)); +} + } // namespace mc } // namespace nest diff --git a/miniapp/recipes.hpp b/miniapp/recipes.hpp index 623b786a035bca2c515dd6b7b111bcc6bade6f1f..75505e843db38ea3adbd7e1524af6d00b6675c5e 100644 --- a/miniapp/recipes.hpp +++ b/miniapp/recipes.hpp @@ -7,9 +7,6 @@ namespace nest { namespace mc { -using cell_id_type = std::size_t; -using cell_size_type = std::size_t; - struct cell_count_info { cell_size_type num_sources; cell_size_type num_targets; @@ -28,10 +25,7 @@ public: * (cell index, source/target index on cell). */ -struct cell_connection_endpoint { - cell_id_type cell; - unsigned endpoint_index; -}; +using cell_connection_endpoint = cell_member_type; struct cell_connection { cell_connection_endpoint source; @@ -43,11 +37,11 @@ struct cell_connection { class recipe { public: - virtual cell_id_type num_cells() const =0; + virtual cell_size_type num_cells() const =0; - virtual cell get_cell(cell_id_type) const =0; - virtual cell_count_info get_cell_count_info(cell_id_type) const =0; - virtual std::vector<cell_connection> connections_on(cell_id_type) const =0; + virtual cell get_cell(cell_gid_type) const =0; + virtual cell_count_info get_cell_count_info(cell_gid_type) const =0; + virtual std::vector<cell_connection> connections_on(cell_gid_type) const =0; }; // miniapp-specific recipes @@ -69,19 +63,19 @@ struct basic_recipe_param { }; std::unique_ptr<recipe> make_basic_ring_recipe( - cell_id_type ncell, + cell_gid_type ncell, basic_recipe_param param, probe_distribution pdist = probe_distribution{}); std::unique_ptr<recipe> make_basic_kgraph_recipe( - cell_id_type ncell, + cell_gid_type ncell, basic_recipe_param param, probe_distribution pdist = probe_distribution{}); std::unique_ptr<recipe> make_basic_rgraph_recipe( - cell_id_type ncell, + cell_gid_type ncell, basic_recipe_param param, - cell_count_type cell_fan_in, + cell_size_type cell_fan_in, probe_distribution pdist = probe_distribution{}); } // namespace mc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7f4a588d933a5ea74342c70dc8b6ac5df95aca8b..a1d9165602b09ca7b23219fc38dbbfff51de5076 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,7 +3,6 @@ set(HEADERS ) set(BASE_SOURCES cell.cpp - mechanism_interface.cpp parameter_list.cpp profiling/profiler.cpp swcio.cpp diff --git a/src/algorithms.hpp b/src/algorithms.hpp index e89f06f539f51b37f7ce95ca8ff2de18b3709d62..60fd0863e8770586764fb6129dee5f1699f57298 100644 --- a/src/algorithms.hpp +++ b/src/algorithms.hpp @@ -90,12 +90,12 @@ bool is_minimal_degree(C const& c) "is_minimal_degree only applies to integral types" ); - if(c.size()==0u) { + if (c.size()==0u) { return true; } using value_type = typename C::value_type; - if(c[0] != value_type(0)) { + if (c[0] != value_type(0)) { return false; } auto i = value_type(1); diff --git a/src/catypes.hpp b/src/catypes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2ae26ceb66946c834cbde399a4b5219a1fe05586 --- /dev/null +++ b/src/catypes.hpp @@ -0,0 +1,47 @@ +#pragma once + +/* + * Common definitions for index types etc. across prototype simulator + * library. (Expect analogues in future versions to be template parameters?) + */ + +#include <type_traits> + +#include <util/lexcmp_def.hpp> + +namespace nest { +namespace mc { + +// for identifying cells globally +using cell_gid_type = std::uint32_t; + +// for sizes of collections of cells +using cell_size_type = typename std::make_unsigned<cell_gid_type>::type; + +// for indexes into cell-local data +using cell_local_index_type = std::uint32_t; + +// for counts of cell-local data +using cell_local_size_type = typename std::make_unsigned<cell_local_index_type>::type; + +struct cell_member_type { + cell_gid_type gid; + cell_local_index_type index; +}; + +DEFINE_LEXICOGRAPHIC_ORDERING(cell_member_type,(a.gid,a.index),(b.gid,b.index)) + +// good idea? bad idea? +using packed_cell_member_type = std::uint64_t; + +inline packed_cell_member_type pack_cell_member(cell_member_type m) { + return ((packed_cell_member_type)m.gid<<32u) + m.index; +} + +inline cell_member_type unpack_cell_member(packed_cell_member_type p) { + return {(cell_gid_type)(p>>32u), (cell_local_index_type)(p&((1ull<<32)-1))}; +} + + +} // namespace mc +} // namespace nest diff --git a/src/cell.cpp b/src/cell.cpp index 01d681a7e080c8c0444fe0299820181d5154028e..73e1960b421394336161db7671ec41ff51d18b66 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -26,7 +26,7 @@ cell::cell() parents_.push_back(0); } -int cell::num_segments() const +cell::size_type cell::num_segments() const { return segments_.size(); } @@ -75,7 +75,7 @@ cable_segment* cell::add_cable(cell::index_type parent, segment_ptr&& cable) return segments_.back()->as_cable(); } -segment* cell::segment(int index) +segment* cell::segment(index_type index) { if(index<0 || index>=num_segments()) { throw std::out_of_range( @@ -85,7 +85,7 @@ segment* cell::segment(int index) return segments_[index].get(); } -segment const* cell::segment(int index) const +segment const* cell::segment(index_type index) const { if(index<0 || index>=num_segments()) { throw std::out_of_range( @@ -109,7 +109,7 @@ soma_segment* cell::soma() return nullptr; } -cable_segment* cell::cable(int index) +cable_segment* cell::cable(index_type index) { if(index>0 && index<num_segments()) { return segment(index)->as_cable(); @@ -146,9 +146,9 @@ std::vector<segment_ptr> const& cell::segments() const return segments_; } -std::vector<int> cell::compartment_counts() const +std::vector<cell::size_type> cell::compartment_counts() const { - std::vector<int> comp_count; + std::vector<size_type> comp_count; comp_count.reserve(num_segments()); for(auto const& s : segments()) { comp_count.push_back(s->num_compartments()); @@ -156,7 +156,7 @@ std::vector<int> cell::compartment_counts() const return comp_count; } -size_t cell::num_compartments() const +cell::size_type cell::num_compartments() const { auto n = 0u; for(auto &s : segments_) { @@ -196,7 +196,7 @@ void cell::add_detector(segment_location loc, double threshold) spike_detectors_.push_back({loc, threshold}); } -std::vector<int> const& cell::segment_parents() const +std::vector<cell::index_type> const& cell::segment_parents() const { return parents_; } @@ -212,24 +212,22 @@ std::vector<int> const& cell::segment_parents() const // - number of compartments in each segment bool cell_basic_equality(cell const& lhs, cell const& rhs) { - if(lhs.num_segments() != rhs.num_segments()) { + if (lhs.num_segments() != rhs.num_segments()) { return false; } - if(lhs.segment_parents() != rhs.segment_parents()) { + if (lhs.segment_parents() != rhs.segment_parents()) { return false; } - for(auto i=0; i<lhs.num_segments(); ++i) { + for (cell::index_type i=0; i<lhs.num_segments(); ++i) { // a quick and dirty test auto& l = *lhs.segment(i); auto& r = *rhs.segment(i); - if(l.kind() != r.kind()) return false; - if(l.area() != r.area()) return false; - if(l.volume() != r.volume()) return false; - if(l.as_cable()) { - if( l.as_cable()->num_compartments() - != r.as_cable()->num_compartments()) - { + if (l.kind() != r.kind()) return false; + if (l.area() != r.area()) return false; + if (l.volume() != r.volume()) return false; + if (l.as_cable()) { + if (l.as_cable()->num_compartments() != r.as_cable()->num_compartments()) { return false; } } diff --git a/src/cell.hpp b/src/cell.hpp index 1cb9b9f65dedbdcc4476c2b447eed1d1dea243ca..137ea339eaaeef83a2a3b26206c98a017e87a181 100644 --- a/src/cell.hpp +++ b/src/cell.hpp @@ -5,8 +5,9 @@ #include <thread> #include <vector> -#include "segment.hpp" +#include "catypes.hpp" #include "cell_tree.hpp" +#include "segment.hpp" #include "stimulus.hpp" #include "util/debug.hpp" @@ -17,12 +18,12 @@ namespace mc { /// description struct compartment_model { cell_tree tree; - std::vector<int> parent_index; - std::vector<int> segment_index; + std::vector<cell_tree::int_type> parent_index; + std::vector<cell_tree::int_type> segment_index; }; struct segment_location { - segment_location(int s, double l) + segment_location(cell_local_index_type s, double l) : segment(s), position(l) { EXPECTS(position>=0. && position<=1.); @@ -30,7 +31,7 @@ struct segment_location { friend bool operator==(segment_location l, segment_location r) { return l.segment==r.segment && l.position==r.position; } - int segment; + cell_local_index_type segment; double position; }; @@ -49,10 +50,11 @@ class cell { public: // types - using index_type = int; + using index_type = cell_local_index_type; + using size_type = cell_local_size_type; using value_type = double; using point_type = point<value_type>; - + struct synapse_instance { segment_location location; parameter_list mechanism; @@ -89,12 +91,12 @@ public: cable_segment* add_cable(index_type parent, Args ...args); /// the number of segments in the cell - int num_segments() const; + size_type num_segments() const; bool has_soma() const; - class segment* segment(int index); - class segment const* segment(int index) const; + class segment* segment(index_type index); + class segment const* segment(index_type index) const; /// access pointer to the soma /// returns nullptr if the cell has no soma @@ -103,7 +105,7 @@ public: /// access pointer to a cable segment /// will throw an std::out_of_range exception if /// the cable index is not valid - cable_segment* cable(int index); + cable_segment* cable(index_type index); /// the volume of the cell value_type volume() const; @@ -112,16 +114,16 @@ public: value_type area() const; /// the total number of compartments over all segments - size_t num_compartments() const; + size_type num_compartments() const; std::vector<segment_ptr> const& segments() const; /// return reference to array that enumerates the index of the parent of /// each segment - std::vector<int> const& segment_parents() const; + std::vector<index_type> const& segment_parents() const; /// return a vector with the compartment count for each segment in the cell - std::vector<int> compartment_counts() const; + std::vector<size_type> compartment_counts() const; compartment_model model() const; diff --git a/src/cell_group.hpp b/src/cell_group.hpp index ff146bd1110eb873d5d83c35969b981a48579b5f..fdefa72c5833c43901854ce7081623a754304bd8 100644 --- a/src/cell_group.hpp +++ b/src/cell_group.hpp @@ -5,8 +5,8 @@ #include <cell.hpp> #include <event_queue.hpp> -#include <communication/spike.hpp> -#include <communication/spike_source.hpp> +#include <spike.hpp> +#include <spike_source.hpp> #include <profiling/profiler.hpp> @@ -17,11 +17,10 @@ namespace mc { // for the next desired sample. struct sampler { - using index_type = int; using time_type = float; using value_type = double; - index_type probe_gid; // samplers are attached to probes + cell_member_type probe_id; // samplers are attached to probes std::function<util::optional<time_type>(time_type, value_type)> sample; }; @@ -86,7 +85,7 @@ public: auto& sampler = samplers_[m->sampler_index]; EXPECTS((bool)sampler.sample); - index_type probe_index = sampler.probe_gid-first_probe_gid_; + index_type probe_index = sampler.probe_id.index; auto next = sampler.sample(cell_.time(), cell_.probe(probe_index)); if (next) { m->time = std::max(*next, cell_time); @@ -137,7 +136,7 @@ public: } } - const std::vector<communication::spike<index_type>>& + const std::vector<spike<index_type>>& spikes() const { return spikes_; } @@ -170,7 +169,7 @@ private: std::vector<spike_source_type> spike_sources_; //. spikes that are generated - std::vector<communication::spike<index_type>> spikes_; + std::vector<spike<index_type>> spikes_; /// pending events to be delivered event_queue<postsynaptic_spike_event> events_; diff --git a/src/cell_tree.hpp b/src/cell_tree.hpp index 4d9f70b1a934ab3b5bdb840d6bb0bd1b8419dfec..4a5ccf57379b54129f5f0310a74854ecbf025b60 100644 --- a/src/cell_tree.hpp +++ b/src/cell_tree.hpp @@ -10,6 +10,8 @@ #include <vector> #include <vector/include/Vector.hpp> + +#include "catypes.hpp" #include "tree.hpp" #include "util.hpp" @@ -29,38 +31,42 @@ namespace mc { /// flexibility in choosing the root. class cell_tree { using range = memory::Range; -public : - // use a signed 16-bit integer for storage of indexes, which is reasonable given - // that typical cells have at most 1000-2000 segments - using int_type = int; + +public: + using int_type = cell_local_index_type; + using size_type = cell_local_size_type; + using index_type = memory::HostVector<int_type>; using view_type = index_type::view_type; using const_view_type = index_type::const_view_type; + using tree = nest::mc::tree<int_type, size_type>; + static constexpr int_type no_parent = tree::no_parent; + /// default empty constructor cell_tree() = default; /// construct from a parent index - cell_tree(std::vector<int> const& parent_index) + cell_tree(std::vector<int_type> const& parent_index) { // handle the case of an empty parent list, which implies a single-compartment model if(parent_index.size()>0) { tree_ = tree(parent_index); } else { - tree_ = tree(std::vector<int>({0})); + tree_ = tree(std::vector<int_type>({0})); } } /// construct from a tree // copy constructor - cell_tree(tree const& t, int s) + cell_tree(tree const& t, int_type s) : tree_(t), soma_(s) { } // move constructor - cell_tree(tree&& t, int s) + cell_tree(tree&& t, int_type s) : tree_(std::move(t)), soma_(s) { } @@ -129,12 +135,12 @@ public : } /// returns the number of child segments of segment b - size_t num_children(size_t b) const { + size_type num_children(int_type b) const { return tree_.num_children(b); } /// returns a list of the children of segment b - const_view_type children(size_t b) const { + const_view_type children(int_type b) const { return tree_.children(b); } @@ -162,7 +168,7 @@ public : index_type depth_from_leaf() { tree::index_type depth(num_segments()); - depth_from_leaf(depth, 0); + depth_from_leaf(depth, int_type{0}); return depth; } @@ -170,7 +176,7 @@ public : { tree::index_type depth(num_segments()); depth[0] = 0; - depth_from_root(depth, 1); + depth_from_root(depth, int_type{1}); return depth; } @@ -179,12 +185,11 @@ private : /// helper type for sub-tree computation /// use in balance() struct sub_tree { - sub_tree(int r, int diam, int dpth) - : root(r), diameter(diam), depth(dpth) + sub_tree(int_type r, int_type diam, int_type dpth): + root(r), diameter(diam), depth(dpth) {} - void set(int r, int diam, int dpth) - { + void set(int r, int diam, int dpth) { root = r; diameter = diam; depth = dpth; @@ -198,15 +203,15 @@ private : "]"; } - int root; - int diameter; - int depth; + int_type root; + int_type diameter; + int_type depth; }; /// returns the index of the segment that would minimise the depth of the /// tree if used as the root segment int_type find_minimum_root() { - if(num_segments()==1) { + if (num_segments()==1) { return 0; } @@ -229,14 +234,14 @@ private : // walk has been completed to the root node, the node that has been // selected will be the root of the sub-tree with the largest diameter. sub_tree max_sub_tree(0, 0, 0); - auto distance_from_max_leaf = 1; + int_type distance_from_max_leaf = 1; auto pnt = max_leaf; auto pos = parent(max_leaf); - while(pos != -1) { + while(pos != no_parent) { for(auto c : children(pos)) { if(c!=pnt) { auto diameter = depth[c] + 1 + distance_from_max_leaf; - if(diameter>max_sub_tree.diameter) { + if (diameter>max_sub_tree.diameter) { max_sub_tree.set(pos, diameter, distance_from_max_leaf); } } @@ -266,7 +271,7 @@ private : return new_root; } - int_type depth_from_leaf(index_type& depth, int segment) + int_type depth_from_leaf(index_type& depth, int_type segment) { int_type max_depth = 0; for(auto c : children(segment)) { @@ -276,7 +281,7 @@ private : return max_depth+1; } - void depth_from_root(index_type& depth, int segment) + void depth_from_root(index_type& depth, int_type segment) { auto d = depth[parent(segment)] + 1; depth[segment] = d; diff --git a/src/communication/communicator.hpp b/src/communication/communicator.hpp index 34185ac0fbd795294211ced7190d8b84a3e70874..01cdb7ff6b93396650efecdc7d1de05ca666a93c 100644 --- a/src/communication/communicator.hpp +++ b/src/communication/communicator.hpp @@ -5,7 +5,7 @@ #include <vector> #include <random> -#include <communication/spike.hpp> +#include <spike.hpp> #include <threading/threading.hpp> #include <algorithms.hpp> #include <event_queue.hpp> diff --git a/src/communication/mpi_global_policy.hpp b/src/communication/mpi_global_policy.hpp index 7409585447ae888eec2aa47ddc1fa0f137df7d6e..3d7eb60f8b7ea8062efd3ac3ad61743584d9bf7f 100644 --- a/src/communication/mpi_global_policy.hpp +++ b/src/communication/mpi_global_policy.hpp @@ -4,14 +4,13 @@ #error "mpi_global_policy.hpp should only be compiled in a WITH_MPI build" #endif +#include <cstdint> #include <type_traits> #include <vector> -#include <cstdint> - -#include <communication/spike.hpp> -#include <communication/mpi.hpp> #include <algorithms.hpp> +#include <communication/mpi.hpp> +#include <spike.hpp> namespace nest { namespace mc { diff --git a/src/communication/serial_global_policy.hpp b/src/communication/serial_global_policy.hpp index a1c7fee9671cb79768e255a710e0082386302e8a..82be592e066b08bb5bab2e022d249f9a650c110c 100644 --- a/src/communication/serial_global_policy.hpp +++ b/src/communication/serial_global_policy.hpp @@ -1,11 +1,10 @@ #pragma once +#include <cstdint> #include <type_traits> #include <vector> -#include <cstdint> - -#include <communication/spike.hpp> +#include <spike.hpp> namespace nest { namespace mc { diff --git a/src/compartment.hpp b/src/compartment.hpp index b92360a560ba5de30a036505d50d457b7b5a5a9c..c69f622f16ece3638e32d8b95155fa1c31f33a65 100644 --- a/src/compartment.hpp +++ b/src/compartment.hpp @@ -3,6 +3,8 @@ #include <iterator> #include <utility> +#include "catypes.hpp" + namespace nest { namespace mc { @@ -10,7 +12,7 @@ namespace mc { /// The compartment is a conic frustrum struct compartment { using value_type = double; - using size_type = int; + using size_type = cell_local_size_type; using value_pair = std::pair<value_type, value_type>; compartment() = delete; @@ -103,8 +105,7 @@ class compartment_iterator : }; class compartment_range { - public: - +public: using size_type = compartment_iterator::size_type; using real_type = compartment_iterator::real_type; diff --git a/src/communication/connection.hpp b/src/connection.hpp similarity index 84% rename from src/communication/connection.hpp rename to src/connection.hpp index ee1acfd72dc21cffe01f28239bca29526366df31..1c0df44e1b266c67b1f6cef99b1fbdf23bae9862 100644 --- a/src/communication/connection.hpp +++ b/src/connection.hpp @@ -2,16 +2,20 @@ #include <cstdint> +#include <catypes.hpp> #include <event_queue.hpp> -#include <communication/spike.hpp> +#include <spike.hpp> namespace nest { namespace mc { -namespace communication { + +using connection_end_type = packed_cell_member_type; class connection { public: - using id_type = uint32_t; + //using id_type = cell_member_type; + using id_type = std::uint32_t; + connection(id_type src, id_type dest, float w, float d) : source_(src), destination_(dest), @@ -55,12 +59,11 @@ bool operator< (connection::id_type lhs, connection rhs) { return lhs < rhs.source(); } -} // namespace communication } // namespace mc } // namespace nest static inline -std::ostream& operator<<(std::ostream& o, nest::mc::communication::connection const& con) { +std::ostream& operator<<(std::ostream& o, nest::mc::connection const& con) { char buff[512]; snprintf( buff, sizeof(buff), "con [%10u -> %10u : weight %8.4f, delay %8.4f]", diff --git a/src/event_queue.hpp b/src/event_queue.hpp index 7f3034f3f08bbb2235bf457c95e8eedfe8d0895d..c41d96a05fdc58320cb6cde8b8b838785cb214be 100644 --- a/src/event_queue.hpp +++ b/src/event_queue.hpp @@ -4,13 +4,15 @@ #include <ostream> #include <queue> +#include "catypes.hpp" #include "util/optional.hpp" namespace nest { namespace mc { struct postsynaptic_spike_event { - uint32_t target; + //cell_member_type target; + std::uint32_t target; float time; float weight; }; @@ -18,7 +20,7 @@ struct postsynaptic_spike_event { inline float event_time(const postsynaptic_spike_event &ev) { return ev.time; } struct sample_event { - uint32_t sampler_index; + std::uint32_t sampler_index; float time; }; @@ -26,7 +28,7 @@ inline float event_time(const sample_event &ev) { return ev.time; } /* Event objects must have a method event_time() which returns a value * from a type with a total ordering with respect to <, >, etc. - */ + */ template <typename Event> class event_queue { diff --git a/src/fvm_cell.hpp b/src/fvm_cell.hpp index 2fa86fd9d6326b3ffc1692f7c08c0fde00edf163..90a76fc55c7985be8d021b40d4a566b661c64ede 100644 --- a/src/fvm_cell.hpp +++ b/src/fvm_cell.hpp @@ -13,7 +13,7 @@ #include <math.hpp> #include <matrix.hpp> #include <mechanism.hpp> -#include <mechanism_interface.hpp> +#include <mechanism_catalogue.hpp> #include <segment.hpp> #include <stimulus.hpp> #include <util.hpp> @@ -194,6 +194,9 @@ private: std::vector<std::pair<uint32_t, i_clamp>> stimulii_; std::vector<std::pair<const vector_type fvm_cell::*, uint32_t>> probes_; + + // mechanism factory + using mechanism_catalogue = nest::mc::mechanisms::catalogue<T, I>; }; //////////////////////////////////////////////////////////////////////////////// @@ -291,10 +294,10 @@ fvm_cell<T, I>::fvm_cell(nest::mc::cell const& cell) // for each mechanism in the cell record the indexes of the segments that // contain the mechanism - std::map<std::string, std::vector<int>> mech_map; + std::map<std::string, std::vector<unsigned>> mech_map; - for(auto i=0; i<cell.num_segments(); ++i) { - for(const auto& mech : cell.segment(i)->mechanisms()) { + for (unsigned i=0; i<cell.num_segments(); ++i) { + for (const auto& mech : cell.segment(i)->mechanisms()) { // FIXME : Membrane has to be a proper mechanism, // because it is exposed via the public interface. // This if statement is bad @@ -308,12 +311,12 @@ fvm_cell<T, I>::fvm_cell(nest::mc::cell const& cell) // instance. // TODO : this works well for density mechanisms (e.g. ion channels), but // does it work for point processes (e.g. synapses)? - for(auto& mech : mech_map) { - auto& helper = nest::mc::mechanisms::get_mechanism_helper(mech.first); + for (auto& mech : mech_map) { + //auto& helper = nest::mc::mechanisms::get_mechanism_helper(mech.first); // calculate the number of compartments that contain the mechanism auto num_comp = 0u; - for(auto seg : mech.second) { + for (auto seg : mech.second) { num_comp += segment_index_[seg+1] - segment_index_[seg]; } @@ -321,7 +324,7 @@ fvm_cell<T, I>::fvm_cell(nest::mc::cell const& cell) // the mechanism index_type compartment_index(num_comp); auto pos = 0u; - for(auto seg : mech.second) { + for (auto seg : mech.second) { auto seg_size = segment_index_[seg+1] - segment_index_[seg]; std::iota( compartment_index.data() + pos, @@ -333,24 +336,24 @@ fvm_cell<T, I>::fvm_cell(nest::mc::cell const& cell) // instantiate the mechanism mechanisms_.push_back( - helper->new_mechanism(voltage_, current_, compartment_index) + mechanism_catalogue::make(mech.first, voltage_, current_, compartment_index) + //helper->new_mechanism(voltage_, current_, compartment_index) ); } synapse_index_ = mechanisms_.size(); - std::map<std::string, std::vector<int>> syn_map; + std::map<std::string, std::vector<cell_local_index_type>> syn_map; for (const auto& syn : cell.synapses()) { syn_map[syn.mechanism.name()].push_back(find_compartment_index(syn.location, graph)); } for (const auto &syni : syn_map) { const auto& mech_name = syni.first; - auto& helper = nest::mc::mechanisms::get_mechanism_helper(mech_name); + // auto& helper = nest::mc::mechanisms::get_mechanism_helper(mech_name); index_type compartment_index(syni.second); - - auto mech = helper->new_mechanism(voltage_, current_, compartment_index); + auto mech = mechanism_catalogue::make(mech_name, voltage_, current_, compartment_index); mech->set_areas(cv_areas_); mechanisms_.push_back(std::move(mech)); } @@ -370,7 +373,7 @@ fvm_cell<T, I>::fvm_cell(nest::mc::cell const& cell) } } } - std::vector<int> indexes(index_set.begin(), index_set.end()); + std::vector<cell_local_index_type> indexes(index_set.begin(), index_set.end()); // create the ion state if(indexes.size()) { diff --git a/src/matrix.hpp b/src/matrix.hpp index d0ddb816adc5cb9bfb6c3c88562e0a41835920ec..79b7218bc97fa0b16469ac50dbb5a91dc58c0db6 100644 --- a/src/matrix.hpp +++ b/src/matrix.hpp @@ -164,7 +164,7 @@ class matrix { auto const ncells = num_cells(); // loop over submatrices - for(auto m=0; m<ncells; ++m) { + for (size_type m=0; m<ncells; ++m) { auto first = cell_index_[m]; auto last = cell_index_[m+1]; diff --git a/src/mechanism_catalogue.hpp b/src/mechanism_catalogue.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ef0b4ed8db8134456871bcb84eb9e134cfd26992 --- /dev/null +++ b/src/mechanism_catalogue.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include <map> +#include <stdexcept> +#include <string> + +#include <mechanism.hpp> +#include <mechanisms/hh.hpp> +#include <mechanisms/pas.hpp> +#include <mechanisms/expsyn.hpp> +#include <mechanisms/exp2syn.hpp> + +namespace nest { +namespace mc { +namespace mechanisms { + +template <typename T, typename I> +struct catalogue { + using view_type = typename mechanism<T, I>::view_type; + using index_view = typename mechanism<T, I>::index_view; + + static mechanism_ptr<T, I> make(const std::string &name, view_type vec_v, view_type vec_i, index_view node_indices) { + auto entry = mech_map.find(name); + if (entry==mech_map.end()) { + throw std::out_of_range("no such mechanism"); + } + + return entry->second(vec_v, vec_i, node_indices); + } + + static bool has(const std::string &name) { + return mech_map.count(name)>0; + } + +private: + using maker_type = mechanism_ptr<T, I> (*)(view_type, view_type, index_view); + static const std::map<std::string, maker_type> mech_map; + + template <template <typename, typename> class mech> + static mechanism_ptr<T, I> maker(view_type vec_v, view_type vec_i, index_view node_indices) { + return make_mechanism<mech<T, I>>(vec_v, vec_i, node_indices); + } +}; + +template <typename T, typename I> +const std::map<std::string, typename catalogue<T, I>::maker_type> catalogue<T, I>::mech_map = { + { "pas", maker<pas::mechanism_pas> }, + { "hh", maker<hh::mechanism_hh> }, + { "expsyn", maker<expsyn::mechanism_expsyn> }, + { "exp2syn", maker<exp2syn::mechanism_exp2syn> } +}; + + +} // namespace mechanisms +} // namespace mc +} // namespace nest diff --git a/src/mechanism_interface.cpp b/src/mechanism_interface.cpp deleted file mode 100644 index 680e8739d11ee0dad16890bb1088a1a7d4b774b5..0000000000000000000000000000000000000000 --- a/src/mechanism_interface.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "mechanism_interface.hpp" - -// -// include the mechanisms -// - -#include <mechanisms/hh.hpp> -#include <mechanisms/pas.hpp> -#include <mechanisms/expsyn.hpp> -#include <mechanisms/exp2syn.hpp> - - -namespace nest { -namespace mc { -namespace mechanisms { - -std::map<std::string, mechanism_helper_ptr<value_type, index_type>> mechanism_helpers; - -void setup_mechanism_helpers() { - mechanism_helpers["pas"] = - make_mechanism_helper< - mechanisms::pas::helper<value_type, index_type> - >(); - - mechanism_helpers["hh"] = - 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>& -get_mechanism_helper(const std::string& name) -{ - auto helper = mechanism_helpers.find(name); - if(helper==mechanism_helpers.end()) { - throw std::out_of_range( - nest::mc::util::pprintf("there is no mechanism named \'%\'", name) - ); - } - - return helper->second; -} - -} // namespace mechanisms -} // namespace nest -} // namespace mc - diff --git a/src/mechanism_interface.hpp b/src/mechanism_interface.hpp index c59caaad6c655d6a69c5206b956b1cb42959cfdf..5e5360e6602761ae2923c6c2afec958279235dca 100644 --- a/src/mechanism_interface.hpp +++ b/src/mechanism_interface.hpp @@ -1,7 +1,6 @@ #pragma once -#include <map> -#include <string> +// just for compatibility with current version of modparser... #include "mechanism.hpp" #include "parameter_list.hpp" @@ -10,11 +9,6 @@ namespace nest { namespace mc { namespace mechanisms { -using value_type = double; -using index_type = int; - -/// helper type for building mechanisms -/// the use of abstract base classes everywhere is a bit ugly template <typename T, typename I> struct mechanism_helper { using value_type = T; @@ -25,34 +19,10 @@ struct mechanism_helper { using view_type = typename mechanism<T,I>::view_type; virtual std::string name() const = 0; - virtual mechanism_ptr<T,I> new_mechanism(view_type, view_type, index_view) const = 0; - virtual void set_parameters(mechanism_ptr_type&, parameter_list const&) const = 0; }; -template <typename T, typename I> -using mechanism_helper_ptr = - std::unique_ptr<mechanism_helper<T,I>>; - -template <typename M> -mechanism_helper_ptr<typename M::value_type, typename M::size_type> -make_mechanism_helper() -{ - return util::make_unique<M>(); -} - -// for now use a global variable for the map of mechanism helpers -extern std::map< - std::string, - mechanism_helper_ptr<value_type, index_type> -> mechanism_helpers; - -void setup_mechanism_helpers(); - -mechanism_helper_ptr<value_type, index_type>& -get_mechanism_helper(const std::string& name); - } // namespace mechanisms } // namespace mc } // namespace nest diff --git a/src/segment.hpp b/src/segment.hpp index c6c49b26a946d36fdc969d9473fa07105d30d4af..b53d21be5b160cff9ab36d8886d8ea9422238dc6 100644 --- a/src/segment.hpp +++ b/src/segment.hpp @@ -4,6 +4,7 @@ #include <vector> #include "algorithms.hpp" +#include "catypes.hpp" #include "compartment.hpp" #include "math.hpp" #include "parameter_list.hpp" @@ -36,6 +37,7 @@ class segment { public: using value_type = double; + using size_type = cell_local_size_type; using point_type = point<value_type>; segmentKind kind() const { @@ -57,8 +59,8 @@ class segment { return kind_==segmentKind::axon; } - virtual int num_compartments() const = 0; - virtual void set_compartments(int) = 0; + virtual size_type num_compartments() const = 0; + virtual void set_compartments(size_type) = 0; virtual value_type volume() const = 0; virtual value_type area() const = 0; @@ -153,13 +155,12 @@ class segment { std::vector<parameter_list> mechanisms_; }; -class placeholder_segment : public segment -{ - public: - +class placeholder_segment : public segment { +public: using base = segment; using base::kind_; using base::value_type; + using base::size_type; placeholder_segment() { @@ -181,23 +182,22 @@ class placeholder_segment : public segment return true; } - int num_compartments() const override + size_type num_compartments() const override { return 0; } - virtual void set_compartments(int) override + virtual void set_compartments(size_type) override { } }; -class soma_segment : public segment -{ - public : - +class soma_segment : public segment { +public: using base = segment; using base::kind_; using base::value_type; using base::point_type; + using base::size_type; soma_segment() = delete; @@ -245,12 +245,12 @@ class soma_segment : public segment } /// soma has one and one only compartments - int num_compartments() const override + size_type num_compartments() const override { return 1; } - void set_compartments(int n) override + void set_compartments(size_type n) override { } private : @@ -261,10 +261,8 @@ class soma_segment : public segment point_type center_; }; -class cable_segment : public segment -{ - public : - +class cable_segment : public segment { +public: using base = segment; using base::kind_; using base::value_type; @@ -332,7 +330,7 @@ class cable_segment : public segment value_type volume() const override { auto sum = value_type{0}; - for(auto i=0; i<num_sub_segments(); ++i) { + for (auto i=0u; i<num_sub_segments(); ++i) { sum += math::volume_frustrum(lengths_[i], radii_[i], radii_[i+1]); } return sum; @@ -341,7 +339,7 @@ class cable_segment : public segment value_type area() const override { auto sum = value_type{0}; - for(auto i=0; i<num_sub_segments(); ++i) { + for (auto i=0u; i<num_sub_segments(); ++i) { sum += math::area_frustrum(lengths_[i], radii_[i], radii_[i+1]); } return sum; @@ -358,7 +356,7 @@ class cable_segment : public segment } // the number sub-segments that define the cable segment - int num_sub_segments() const + size_type num_sub_segments() const { return radii_.size()-1; } @@ -378,12 +376,12 @@ class cable_segment : public segment return this; } - int num_compartments() const override + size_type num_compartments() const override { return num_compartments_; } - void set_compartments(int n) override + void set_compartments(size_type n) override { if(n<1) { throw std::out_of_range( @@ -406,8 +404,8 @@ class cable_segment : public segment // we find ourselves having to do it over and over again. // The time to cache it might be when update_lengths() is called. auto sum = value_type(0); - auto i=0; - for(i=0; i<num_sub_segments(); ++i) { + size_type i = 0; + for (i = 0; i<num_sub_segments(); ++i) { if(sum+lengths_[i]>pos) { break; } @@ -425,19 +423,18 @@ class cable_segment : public segment return {num_compartments(), radii_.front(), radii_.back(), length()}; } - private : - +private: void update_lengths() { - if(locations_.size()) { + if (locations_.size()) { lengths_.resize(num_sub_segments()); - for(auto i=0; i<num_sub_segments(); ++i) { + for (size_type i=0; i<num_sub_segments(); ++i) { lengths_[i] = norm(locations_[i] - locations_[i+1]); } } } - int num_compartments_ = 1; + size_type num_compartments_ = 1; std::vector<value_type> lengths_; std::vector<value_type> radii_; std::vector<point_type> locations_; diff --git a/src/communication/spike.hpp b/src/spike.hpp similarity index 75% rename from src/communication/spike.hpp rename to src/spike.hpp index 03b5ed75def7a2fb68bd491ae7f1208d4b230b8a..b0b5a9bbb973408ee7300c2b6d169537d6c9987e 100644 --- a/src/communication/spike.hpp +++ b/src/spike.hpp @@ -1,11 +1,10 @@ #pragma once -#include <type_traits> #include <ostream> +#include <type_traits> namespace nest { namespace mc { -namespace communication { template < typename I, @@ -25,24 +24,17 @@ struct spike { } // namespace mc } // namespace nest -} // namespace communication /// custom stream operator for printing nest::mc::spike<> values template <typename I> -std::ostream& operator<<( - std::ostream& o, - nest::mc::communication::spike<I> s) -{ +std::ostream& operator<<(std::ostream& o, nest::mc::spike<I> s) { return o << "spike[t " << s.time << ", src " << s.source << "]"; } /// less than comparison operator for nest::mc::spike<> values /// spikes are ordered by spike time, for use in sorting and queueing template <typename I> -bool operator<( - nest::mc::communication::spike<I> lhs, - nest::mc::communication::spike<I> rhs) -{ +bool operator<(nest::mc::spike<I> lhs, nest::mc::spike<I> rhs) { return lhs.time < rhs.time; } diff --git a/src/communication/spike_source.hpp b/src/spike_source.hpp similarity index 100% rename from src/communication/spike_source.hpp rename to src/spike_source.hpp diff --git a/src/tree.hpp b/src/tree.hpp index 98ff9aa43656f9d68b879297a6ffd5399348b6f0..6d5eeae78acd2e6646d86edbfa657b197ca95927 100644 --- a/src/tree.hpp +++ b/src/tree.hpp @@ -1,4 +1,4 @@ -#pragma once + #pragma once #include <algorithm> #include <cassert> @@ -12,16 +12,18 @@ namespace nest { namespace mc { +template <typename IntT, typename SizeT = std::size_t> class tree { using range = memory::Range; - public : - - using int_type = int; +public: + using int_type = IntT; + using size_type = SizeT; using index_type = memory::HostVector<int_type>; - using view_type = index_type::view_type; - using const_view_type = index_type::const_view_type; + using view_type = typename index_type::view_type; + using const_view_type = typename index_type::const_view_type; + static constexpr int_type no_parent = (int_type)-1; tree() = default; @@ -67,12 +69,12 @@ class tree { init(new_parent_index.size()); parents_(memory::all) = new_parent_index; - parents_[0] = -1; + parents_[0] = no_parent; child_index_(memory::all) = algorithms::make_index(algorithms::child_count(parents_)); - std::vector<int> pos(parents_.size(), 0); + std::vector<int_type> pos(parents_.size(), 0); for (auto i = 1u; i < parents_.size(); ++i) { auto p = parents_[i]; children_[child_index_[p] + pos[p]] = i; @@ -80,16 +82,18 @@ class tree { } } - size_t num_children() const { - return children_.size(); + size_type num_children() const { + return static_cast<size_type>(children_.size()); } - size_t num_children(size_t b) const { + + size_type num_children(size_t b) const { return child_index_[b+1] - child_index_[b]; } - size_t num_nodes() const { + + size_type num_nodes() const { // the number of nodes is the size of the child index minus 1 // ... except for the case of an empty tree - auto sz = child_index_.size(); + auto sz = static_cast<size_type>(child_index_.size()); return sz ? sz - 1 : 0; } @@ -104,7 +108,7 @@ class tree { } /// return the list of all children of branch b - const_view_type children(size_t b) const { + const_view_type children(size_type b) const { return children_(child_index_[b], child_index_[b+1]); } @@ -122,7 +126,7 @@ class tree { } /// memory used to store tree (in bytes) - size_t memory() const { + std::size_t memory() const { return sizeof(int_type)*data_.size() + sizeof(tree); } @@ -164,17 +168,16 @@ class tree { return p; } - private : - - void init(int nnode) { - auto nchild = nnode -1; +private: + void init(size_type nnode) { + auto nchild = nnode - 1; data_ = index_type(nchild + (nnode + 1) + nnode); set_ranges(nnode); } - void set_ranges(int nnode) { - if(nnode) { + void set_ranges(size_type nnode) { + if (nnode) { auto nchild = nnode - 1; // data_ is partitioned as follows: // data_ = [children_[nchild], child_index_[nnode+1], parents_[nnode]] @@ -215,17 +218,17 @@ class tree { /// new_node /// p : permutation vector, p[i] is the new index of node i in the old /// tree - int add_children( - int new_node, - int old_node, - int parent_node, + int_type add_children( + int_type new_node, + int_type old_node, + int_type parent_node, view_type p, tree const& old_tree ) { - // check for the senitel that indicates that the old root has + // check for the sentinel that indicates that the old root has // been processed - if(old_node==-1) { + if (old_node==no_parent) { return new_node; } @@ -237,7 +240,7 @@ class tree { auto this_node = new_node; auto pos = child_index_[this_node]; - auto add_parent_as_child = parent_node>=0 && old_node>0; + auto add_parent_as_child = parent_node!=no_parent && old_node>0; // // STEP 1 : add the child indexes for this_node // @@ -259,12 +262,12 @@ class tree { // STEP 2 : recursively add each child's children // new_node++; - for(auto b : old_children) { - if(b != parent_node) { - new_node = add_children(new_node, b, -1, p, old_tree); + for (auto b : old_children) { + if (b != parent_node) { + new_node = add_children(new_node, b, no_parent, p, old_tree); } } - if(add_parent_as_child) { + if (add_parent_as_child) { new_node = add_children( new_node, old_tree.parent(old_node), old_node, p, old_tree @@ -286,38 +289,38 @@ class tree { view_type parents_ = data_(0, 0); }; -template <typename C> -std::vector<int> make_parent_index(tree const& t, C const& counts) +template <typename IntT, typename SizeT, typename C> +std::vector<IntT> make_parent_index(tree<IntT, SizeT> const& t, C const& counts) { using range = memory::Range; + using int_type = typename tree<IntT, SizeT>::int_type; + constexpr auto no_parent = tree<IntT, SizeT>::no_parent; - if( !algorithms::is_positive(counts) - || counts.size() != t.num_nodes() ) - { + if (!algorithms::is_positive(counts) || counts.size() != t.num_nodes()) { throw std::domain_error( "make_parent_index requires one non-zero count per segment" ); } auto index = algorithms::make_index(counts); auto num_compartments = index.back(); - std::vector<int> parent_index(num_compartments); - auto pos = 0; - for(int i : range(0, t.num_nodes())) { + std::vector<int_type> parent_index(num_compartments); + int_type pos = 0; + for (int_type i : range(0, t.num_nodes())) { // get the parent of this segment // taking care for the case where the root node has -1 as its parent auto parent = t.parent(i); - parent = parent>=0 ? parent : 0; + parent = parent!=no_parent ? parent : 0; // the index of the first compartment in the segment // is calculated differently for the root (i.e when i==parent) - if(i!=parent) { + if (i!=parent) { parent_index[pos++] = index[parent+1]-1; } else { parent_index[pos++] = parent; } // number the remaining compartments in the segment consecutively - while(pos<index[i+1]) { + while (pos<index[i+1]) { parent_index[pos] = pos-1; pos++; } diff --git a/src/util/lexcmp_def.hpp b/src/util/lexcmp_def.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d1c3e8a3bfc63341070b55b1320de03583797bbe --- /dev/null +++ b/src/util/lexcmp_def.hpp @@ -0,0 +1,40 @@ +#pragma once + +/* + * Macro definitions for defining comparison operators for + * record-like types. + * + * Use: + * + * To define comparison operations for a record type xyzzy + * with fields foo, bar and baz: + * + * DEFINE_LEXICOGRAPHIC_ORDERING(xyzzy,(a.foo,a.bar,a.baz),(b.foo,b.bar,b.baz)) + * + * The explicit use of 'a' and 'b' in the second and third parameters + * is needed only to save a heroic amount of preprocessor macro + * deep magic. + * + */ + +#include <tuple> + +#define DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(proxy,op,type,a_fields,b_fields) \ +inline bool operator op(const type &a,const type &b) { return proxy a_fields op proxy b_fields; } + +#define DEFINE_LEXICOGRAPHIC_ORDERING(type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,<,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,>,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,<=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,>=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,!=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,==,type,a_fields,b_fields) + +#define DEFINE_LEXICOGRAPHIC_ORDERING_BY_VALUE(type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,<,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,>,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,<=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,>=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,!=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,==,type,a_fields,b_fields) + diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index a3a2d55333f6316b133bff3982ec58e1b03d525d..61d713bc831e7ec63dfaf370f7931e204c7d9e45 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -16,6 +16,7 @@ set(TEST_SOURCES test_event_queue.cpp test_fvm.cpp test_cell_group.cpp + test_lexcmp.cpp test_matrix.cpp test_mechanisms.cpp test_optional.cpp diff --git a/tests/unit/test_cell.cpp b/tests/unit/test_cell.cpp index 88c8dcaced167d4030529adb8a348a116158c17f..3102d97435d3095b4ef91b885b040ac084f37a5f 100644 --- a/tests/unit/test_cell.cpp +++ b/tests/unit/test_cell.cpp @@ -1,6 +1,6 @@ #include "gtest.h" -#include "../src/cell.hpp" +#include "cell.hpp" TEST(cell_type, soma) { @@ -59,7 +59,7 @@ TEST(cell_type, add_segment) ); c.add_cable(0, std::move(seg)); - EXPECT_EQ(c.num_segments(), 2); + EXPECT_EQ(c.num_segments(), 2u); } // add segment on the fly @@ -78,7 +78,7 @@ TEST(cell_type, add_segment) segmentKind::dendrite, cable_radius, cable_radius, cable_length ); - EXPECT_EQ(c.num_segments(), 2); + EXPECT_EQ(c.num_segments(), 2u); } { cell c; @@ -97,7 +97,7 @@ TEST(cell_type, add_segment) std::vector<double>{cable_length, cable_length, cable_length} ); - EXPECT_EQ(c.num_segments(), 2); + EXPECT_EQ(c.num_segments(), 2u); } } @@ -137,7 +137,7 @@ TEST(cell_type, multiple_cables) c.add_cable(1, seg(segmentKind::dendrite)); c.add_cable(1, seg(segmentKind::dendrite)); - EXPECT_EQ(c.num_segments(), 5); + EXPECT_EQ(c.num_segments(), 5u); // each of the 5 segments has volume 1 by design EXPECT_EQ(c.volume(), 5.); // each of the 4 cables has volume 2., and the soma has an awkward area @@ -148,12 +148,14 @@ TEST(cell_type, multiple_cables) const auto model = c.model(); auto const& con = model.tree; + auto no_parent = cell_tree::no_parent; + EXPECT_EQ(con.num_segments(), 5u); - EXPECT_EQ(con.parent(0), -1); - EXPECT_EQ(con.parent(1), 0); - EXPECT_EQ(con.parent(2), 0); - EXPECT_EQ(con.parent(3), 1); - EXPECT_EQ(con.parent(4), 1); + EXPECT_EQ(con.parent(0), no_parent); + EXPECT_EQ(con.parent(1), 0u); + EXPECT_EQ(con.parent(2), 0u); + EXPECT_EQ(con.parent(3), 1u); + EXPECT_EQ(con.parent(4), 1u); EXPECT_EQ(con.num_children(0), 2u); EXPECT_EQ(con.num_children(1), 2u); EXPECT_EQ(con.num_children(2), 0u); diff --git a/tests/unit/test_cell_group.cpp b/tests/unit/test_cell_group.cpp index d9787a1935657391be82f2e674b13bab9ef908ed..033cd3109b57d1a74362a2bd0a9424027567d0a5 100644 --- a/tests/unit/test_cell_group.cpp +++ b/tests/unit/test_cell_group.cpp @@ -2,15 +2,13 @@ #include "gtest.h" +#include <catypes.hpp> #include <fvm_cell.hpp> #include <cell_group.hpp> nest::mc::cell make_cell() { using namespace nest::mc; - // setup global state for the mechanisms - mechanisms::setup_mechanism_helpers(); - nest::mc::cell cell; // Soma with diameter 12.6157 um and HH channel @@ -36,7 +34,7 @@ TEST(cell_group, test) { using namespace nest::mc; - using cell_type = cell_group<fvm::fvm_cell<double, int>>; + using cell_type = cell_group<fvm::fvm_cell<double, cell_local_size_type>>; auto cell = cell_type{make_cell()}; diff --git a/tests/unit/test_fvm.cpp b/tests/unit/test_fvm.cpp index 1383167aafec9b0c0ae36f2bd6ab8661803d2fe5..99e676cb317fe566142cb2c713b0a83834dd2ee6 100644 --- a/tests/unit/test_fvm.cpp +++ b/tests/unit/test_fvm.cpp @@ -1,20 +1,19 @@ #include <fstream> #include "gtest.h" -#include "../test_util.hpp" +#include <catypes.hpp> #include <cell.hpp> #include <fvm_cell.hpp> +#include "../test_util.hpp" + TEST(fvm, cable) { using namespace nest::mc; nest::mc::cell cell; - // setup global state for the mechanisms - nest::mc::mechanisms::setup_mechanism_helpers(); - cell.add_soma(6e-4); // 6um in cm // 1um radius and 4mm long, all in cm @@ -42,7 +41,7 @@ TEST(fvm, cable) cell.segment(1)->set_compartments(4); cell.segment(2)->set_compartments(4); - using fvm_cell = fvm::fvm_cell<double, int>; + using fvm_cell = fvm::fvm_cell<double, cell_local_index_type>; fvm_cell fvcell(cell); auto& J = fvcell.jacobian(); @@ -64,9 +63,6 @@ TEST(fvm, init) nest::mc::cell cell; - // setup global state for the mechanisms - nest::mc::mechanisms::setup_mechanism_helpers(); - cell.add_soma(12.6157/2.0); //auto& props = cell.soma()->properties; @@ -95,7 +91,7 @@ TEST(fvm, init) cell.segment(1)->set_compartments(10); - using fvm_cell = fvm::fvm_cell<double, int>; + using fvm_cell = fvm::fvm_cell<double, cell_local_index_type>; fvm_cell fvcell(cell); auto& J = fvcell.jacobian(); EXPECT_EQ(J.size(), 11u); diff --git a/tests/unit/test_lexcmp.cpp b/tests/unit/test_lexcmp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a02ac0765823f61d54e8acee3cf38611552d9dd7 --- /dev/null +++ b/tests/unit/test_lexcmp.cpp @@ -0,0 +1,110 @@ +#include "gtest.h" + +#include <util/lexcmp_def.hpp> + +struct lexcmp_test_one { + int foo; +}; + +DEFINE_LEXICOGRAPHIC_ORDERING(lexcmp_test_one, (a.foo), (b.foo)) + +TEST(lexcmp_def,one) { + lexcmp_test_one p{3}, q{4}, r{4}; + + EXPECT_LE(p,q); + EXPECT_LT(p,q); + EXPECT_NE(p,q); + EXPECT_GE(q,p); + EXPECT_GT(q,p); + + EXPECT_LE(q,r); + EXPECT_GE(q,r); + EXPECT_EQ(q,r); +} + +struct lexcmp_test_three { + int x; + std::string y; + double z; +}; + +// test fields in reverse order: z, y, x +DEFINE_LEXICOGRAPHIC_ORDERING(lexcmp_test_three, (a.z,a.y,a.x), (b.z,b.y,b.x)) + +TEST(lexcmp_def,three) { + lexcmp_test_three p{1,"foo",2}; + lexcmp_test_three q{1,"foo",3}; + lexcmp_test_three r{1,"bar",2}; + lexcmp_test_three s{5,"foo",2}; + + EXPECT_LE(p,q); + EXPECT_LT(p,q); + EXPECT_NE(p,q); + EXPECT_GE(q,p); + EXPECT_GT(q,p); + + EXPECT_LE(r,p); + EXPECT_LT(r,p); + EXPECT_NE(p,r); + EXPECT_GE(p,r); + EXPECT_GT(p,r); + + EXPECT_LE(p,s); + EXPECT_LT(p,s); + EXPECT_NE(p,s); + EXPECT_GE(s,p); + EXPECT_GT(s,p); +} + +// test fields accessed by reference-returning member function + +class lexcmp_test_refmemfn { +public: + explicit lexcmp_test_refmemfn(int foo): foo_(foo) {} + + const int &foo() const { return foo_; } + int &foo() { return foo_; } + +private: + int foo_; +}; + +DEFINE_LEXICOGRAPHIC_ORDERING(lexcmp_test_refmemfn, (a.foo()), (b.foo())) + +TEST(lexcmp_def,refmemfn) { + lexcmp_test_refmemfn p{3}; + const lexcmp_test_refmemfn q{4}; + + EXPECT_LE(p,q); + EXPECT_LT(p,q); + EXPECT_NE(p,q); + EXPECT_GE(q,p); + EXPECT_GT(q,p); +} + +// test comparison via proxy tuple object + +class lexcmp_test_valmemfn { +public: + explicit lexcmp_test_valmemfn(int foo, int bar): foo_(foo), bar_(bar) {} + int foo() const { return foo_; } + int bar() const { return bar_; } + +private: + int foo_; + int bar_; +}; + +DEFINE_LEXICOGRAPHIC_ORDERING_BY_VALUE(lexcmp_test_valmemfn, (a.foo(),a.bar()), (b.foo(),b.bar())) + +TEST(lexcmp_def,proxy) { + lexcmp_test_valmemfn p{3,2}, q{3,4}; + + EXPECT_LE(p,q); + EXPECT_LT(p,q); + EXPECT_NE(p,q); + EXPECT_GE(q,p); + EXPECT_GT(q,p); +} + + diff --git a/tests/unit/test_mechanisms.cpp b/tests/unit/test_mechanisms.cpp index 2e31f1139d25cb3e36bc1ff0b32a3ec8a4316a4b..377f683fa8ff0831b0cdff3f94be96710d966d0c 100644 --- a/tests/unit/test_mechanisms.cpp +++ b/tests/unit/test_mechanisms.cpp @@ -1,25 +1,17 @@ #include "gtest.h" -#include "../src/mechanism_interface.hpp" -#include "../src/matrix.hpp" +//#include "../src/mechanism_interface.hpp" +#include "mechanism_catalogue.hpp" +#include "matrix.hpp" TEST(mechanisms, helpers) { - nest::mc::mechanisms::setup_mechanism_helpers(); - - EXPECT_EQ(nest::mc::mechanisms::mechanism_helpers.size(), 4u); + using namespace nest::mc; + using catalogue = mechanisms::catalogue<double, int>; // verify that the hh and pas channels are available - EXPECT_EQ(nest::mc::mechanisms::get_mechanism_helper("hh")->name(), "hh"); - EXPECT_EQ(nest::mc::mechanisms::get_mechanism_helper("pas")->name(), "pas"); - - // check that an out_of_range exception is thrown if an invalid mechanism is - // requested - ASSERT_THROW( - nest::mc::mechanisms::get_mechanism_helper("dachshund"), - std::out_of_range - ); + EXPECT_TRUE(catalogue::has("hh")); + EXPECT_TRUE(catalogue::has("pas")); - //0 1 2 3 4 5 6 7 8 9 std::vector<int> parent_index = {0,0,1,2,3,4,0,6,7,8}; memory::HostVector<int> node_indices = std::vector<int>{0,6,7,8,9}; auto n = node_indices.size(); @@ -28,10 +20,17 @@ TEST(mechanisms, helpers) { memory::HostVector<double> vec_i(n, 0.); memory::HostVector<double> vec_v(n, 0.); - auto& helper = nest::mc::mechanisms::get_mechanism_helper("hh"); - auto mech = helper->new_mechanism(vec_v, vec_i, node_indices); + auto mech = catalogue::make("hh", vec_v, vec_i, node_indices); EXPECT_EQ(mech->name(), "hh"); EXPECT_EQ(mech->size(), 5u); //EXPECT_EQ(mech->matrix_, &matrix); + + // check that an out_of_range exception is thrown if an invalid mechanism is + // requested + ASSERT_THROW( + catalogue::make("dachshund", vec_v, vec_i, node_indices), + std::out_of_range + ); + //0 1 2 3 4 5 6 7 8 9 } diff --git a/tests/unit/test_probe.cpp b/tests/unit/test_probe.cpp index 52ac4e7f62171bc556df5b0ba4e25f05b3304fa5..289e5929c909d19732e9d7bae7ba43a05b2ccdcb 100644 --- a/tests/unit/test_probe.cpp +++ b/tests/unit/test_probe.cpp @@ -1,5 +1,6 @@ #include "gtest.h" +#include "catypes.hpp" #include "cell.hpp" #include "fvm_cell.hpp" @@ -16,9 +17,9 @@ TEST(probe, instantiation) auto p2 = c1.add_probe(loc2, probeKind::membrane_current); // expect locally provided probe ids to be numbered sequentially from zero. - - EXPECT_EQ(0, p1); - EXPECT_EQ(1, p2); + + EXPECT_EQ(0u, p1); + EXPECT_EQ(1u, p2); // expect the probes() return to be a collection with these two probes. @@ -51,11 +52,11 @@ TEST(probe, fvm_cell) 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); - fvm::fvm_cell<double, int> lcell(bs); + fvm::fvm_cell<double, cell_local_size_type> lcell(bs); lcell.setup_matrix(0.01); lcell.initialize(); diff --git a/tests/unit/test_spikes.cpp b/tests/unit/test_spikes.cpp index b16f89cda31768f43b8509b9f9cdde375ed9bc25..3b4862029208c1f6c5a657d83dd982f510852cd6 100644 --- a/tests/unit/test_spikes.cpp +++ b/tests/unit/test_spikes.cpp @@ -1,7 +1,7 @@ #include "gtest.h" -#include <communication/spike.hpp> -#include <communication/spike_source.hpp> +#include <spike.hpp> +#include <spike_source.hpp> struct cell_proxy { double voltage(nest::mc::segment_location loc) const { diff --git a/tests/unit/test_swcio.cpp b/tests/unit/test_swcio.cpp index 32eaff75b967ccf9c5f8b7ef7f06c8b3d8b10f3e..c927224ffaef7e6e9d026a53dd81377b061a24eb 100644 --- a/tests/unit/test_swcio.cpp +++ b/tests/unit/test_swcio.cpp @@ -502,7 +502,7 @@ TEST(swc_io, cell_construction) cell cell = io::swc_read_cell(is); EXPECT_TRUE(cell.has_soma()); - EXPECT_EQ(4, cell.num_segments()); + EXPECT_EQ(4u, cell.num_segments()); EXPECT_EQ(norm(points[1]-points[2]), cell.cable(1)->length()); EXPECT_EQ(norm(points[2]-points[3]), cell.cable(2)->length()); @@ -515,13 +515,13 @@ TEST(swc_io, cell_construction) EXPECT_EQ(2.1, cell.soma()->radius()); EXPECT_EQ(point_type(0, 0, 0), cell.soma()->center()); - for (auto i = 1; i < cell.num_segments(); ++i) { + for (auto i = 1u; i < cell.num_segments(); ++i) { EXPECT_TRUE(cell.segment(i)->is_dendrite()); } - EXPECT_EQ(1, cell.cable(1)->num_sub_segments()); - EXPECT_EQ(1, cell.cable(2)->num_sub_segments()); - EXPECT_EQ(2, cell.cable(3)->num_sub_segments()); + EXPECT_EQ(1u, cell.cable(1)->num_sub_segments()); + EXPECT_EQ(1u, cell.cable(2)->num_sub_segments()); + EXPECT_EQ(2u, cell.cable(3)->num_sub_segments()); // Check the radii @@ -563,7 +563,7 @@ TEST(swc_parser, from_file_ball_and_stick) auto cell = nest::mc::io::swc_read_cell(fid); // verify that the correct number of nodes was read - EXPECT_EQ(cell.num_segments(), 2); + EXPECT_EQ(cell.num_segments(), 2u); EXPECT_EQ(cell.num_compartments(), 2u); // make an equivalent cell via C++ interface diff --git a/tests/unit/test_synapses.cpp b/tests/unit/test_synapses.cpp index 9ad68c2444ef17d6f2b2355e3c388f76ca9220e6..8cd9de04f57625ec7416e5a571ab24447c1a6cae 100644 --- a/tests/unit/test_synapses.cpp +++ b/tests/unit/test_synapses.cpp @@ -14,7 +14,7 @@ TEST(synapses, add_to_cell) nest::mc::cell cell; // setup global state for the mechanisms - nest::mc::mechanisms::setup_mechanism_helpers(); + // nest::mc::mechanisms::setup_mechanism_helpers(); // Soma with diameter 12.6157 um and HH channel auto soma = cell.add_soma(12.6157/2.0); @@ -30,15 +30,15 @@ TEST(synapses, add_to_cell) EXPECT_EQ(3u, cell.synapses().size()); const auto& syns = cell.synapses(); - EXPECT_EQ(syns[0].location.segment, 0); + EXPECT_EQ(syns[0].location.segment, 0u); 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.segment, 1u); 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.segment, 0u); EXPECT_EQ(syns[2].location.position, 0.3); EXPECT_EQ(syns[2].mechanism.name(), "expsyn"); } diff --git a/tests/unit/test_tree.cpp b/tests/unit/test_tree.cpp index b82da064b6143fa120c92df2b223db8b95db15ff..4c69ce400d1c6146f7f704b2317a0189b8a41a53 100644 --- a/tests/unit/test_tree.cpp +++ b/tests/unit/test_tree.cpp @@ -17,20 +17,24 @@ using json = nlohmann::json; using range = memory::Range; using namespace nest::mc; +using int_type = cell_tree::int_type; + TEST(cell_tree, from_parent_index) { + auto no_parent = cell_tree::no_parent; + // tree with single branch corresponding to the root node // this is equivalent to a single compartment model // CASE 1 : single root node in parent_index { - std::vector<int> parent_index = {0}; + std::vector<int_type> parent_index = {0}; cell_tree tree(parent_index); EXPECT_EQ(tree.num_segments(), 1u); EXPECT_EQ(tree.num_children(0), 0u); } // CASE 2 : empty parent_index { - std::vector<int> parent_index; + std::vector<int_type> parent_index; cell_tree tree(parent_index); EXPECT_EQ(tree.num_segments(), 1u); EXPECT_EQ(tree.num_children(0), 0u); @@ -46,7 +50,7 @@ TEST(cell_tree, from_parent_index) { // / // 3 // - std::vector<int> parent_index = + std::vector<int_type> parent_index = {0, 0, 1, 2, 0, 4}; cell_tree tree(parent_index); EXPECT_EQ(tree.num_segments(), 3u); @@ -66,7 +70,7 @@ TEST(cell_tree, from_parent_index) { // / \. // 3 8 // - std::vector<int> parent_index = + std::vector<int_type> parent_index = {0, 0, 1, 2, 0, 4, 0, 6, 7, 8}; cell_tree tree(parent_index); @@ -79,10 +83,10 @@ TEST(cell_tree, from_parent_index) { EXPECT_EQ(tree.num_children(3), 0u); // Check new structure - EXPECT_EQ(-1, tree.parent(0)); - EXPECT_EQ(0, tree.parent(1)); - EXPECT_EQ(0, tree.parent(2)); - EXPECT_EQ(0, tree.parent(3)); + EXPECT_EQ(no_parent, tree.parent(0)); + EXPECT_EQ(0u, tree.parent(1)); + EXPECT_EQ(0u, tree.parent(2)); + EXPECT_EQ(0u, tree.parent(3)); } { // @@ -100,7 +104,7 @@ TEST(cell_tree, from_parent_index) { // \. // 13 // - std::vector<int> parent_index = + std::vector<int_type> parent_index = {0, 0, 1, 2, 0, 4, 0, 6, 7, 8, 9, 8, 11, 12}; cell_tree tree(parent_index); EXPECT_EQ(tree.num_segments(), 6u); @@ -115,12 +119,12 @@ TEST(cell_tree, from_parent_index) { EXPECT_EQ(tree.num_children(5), 0u); // Check new structure - EXPECT_EQ(-1, tree.parent(0)); - EXPECT_EQ(0, tree.parent(1)); - EXPECT_EQ(0, tree.parent(2)); - EXPECT_EQ(0, tree.parent(3)); - EXPECT_EQ(3, tree.parent(4)); - EXPECT_EQ(3, tree.parent(5)); + EXPECT_EQ(no_parent, tree.parent(0)); + EXPECT_EQ(0u, tree.parent(1)); + EXPECT_EQ(0u, tree.parent(2)); + EXPECT_EQ(0u, tree.parent(3)); + EXPECT_EQ(3u, tree.parent(4)); + EXPECT_EQ(3u, tree.parent(5)); } { // @@ -129,7 +133,7 @@ TEST(cell_tree, from_parent_index) { // 1 // / \. // 2 3 - std::vector<int> parent_index = {0,0,1,1}; + std::vector<int_type> parent_index = {0,0,1,1}; cell_tree tree(parent_index); EXPECT_EQ(tree.num_segments(), 4u); @@ -146,7 +150,7 @@ TEST(cell_tree, from_parent_index) { // 1 4 5 // / \. // 2 3 - std::vector<int> parent_index = {0,0,1,1,0,0}; + std::vector<int_type> parent_index = {0,0,1,1,0,0}; cell_tree tree(parent_index); EXPECT_EQ(tree.num_segments(), 6u); @@ -158,11 +162,11 @@ TEST(cell_tree, from_parent_index) { EXPECT_EQ(tree.num_children(4), 0u); // Check children - EXPECT_EQ(1, tree.children(0)[0]); - EXPECT_EQ(4, tree.children(0)[1]); - EXPECT_EQ(5, tree.children(0)[2]); - EXPECT_EQ(2, tree.children(1)[0]); - EXPECT_EQ(3, tree.children(1)[1]); + EXPECT_EQ(1u, tree.children(0)[0]); + EXPECT_EQ(4u, tree.children(0)[1]); + EXPECT_EQ(5u, tree.children(0)[2]); + EXPECT_EQ(2u, tree.children(1)[0]); + EXPECT_EQ(3u, tree.children(1)[1]); } /* FIXME { @@ -198,8 +202,8 @@ TEST(tree, change_root) { // 1 2 -> 1 // | // 2 - std::vector<int> parent_index = {0,0,0}; - tree t(parent_index); + std::vector<int_type> parent_index = {0,0,0}; + tree<int_type> t(parent_index); t.change_root(1); EXPECT_EQ(t.num_nodes(), 3u); @@ -216,8 +220,8 @@ TEST(tree, change_root) { // 1 2 -> 1 2 3 // / \ | // 3 4 4 - std::vector<int> parent_index = {0,0,0,1,1}; - tree t(parent_index); + std::vector<int_type> parent_index = {0,0,0,1,1}; + tree<int_type> t(parent_index); t.change_root(1u); EXPECT_EQ(t.num_nodes(), 5u); @@ -240,8 +244,8 @@ TEST(tree, change_root) { // 3 4 3 4 6 // / \. // 5 6 - std::vector<int> parent_index = {0,0,0,1,1,4,4}; - tree t(parent_index); + std::vector<int_type> parent_index = {0,0,0,1,1,4,4}; + tree<int_type> t(parent_index); t.change_root(1); @@ -258,6 +262,8 @@ TEST(tree, change_root) { } TEST(cell_tree, balance) { + auto no_parent = cell_tree::no_parent; + { // a cell with the following structure // will balance around 1 @@ -268,13 +274,13 @@ TEST(cell_tree, balance) { // 3 4 3 4 6 // / \. // 5 6 - std::vector<int> parent_index = {0,0,0,1,1,4,4}; + std::vector<int_type> parent_index = {0,0,0,1,1,4,4}; cell_tree t(parent_index); t.balance(); // the soma (original root) has moved to 5 in the new tree - EXPECT_EQ(t.soma(), 5); + EXPECT_EQ(t.soma(), 5u); EXPECT_EQ(t.num_segments(), 7u); EXPECT_EQ(t.num_children(0),3u); @@ -284,13 +290,13 @@ TEST(cell_tree, balance) { EXPECT_EQ(t.num_children(4),0u); EXPECT_EQ(t.num_children(5),1u); EXPECT_EQ(t.num_children(6),0u); - EXPECT_EQ(t.parent(0),-1); - EXPECT_EQ(t.parent(1), 0); - EXPECT_EQ(t.parent(2), 0); - EXPECT_EQ(t.parent(3), 0); - EXPECT_EQ(t.parent(4), 2); - EXPECT_EQ(t.parent(5), 2); - EXPECT_EQ(t.parent(6), 5); + EXPECT_EQ(t.parent(0), no_parent); + EXPECT_EQ(t.parent(1), 0u); + EXPECT_EQ(t.parent(2), 0u); + EXPECT_EQ(t.parent(3), 0u); + EXPECT_EQ(t.parent(4), 2u); + EXPECT_EQ(t.parent(5), 2u); + EXPECT_EQ(t.parent(6), 5u); //t.to_graphviz("cell.dot"); } @@ -307,7 +313,7 @@ TEST(cell_tree, json_load) std::ifstream(path) >> cell_data; for(auto c : range(0,cell_data.size())) { - std::vector<int> parent_index = cell_data[c]["parent_index"]; + std::vector<int_type> parent_index = cell_data[c]["parent_index"]; cell_tree tree(parent_index); //tree.to_graphviz("cell" + std::to_string(c) + ".dot"); } diff --git a/tests/validation/validate_ball_and_stick.cpp b/tests/validation/validate_ball_and_stick.cpp index 0e41bd021534af6020482659f082eca0867fb63a..a819173e937419a87471a79f1644a243b20e7ac0 100644 --- a/tests/validation/validate_ball_and_stick.cpp +++ b/tests/validation/validate_ball_and_stick.cpp @@ -1,6 +1,7 @@ #include <fstream> #include <json/src/json.hpp> +#include <catypes.hpp> #include <cell.hpp> #include <fvm_cell.hpp> @@ -16,9 +17,6 @@ TEST(ball_and_stick, neuron_baseline) nest::mc::cell cell; - // setup global state for the mechanisms - nest::mc::mechanisms::setup_mechanism_helpers(); - // Soma with diameter 12.6157 um and HH channel auto soma = cell.add_soma(12.6157/2.0); soma->add_mechanism(hh_parameters()); @@ -92,7 +90,7 @@ TEST(ball_and_stick, neuron_baseline) std::vector<std::vector<double>> v(3); // make the lowered finite volume cell - fvm::fvm_cell<double, int> model(cell); + fvm::fvm_cell<double, cell_local_size_type> model(cell); auto graph = cell.model(); // set initial conditions @@ -165,9 +163,6 @@ TEST(ball_and_3stick, neuron_baseline) nest::mc::cell cell; - // setup global state for the mechanisms - nest::mc::mechanisms::setup_mechanism_helpers(); - // Soma with diameter 12.6157 um and HH channel auto soma = cell.add_soma(12.6157/2.0); soma->add_mechanism(hh_parameters()); @@ -250,7 +245,7 @@ TEST(ball_and_3stick, neuron_baseline) std::vector<std::vector<double>> v(3); // make the lowered finite volume cell - fvm::fvm_cell<double, int> model(cell); + fvm::fvm_cell<double, cell_local_size_type> model(cell); auto graph = cell.model(); // set initial conditions diff --git a/tests/validation/validate_soma.cpp b/tests/validation/validate_soma.cpp index 9c3c9fdfa56b14b9aa948c762023355541866d9a..203967014117ca539564aadb35da98ceb1b60054 100644 --- a/tests/validation/validate_soma.cpp +++ b/tests/validation/validate_soma.cpp @@ -1,6 +1,7 @@ #include <fstream> #include <json/src/json.hpp> +#include <catypes.hpp> #include <cell.hpp> #include <fvm_cell.hpp> @@ -17,9 +18,6 @@ TEST(soma, neuron_baseline) nest::mc::cell cell; - // setup global state for the mechanisms - nest::mc::mechanisms::setup_mechanism_helpers(); - // Soma with diameter 18.8um and HH channel auto soma = cell.add_soma(18.8/2.0); soma->mechanism("membrane").set("r_L", 123); // no effect for single compartment cell @@ -29,7 +27,7 @@ TEST(soma, neuron_baseline) cell.add_stimulus({0,0.5}, {10., 100., 0.1}); // make the lowered finite volume cell - fvm::fvm_cell<double, int> model(cell); + fvm::fvm_cell<double, cell_local_size_type> model(cell); // load data from file auto cell_data = testing::g_validation_data.load("soma.json"); @@ -85,9 +83,6 @@ TEST(soma, convergence) nest::mc::cell cell; - // setup global state for the mechanisms - nest::mc::mechanisms::setup_mechanism_helpers(); - // Soma with diameter 18.8um and HH channel auto soma = cell.add_soma(18.8/2.0); soma->mechanism("membrane").set("r_L", 123); // no effect for single compartment cell @@ -97,7 +92,7 @@ TEST(soma, convergence) cell.add_stimulus({0,0.5}, {10., 100., 0.1}); // make the lowered finite volume cell - fvm::fvm_cell<double, int> model(cell); + fvm::fvm_cell<double, cell_local_size_type> model(cell); // generate baseline solution with small dt=0.0001 std::vector<double> baseline_spike_times; diff --git a/tests/validation/validate_synapses.cpp b/tests/validation/validate_synapses.cpp index 42ace29c3393bb177b878ab3e8c6eb6de42d8676..c95f5af1d93efaf4a9b5794ef84e530e1d1196ec 100644 --- a/tests/validation/validate_synapses.cpp +++ b/tests/validation/validate_synapses.cpp @@ -3,6 +3,7 @@ #include <json/src/json.hpp> +#include <catypes.hpp> #include <cell.hpp> #include <cell_group.hpp> #include <fvm_cell.hpp> @@ -50,12 +51,10 @@ void run_neuron_baseline(const char* syn_type, const char* data_file) { using namespace nest::mc; using namespace nlohmann; + using lowered_cell = fvm::fvm_cell<double, cell_local_size_type>; nest::mc::cell cell; - // setup global state for the mechanisms - mechanisms::setup_mechanism_helpers(); - // Soma with diameter 12.6157 um and HH channel auto soma = cell.add_soma(12.6157/2.0); soma->add_mechanism(hh_parameters()); @@ -106,7 +105,7 @@ void run_neuron_baseline(const char* syn_type, const char* data_file) std::vector<std::vector<double>> v(2); // make the lowered finite volume cell - cell_group<fvm::fvm_cell<double, int>> group(cell); + cell_group<lowered_cell> group(cell); group.set_source_gids(0); group.set_target_gids(0);