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);