diff --git a/src/fvm_multicell.hpp b/src/fvm_multicell.hpp
index 72d22b25270bb1eb71a7a3307e39c2ad17bec62d..09e55a19f6efd8a2f0859e07673f7d345f3b2383 100644
--- a/src/fvm_multicell.hpp
+++ b/src/fvm_multicell.hpp
@@ -22,6 +22,7 @@
 #include <util/debug.hpp>
 #include <util/meta.hpp>
 #include <util/partition.hpp>
+#include <util/rangeutil.hpp>
 #include <util/span.hpp>
 
 #include <vector/include/Vector.hpp>
@@ -67,7 +68,7 @@ public:
     void reset();
 
     void deliver_event(target_handle h, value_type weight) {
-        mechanisms_[synapse_base_+h.first]->net_receive(h.second, weight);
+        mechanisms_[h.first]->net_receive(h.second, weight);
     }
 
     value_type detector_voltage(detector_handle h) const {
@@ -300,6 +301,8 @@ void fvm_multicell<T, I>::initialize(
     Targets& target_handles,
     Probes& probe_handles)
 {
+    using util::assign_by;
+    using util::sort_by;
     using util::transform_view;
     using util::make_partition;
     using util::make_span;
@@ -388,11 +391,7 @@ void fvm_multicell<T, I>::initialize(
             auto& map_entry = syn_mech_map[syn_mech_index];
 
             size_type syn_comp = comp_ival.first+find_compartment_index(syn.location, graph);
-            size_type syn_index = map_entry.size();
             map_entry.push_back(syn_comp);
-
-            *target_hi++ = target_handle{syn_mech_index, syn_index};
-            ++targets_count;
         }
 
         // normalize capacitance across cell
@@ -434,11 +433,6 @@ void fvm_multicell<T, I>::initialize(
         }
     }
 
-    // confirm write-parameters were appropriately sized
-    EXPECTS(detectors_size==detectors_count);
-    EXPECTS(targets_size==targets_count);
-    EXPECTS(probes_size==probes_count);
-
     // initalize matrix
     matrix_ = matrix_type(group_parent_index);
 
@@ -461,12 +455,43 @@ void fvm_multicell<T, I>::initialize(
     synapse_base_ = mechanisms_.size();
     for (const auto& syni: syn_mech_indices) {
         const auto& mech_name = syni.first;
+        size_type mech_index = mechanisms_.size();
+
+        auto comp_indices = syn_mech_map[syni.second];
+        size_type n_indices = size(comp_indices);
+
+        // sort indices but keep track of their original order for assigning
+        // target handles
+
+        using index_pair = std::pair<cell_lid_type, size_type>;
+        auto compartment_index = [](index_pair x) { return x.first; };
+        auto target_index = [](index_pair x) { return x.second; };
 
-        auto mech = mechanism_catalogue::make(mech_name, voltage_, current_, syn_mech_map[syni.second]);
+        std::vector<index_pair> permute;
+        assign_by(permute, make_span(0u, n_indices),
+            [&](size_type i) { return index_pair(comp_indices[i], i); });
+
+        sort_by(permute, compartment_index);
+        assign_by(comp_indices, permute, compartment_index);
+
+        // make target handles
+        std::vector<target_handle> handles(n_indices);
+        for (auto i: make_span(0u, n_indices)) {
+            handles[target_index(permute[i])] = {mech_index, i};
+        }
+        target_hi = std::copy_n(std::begin(handles), n_indices, target_hi);
+        targets_count += n_indices;
+
+        auto mech = mechanism_catalogue::make(mech_name, voltage_, current_, comp_indices);
         mech->set_areas(cv_areas_);
         mechanisms_.push_back(std::move(mech));
     }
 
+    // confirm write-parameters were appropriately sized
+    EXPECTS(detectors_size==detectors_count);
+    EXPECTS(targets_size==targets_count);
+    EXPECTS(probes_size==probes_count);
+
     // build the ion species
     for(auto ion : mechanisms::ion_kinds()) {
         // find the compartment indexes of all compartments that have a
diff --git a/src/util/range.hpp b/src/util/range.hpp
index df5625d0e6dc1e315e18d1e2e1a0e4b4ccecbd94..4fa8f25fe2650f126d9e1aac49716c9b08bf5e7a 100644
--- a/src/util/range.hpp
+++ b/src/util/range.hpp
@@ -152,60 +152,17 @@ range<U, V> make_range(const U& left, const V& right) {
 }
 
 template <typename Seq>
-auto canonical_view(const Seq& s) ->
+auto canonical_view(Seq& s) ->
     range<sentinel_iterator_t<decltype(std::begin(s)), decltype(std::end(s))>>
 {
     return {make_sentinel_iterator(std::begin(s), std::end(s)), make_sentinel_end(std::begin(s), std::end(s))};
 }
 
-/*
- * Present a single item as a range
- */
-
-template <typename T>
-range<T*> singleton_view(T& item) {
-    return {&item, &item+1};
-}
-
-template <typename T>
-range<const T*> singleton_view(const T& item) {
-    return {&item, &item+1};
-}
-
-/*
- * Range/container utility functions
- */
-
-template <typename Container, typename Seq>
-Container& append(Container &c, const Seq& seq) {
-    auto canon = canonical_view(seq);
-    c.insert(c.end(), std::begin(canon), std::end(canon));
-    return c;
-}
-
-template <typename AssignableContainer, typename Seq>
-AssignableContainer& assign(AssignableContainer& c, const Seq& seq) {
-    auto canon = canonical_view(seq);
-    c.assign(std::begin(canon), std::end(canon));
-    return c;
-}
-
 template <typename Seq>
-range<typename sequence_traits<Seq>::iterator_type, typename sequence_traits<Seq>::sentinel_type>
-range_view(Seq& seq) {
-    return make_range(std::begin(seq), std::end(seq));
-}
-
-template <
-    typename Seq,
-    typename Iter = typename sequence_traits<Seq>::iterator_type,
-    typename Size = typename sequence_traits<Seq>::size_type
->
-enable_if_t<is_forward_iterator<Iter>::value, range<Iter>>
-subrange_view(Seq& seq, Size bi, Size ei) {
-    Iter b = std::next(std::begin(seq), bi);
-    Iter e = std::next(b, ei-bi);
-    return make_range(b, e);
+auto canonical_view(const Seq& s) ->
+    range<sentinel_iterator_t<decltype(std::begin(s)), decltype(std::end(s))>>
+{
+    return {make_sentinel_iterator(std::begin(s), std::end(s)), make_sentinel_end(std::begin(s), std::end(s))};
 }
 
 } // namespace util
diff --git a/src/util/rangeutil.hpp b/src/util/rangeutil.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..95200b9c9a5b37c6a02bc236aa1d86bec8dac629
--- /dev/null
+++ b/src/util/rangeutil.hpp
@@ -0,0 +1,100 @@
+#pragma once
+
+/*
+ * Sequence and container utilities compatible
+ * with ranges.
+ */
+
+#include <iterator>
+
+#include <util/meta.hpp>
+#include <util/range.hpp>
+#include <util/transform.hpp>
+
+namespace nest {
+namespace mc {
+namespace util {
+
+// Present a single item as a range
+
+template <typename T>
+range<T*> singleton_view(T& item) {
+    return {&item, &item+1};
+}
+
+template <typename T>
+range<const T*> singleton_view(const T& item) {
+    return {&item, &item+1};
+}
+
+// Non-owning views and subviews
+
+template <typename Seq>
+range<typename sequence_traits<Seq>::iterator_type, typename sequence_traits<Seq>::sentinel_type>
+range_view(Seq& seq) {
+    return make_range(std::begin(seq), std::end(seq));
+}
+
+template <
+    typename Seq,
+    typename Iter = typename sequence_traits<Seq>::iterator_type,
+    typename Size = typename sequence_traits<Seq>::size_type
+>
+enable_if_t<is_forward_iterator<Iter>::value, range<Iter>>
+subrange_view(Seq& seq, Size bi, Size ei) {
+    Iter b = std::next(std::begin(seq), bi);
+    Iter e = std::next(b, ei-bi);
+    return make_range(b, e);
+}
+
+// Append sequence to a container
+
+template <typename Container, typename Seq>
+Container& append(Container &c, const Seq& seq) {
+    auto canon = canonical_view(seq);
+    c.insert(c.end(), std::begin(canon), std::end(canon));
+    return c;
+}
+
+// Assign sequence to a container
+
+template <typename AssignableContainer, typename Seq>
+AssignableContainer& assign(AssignableContainer& c, const Seq& seq) {
+    auto canon = canonical_view(seq);
+    c.assign(std::begin(canon), std::end(canon));
+    return c;
+}
+
+// Assign sequence to a container with transform `proj`
+
+template <typename AssignableContainer, typename Seq, typename Proj>
+AssignableContainer& assign_by(AssignableContainer& c, const Seq& seq, const Proj& proj) {
+    auto canon = canonical_view(transform_view(seq, proj));
+    c.assign(std::begin(canon), std::end(canon));
+    return c;
+}
+
+// Sort in-place
+
+template <typename Seq>
+void sort(Seq& seq) {
+    auto canon = canonical_view(seq);
+    std::sort(std::begin(canon), std::end(canon));
+}
+
+// Sort in-place by projection `proj`
+
+template <typename Seq, typename Proj>
+void sort_by(Seq& seq, const Proj& proj) {
+    using value_type = typename sequence_traits<Seq>::value_type;
+    auto canon = canonical_view(seq);
+
+    std::sort(std::begin(canon), std::end(canon),
+        [&proj](const value_type& a, const value_type& b) {
+            return proj(a) < proj(b);
+        });
+}
+
+} // namespace util
+} // namespace mc
+} // namespace nest
diff --git a/src/util/sentinel.hpp b/src/util/sentinel.hpp
index 8d08ecd41fe77f9c11ed08b8b539536792459c36..eebbfd2382359f388f84567701678713a177feee 100644
--- a/src/util/sentinel.hpp
+++ b/src/util/sentinel.hpp
@@ -179,6 +179,6 @@ sentinel_iterator_t<I, S> make_sentinel_end(const I& i, const S& s) {
     return sentinel_iterator_t<I, S>(s);
 }
 
-}
-}
-}
+} // namespace util
+} // namespace mc
+} // namespace nest
diff --git a/tests/global_communication/test_mpi_gather_all.cpp b/tests/global_communication/test_mpi_gather_all.cpp
index 50fbf4052da14b057c6ed003d51cfa8b13436e93..b5ecf73fa7088357e8bdbcc851d44f6f190d7b7b 100644
--- a/tests/global_communication/test_mpi_gather_all.cpp
+++ b/tests/global_communication/test_mpi_gather_all.cpp
@@ -7,7 +7,7 @@
 
 #include <communication/mpi_global_policy.hpp>
 #include <communication/mpi.hpp>
