diff --git a/arbor/backends/multicore/matrix_state.hpp b/arbor/backends/multicore/matrix_state.hpp index 24a21c1b5bc8beddf4781547b892bedbd33a80d3..1831bfa07c221c26a28b8e71104262e4add0faa2 100644 --- a/arbor/backends/multicore/matrix_state.hpp +++ b/arbor/backends/multicore/matrix_state.hpp @@ -58,13 +58,15 @@ public: auto n = size(); invariant_d = array(n, 0); - for (auto i: util::make_span(1u, n)) { - auto gij = face_conductance[i]; - - u[i] = -gij; - invariant_d[i] += gij; - if (p[i]!=-1) { - invariant_d[p[i]] += gij; + if (n >= 1) { // skip empty matrix, ie cell with empty morphology + for (auto i: util::make_span(1u, n)) { + auto gij = face_conductance[i]; + + u[i] = -gij; + invariant_d[i] += gij; + if (p[i]!=-1) { + invariant_d[p[i]] += gij; + } } } } @@ -116,7 +118,7 @@ public: for (auto cv_span: util::partition_view(cell_cv_divs)) { auto first = cv_span.first; auto last = cv_span.second; // one past the end - + if (first >= last) continue; // skip cell with no CVs if (d[first]!=0) { // backward sweep for(auto i=last-1; i>first; --i) { diff --git a/arbor/util/span.hpp b/arbor/util/span.hpp index c6599e163f15698b64c384567efd5bb5fbd28224..06cc4bcd4d0795b3ffd69e81521de82762b793bd 100644 --- a/arbor/util/span.hpp +++ b/arbor/util/span.hpp @@ -22,24 +22,24 @@ namespace util { template <typename I> using span = range<counter<I>>; -template <typename I, typename J> +template <typename I, typename J, typename = std::enable_if_t<std::is_integral<std::common_type_t<I, J>>::value>> span<std::common_type_t<I, J>> make_span(I left, J right) { return span<std::common_type_t<I, J>>(left, right); } template <typename I, typename J> span<std::common_type_t<I, J>> make_span(std::pair<I, J> interval) { - return span<std::common_type_t<I, J>>(interval.first, interval.second); + return make_span(interval.first, interval.second); } template <typename I> span<I> make_span(I right) { - return span<I>(I{}, right); + return make_span(I{}, right); } template <typename Seq> auto count_along(const Seq& s) { - return util::make_span(std::size(s)); + return make_span(std::size(s)); } } // namespace util diff --git a/test/unit/test_simulation.cpp b/test/unit/test_simulation.cpp index 569c4fa403889cc5dc3cdfba762d3d3de0692d8f..3110d43822af939061ea6422bf77531a6c377589 100644 --- a/test/unit/test_simulation.cpp +++ b/test/unit/test_simulation.cpp @@ -2,8 +2,11 @@ #include <random> #include <vector> +#include <any> +#include <arbor/cable_cell.hpp> #include <arbor/common_types.hpp> +#include <arbor/context.hpp> #include <arbor/domain_decomposition.hpp> #include <arbor/load_balance.hpp> #include <arbor/lif_cell.hpp> @@ -33,6 +36,25 @@ static auto n_thread_context(unsigned n_thread) { return make_context(proc_allocation(std::max((int)n_thread, 1), -1)); } +struct null_recipe: arb::recipe { + arb::cable_cell_global_properties properties; + null_recipe() { properties.default_parameters = arb::neuron_parameter_defaults; } + arb::cell_size_type num_cells() const override { return 1; } + arb::cell_kind get_cell_kind(arb::cell_gid_type) const override { return arb::cell_kind::cable; } + arb::util::unique_any get_cell_description(arb::cell_gid_type) const override { return {arb::cable_cell{}}; } + std::vector<arb::probe_info> get_probes(arb::cell_gid_type gid) const override { return {}; } + std::any get_global_properties(arb::cell_kind) const override { return properties; } +}; + +// Test that cell models with empty morpologies build and run without error. +TEST(simulation, null) { + auto r = null_recipe{}; + auto c = arb::make_context(); + auto d = arb::partition_load_balance(r, c); + auto s = arb::simulation(r, d, c); + s.run(0.05, 0.01); +} + TEST(simulation, spike_global_callback) { constexpr unsigned n = 5; double t_max = 10.; diff --git a/test/unit/test_span.cpp b/test/unit/test_span.cpp index 6c55aeade259d722e84e2c14c52f1a3415badb88..7447e93366ef8ee18184f1cb73c17c0c8068de7a 100644 --- a/test/unit/test_span.cpp +++ b/test/unit/test_span.cpp @@ -40,7 +40,7 @@ TEST(span, int_access) { TEST(span, int_iterators) { using span = util::span<int>; - + using uc_span = util::span<unsigned char>; int n = 97; int a = 3; int b = a+n; @@ -53,11 +53,29 @@ TEST(span, int_iterators) { EXPECT_EQ(n, std::distance(s.begin(), s.end())); EXPECT_EQ(n, std::distance(s.cbegin(), s.cend())); - int sum = 0; - for (auto i: span(a, b)) { - sum += i; + { + int sum = 0; + for (auto i: span(a, b)) { + sum += i; + } + EXPECT_EQ(sum, (a+b-1)*(b-a)/2); + } + + { + auto touched = 0ul; + auto s = uc_span(b, a); + for (auto _: s) ++touched; + EXPECT_EQ(s.size(), touched); + EXPECT_GT(touched, 0ul); // + } + + { + auto touched = 0ul; + auto s = uc_span(a, a); + for (auto _: s) ++touched; + EXPECT_EQ(s.size(), touched); + EXPECT_EQ(0ul, touched); } - EXPECT_EQ(sum, (a+b-1)*(b-a)/2); } TEST(span, make_span) {