-#include <util/range.hpp>
+#include <util/rangeutil.hpp>
 
 using namespace nest::mc;
 using namespace nest::mc::communication;
diff --git a/tests/unit/test_cell_group.cpp b/tests/unit/test_cell_group.cpp
index 9b3f6e6a0b13f7338558889e40e47d7fe7ed99c8..a18b9b881988dbadae86550c9649ca1c20146637 100644
--- a/tests/unit/test_cell_group.cpp
+++ b/tests/unit/test_cell_group.cpp
@@ -3,7 +3,7 @@
 #include <cell_group.hpp>
 #include <common_types.hpp>
 #include <fvm_cell.hpp>
-#include <util/range.hpp>
+#include <util/rangeutil.hpp>
 
 #include "../test_common_cells.hpp"
 
diff --git a/tests/unit/test_fvm.cpp b/tests/unit/test_fvm.cpp
index 6d067182f972a0bc65147e8345f3043230d70d9a..45c038bf529f80e3339753662bf26e5a1762c168 100644
--- a/tests/unit/test_fvm.cpp
+++ b/tests/unit/test_fvm.cpp
@@ -5,7 +5,7 @@
 #include <common_types.hpp>
 #include <cell.hpp>
 #include <fvm_cell.hpp>
-#include <util/range.hpp>
+#include <util/rangeutil.hpp>
 
 #include "../test_common_cells.hpp"
 #include "../test_util.hpp"
diff --git a/tests/unit/test_fvm_multi.cpp b/tests/unit/test_fvm_multi.cpp
index fbd4de99b91198128c6b3d0f0098f38f8440984d..df8356418705c51a865a9eb1cbcbf3ce5565c90e 100644
--- a/tests/unit/test_fvm_multi.cpp
+++ b/tests/unit/test_fvm_multi.cpp
@@ -5,7 +5,7 @@
 #include <common_types.hpp>
 #include <cell.hpp>
 #include <fvm_multicell.hpp>
-#include <util/range.hpp>
+#include <util/rangeutil.hpp>
 
 #include "../test_util.hpp"
 #include "../test_common_cells.hpp"
diff --git a/tests/unit/test_probe.cpp b/tests/unit/test_probe.cpp
index cf7562c94fbf9ddcf33e16308d418dbdddd0ebf7..1a2d7f151fe7b347d154c709ddf14ea61e9b114a 100644
--- a/tests/unit/test_probe.cpp
+++ b/tests/unit/test_probe.cpp
@@ -3,7 +3,7 @@
 #include <common_types.hpp>
 #include <cell.hpp>
 #include <fvm_cell.hpp>
-#include <util/range.hpp>
+#include <util/rangeutil.hpp>
 
 TEST(probe, instantiation)
 {
diff --git a/tests/unit/test_range.cpp b/tests/unit/test_range.cpp
index 118a4dc12393e74b74a62f84eee645d0399a490a..3cf2893e451c9674e85ba7ffa384a24e3a6eb6f5 100644
--- a/tests/unit/test_range.cpp
+++ b/tests/unit/test_range.cpp
@@ -14,6 +14,7 @@
 #include <util/counter.hpp>
 #include <util/meta.hpp>
 #include <util/range.hpp>
+#include <util/rangeutil.hpp>
 #include <util/sentinel.hpp>
 
 using namespace nest::mc;
@@ -212,7 +213,6 @@ TYPED_TEST_P(counter_range, extreme_size) {
     auto range = util::make_range(l, r);
     EXPECT_FALSE(range.empty());
     EXPECT_EQ(std::numeric_limits<unsigned_int_type>::max(), range.size());
-
 }
 
 
@@ -226,7 +226,6 @@ TYPED_TEST_P(counter_range, size) {
     auto range = util::make_range(l, r);
     EXPECT_FALSE(range.empty());
     EXPECT_EQ(6u, range.size());
-
 }
 
 TYPED_TEST_P(counter_range, at) {
@@ -270,6 +269,36 @@ using signed_int_types = ::testing::Types<signed char, short,
 
 INSTANTIATE_TYPED_TEST_CASE_P(int_types, counter_range, int_types);
 
+TEST(range, assign) {
+    const char *cstr = "howdy";
+    std::string text = "pardner";
+
+    util::assign(text, util::make_range(cstr, null_terminated));
+    EXPECT_EQ("howdy", text);
+
+    const std::vector<char> vstr = {'x', 'y', 'z', 'z', 'y'};
+    util::assign(text, vstr);
+    EXPECT_EQ("xyzzy", text);
+
+    util::assign_by(text, vstr,
+        [](char c) { return c=='z'? '1': '0'; });
+    EXPECT_EQ("00110", text);
+}
+
+TEST(range, sort) {
+    char cstr[] = "howdy";
+
+    auto cstr_range = util::make_range(std::begin(cstr), null_terminated);
+
+    // simple sort
+    util::sort(cstr_range);
+    EXPECT_EQ(std::string("dhowy"), cstr);
+
+    // reverse sort by transform c to -c
+    util::sort_by(cstr_range, [](char c) { return -c; });
+    EXPECT_EQ(std::string("ywohd"), cstr);
+}
+
 #ifdef WITH_TBB
 
 TEST(range, tbb_split) {
diff --git a/tests/validation/validate_soma.cpp b/tests/validation/validate_soma.cpp
index 8952ba30c93d5c7121fa09c6092e281d39564eb4..05ff783e37e987231dc5cc65e040119ffe7b3b9e 100644
--- a/tests/validation/validate_soma.cpp
+++ b/tests/validation/validate_soma.cpp
@@ -4,7 +4,7 @@
 #include <common_types.hpp>
 #include <cell.hpp>
 #include <fvm_cell.hpp>
-#include <util/range.hpp>
+#include <util/rangeutil.hpp>
 
 #include "gtest.h"
 
diff --git a/tests/validation/validate_synapses.cpp b/tests/validation/validate_synapses.cpp
index d1de3df06945b33466ccbbc105d412196c0a5f0b..62b91841ab37fd626bde4a7cf6a2e03a096d1e90 100644
--- a/tests/validation/validate_synapses.cpp
+++ b/tests/validation/validate_synapses.cpp
@@ -8,7 +8,7 @@
 #include <cell_group.hpp>
 #include <fvm_cell.hpp>
 #include <mechanism_interface.hpp>
-#include <util/range.hpp>
+#include <util/rangeutil.hpp>
 
 #include "gtest.h"
 #include "../test_util.hpp"