diff --git a/src/algorithms.hpp b/src/algorithms.hpp
index bc25b98b84518e0a0c444bf6163bd05b8ed37711..8ac62055f351212fb75c72657fa6157463450f45 100644
--- a/src/algorithms.hpp
+++ b/src/algorithms.hpp
@@ -5,6 +5,7 @@
 #include <algorithm>
 #include <numeric>
 #include <type_traits>
+#include <vector>
 
 /*
  * Some simple wrappers around stl algorithms to improve readability of code
@@ -117,6 +118,89 @@ namespace algorithms{
         return true;
     }
 
+    template<typename C>
+    bool has_contiguous_segments(const C &parent_index)
+    {
+        static_assert(
+            std::is_integral<typename C::value_type>::value,
+            "integral type required"
+        );
+
+        if (!is_minimal_degree(parent_index)) {
+            return false;
+        }
+
+        std::vector<bool> is_leaf(parent_index.size(), false);
+
+        for (std::size_t i = 1; i < parent_index.size(); ++i) {
+            auto p = parent_index[i];
+            if (is_leaf[p]) {
+                return false;
+            }
+
+            if (p != i-1) {
+                // we have a branch and i-1 is a leaf node
+                is_leaf[i-1] = true;
+            }
+        }
+
+        return true;
+    }
+
+    template<typename C>
+    std::vector<typename C::value_type> child_count(const C &parent_index)
+    {
+        static_assert(
+            std::is_integral<typename C::value_type>::value,
+            "integral type required"
+        );
+
+        std::vector<typename C::value_type> count(parent_index.size(), 0);
+        for (std::size_t i = 1; i < parent_index.size(); ++i) {
+            ++count[parent_index[i]];
+        }
+
+        return count;
+    }
+
+    template<typename C, bool CheckStrict = true>
+    std::vector<typename C::value_type> branches(const C &parent_index)
+    {
+        static_assert(
+            std::is_integral<typename C::value_type>::value,
+            "integral type required"
+        );
+
+        if (CheckStrict && !has_contiguous_segments(parent_index)) {
+            throw std::invalid_argument(
+                "parent_index has not contiguous branch numbering"
+            );
+        }
+
+        auto num_child = child_count(parent_index);
+        std::vector<typename C::value_type> branch_runs(
+            parent_index.size(), 0
+        );
+
+        std::size_t num_branches = (num_child[0] == 1) ? 1 : 0;
+        for (std::size_t i = 1; i < parent_index.size(); ++i) {
+            auto p = parent_index[i];
+            if (num_child[p] > 1) {
+                ++num_branches;
+            }
+
+            branch_runs[i] = num_branches;
+        }
+
+        return branch_runs;
+    }
+
+    template<typename C>
+    std::vector<typename C::value_type> branches_fast(const C &parent_index)
+    {
+        return branches<C,false>(parent_index);
+    }
+
 } // namespace algorithms
 } // namespace mc
 } // namespace nest
diff --git a/src/point.hpp b/src/point.hpp
index cf74f3238d705e4e28c9430bb42cc85aa2b1ee14..3b048bb3db7fb580443e019c98292821f715ffb2 100644
--- a/src/point.hpp
+++ b/src/point.hpp
@@ -73,6 +73,20 @@ dot(
     return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z;
 }
 
+template<typename T>
+bool operator==(const point<T> &rhs, const point<T> &lhs)
+{
+    return (rhs.x == lhs.x) &&
+           (rhs.y == lhs.y) &&
+           (rhs.z == lhs.z);
+}
+
+template<typename T>
+bool operator!=(const point<T> &rhs, const point<T> &lhs)
+{
+    return !(rhs == lhs);
+}
+
 } // namespace mc
 } // namespace nest
 
@@ -81,5 +95,3 @@ std::ostream& operator << (std::ostream& o, nest::mc::point<T> const& p)
 {
     return o << "[" << p.x << ", " << p.y << ", " << p.z << "]";
 }
-
-
diff --git a/src/swcio.cpp b/src/swcio.cpp
index 98db848e2b4768d59399a3340c0d3611104fb4e9..f96676449d9526154d4f7d0cd3531da62bba715e 100644
--- a/src/swcio.cpp
+++ b/src/swcio.cpp
@@ -4,7 +4,10 @@
 #include <sstream>
 #include <unordered_set>
 
+#include <algorithms.hpp>
+#include <point.hpp>
 #include <swcio.hpp>
+#include <util.hpp>
 
 namespace nest {
 namespace mc {
@@ -32,7 +35,8 @@ void swc_record::check_consistency() const
 {
     // Check record type as well; enum's do not offer complete type safety,
     // since you can cast anything that fits to its underlying type
-    if (type_ < 0 || type_ > custom) {
+    if (static_cast<int>(type_) < 0 ||
+        static_cast<int>(type_) > static_cast<int>(kind::custom)) {
         throw std::invalid_argument("unknown record type");
     }
 
@@ -65,7 +69,7 @@ std::ostream &operator<<(std::ostream &os, const swc_record &record)
 {
     // output in one-based indexing
     os << record.id_+1 << " "
-       << record.type_ << " "
+       << static_cast<int>(record.type_) << " "
        << std::setprecision(7) << record.x_ << " "
        << std::setprecision(7) << record.y_ << " "
        << std::setprecision(7) << record.z_ << " "
@@ -158,10 +162,10 @@ swc_record swc_parser::parse_record(std::istringstream &is)
 {
     auto id = parse_value_strict<int>(is, *this);
     auto type = parse_value_strict<swc_record::kind>(is, *this);
-    auto x = parse_value_strict<float>(is, *this);
-    auto y = parse_value_strict<float>(is, *this);
-    auto z = parse_value_strict<float>(is, *this);
-    auto r = parse_value_strict<float>(is, *this);
+    auto x = parse_value_strict<swc_record::coord_type>(is, *this);
+    auto y = parse_value_strict<swc_record::coord_type>(is, *this);
+    auto z = parse_value_strict<swc_record::coord_type>(is, *this);
+    auto r = parse_value_strict<swc_record::coord_type>(is, *this);
     auto parent_id = parse_value_strict<swc_record::id_type>(is, *this);
 
     // Convert to zero-based, leaving parent_id as-is if -1
@@ -177,26 +181,26 @@ swc_record_range_clean::swc_record_range_clean(std::istream &is)
 {
     std::unordered_set<swc_record::id_type> ids;
 
-    std::size_t          num_trees = 0;
+    std::size_t         num_trees = 0;
     swc_record::id_type last_id   = -1;
-    bool                 needsort  = false;
+    bool                needsort  = false;
 
     swc_record curr_record;
-    for (auto c : swc_get_records<swc_io_raw>(is)) {
-        if (c.parent() == -1 && ++num_trees > 1) {
+    for (auto r : swc_get_records<swc_io_raw>(is)) {
+        if (r.parent() == -1 && ++num_trees > 1) {
             // only a single tree is allowed
             break;
         }
 
-        auto inserted = ids.insert(c.id());
+        auto inserted = ids.insert(r.id());
         if (inserted.second) {
             // not a duplicate; insert record
-            records_.push_back(c);
-            if (!needsort && c.id() < last_id) {
+            records_.push_back(r);
+            if (!needsort && r.id() < last_id) {
                 needsort = true;
             }
 
-            last_id = c.id();
+            last_id = r.id();
         }
     }
 
@@ -207,13 +211,110 @@ swc_record_range_clean::swc_record_range_clean(std::istream &is)
     // Renumber records if necessary
     std::map<swc_record::id_type, swc_record::id_type> idmap;
     swc_record::id_type next_id = 0;
-    for (auto &c : records_) {
-        if (c.id() != next_id) {
-            c.renumber(next_id, idmap);
+    for (auto &r : records_) {
+        if (r.id() != next_id) {
+            r.renumber(next_id, idmap);
         }
 
         ++next_id;
     }
+
+    // Reject if branches are not contiguously numbered
+    std::vector<swc_record::id_type> parent_list = { 0 };
+    for (std::size_t i = 1; i < records_.size(); ++i) {
+        parent_list.push_back(records_[i].parent());
+    }
+
+    if (!nest::mc::algorithms::has_contiguous_segments(parent_list)) {
+        throw swc_parse_error("branches are not contiguously numbered", 0);
+    }
+}
+
+//
+// Convenience functions for returning the radii and the coordinates of a series
+// of swc records
+//
+static std::vector<swc_record::coord_type>
+swc_radii(const std::vector<swc_record> &records)
+{
+    std::vector<swc_record::coord_type> radii;
+    for (const auto &r : records) {
+        radii.push_back(r.radius());
+    }
+
+    return radii;
+}
+
+static std::vector<nest::mc::point<swc_record::coord_type> >
+swc_points(const std::vector<swc_record> &records)
+{
+    std::vector<nest::mc::point<swc_record::coord_type> > points;
+    for (const auto &r : records) {
+        points.push_back(r.coord());
+    }
+
+    return points;
+}
+
+static void make_cable(cell &cell,
+                       const std::vector<swc_record::id_type> &branch_index,
+                       const std::vector<swc_record> &branch_run)
+{
+    auto new_parent = branch_index[branch_run.back().id()] - 1;
+    cell.add_cable(new_parent, nest::mc::segmentKind::dendrite,
+                   swc_radii(branch_run), swc_points(branch_run));
+}
+
+cell swc_read_cell(std::istream &is)
+{
+    cell newcell;
+    std::vector<swc_record::id_type> parent_list;
+    std::vector<swc_record> swc_records;
+    for (const auto &r : swc_get_records<swc_io_clean>(is)) {
+        swc_records.push_back(r);
+        parent_list.push_back(r.parent());
+    }
+
+    // The parent of soma must be 0
+    if (!parent_list.empty()) {
+        parent_list[0] = 0;
+    }
+
+    auto branch_index = nest::mc::algorithms::branches(parent_list);
+    std::vector<swc_record> branch_run;
+
+    branch_run.reserve(parent_list.size());
+    auto last_branch_point = branch_index[0];
+    for (auto i = 0u; i < swc_records.size(); ++i) {
+        if (branch_index[i] != last_branch_point) {
+            // New branch encountered; add to cell the current one
+            const auto &p = branch_run.back();
+            if (p.parent() == -1) {
+                // This is a soma
+                newcell.add_soma(p.radius(), p.coord());
+                last_branch_point = i;
+            } else {
+                last_branch_point = i - 1;
+                make_cable(newcell, branch_index, branch_run);
+            }
+
+            // Reset the branch run
+            branch_run.clear();
+            if (p.parent() != -1) {
+                // Add parent of the current cell to the branch,
+                // if not branching from soma
+                branch_run.push_back(swc_records[parent_list[i]]);
+            }
+        }
+
+        branch_run.push_back(swc_records[i]);
+    }
+
+    if (!branch_run.empty()) {
+        make_cable(newcell, branch_index, branch_run);
+    }
+
+    return newcell;
 }
 
 } // namespace io
diff --git a/src/swcio.hpp b/src/swcio.hpp
index 0486a2b511e7afcb13fbc13f7a5977fa4f4db6a4..a58bbac9aee9a32c03ae9bb33eb9289782a537b2 100644
--- a/src/swcio.hpp
+++ b/src/swcio.hpp
@@ -6,6 +6,9 @@
 #include <string>
 #include <vector>
 
+#include <cell.hpp>
+#include <point.hpp>
+
 namespace nest {
 namespace mc {
 namespace io {
@@ -14,12 +17,10 @@ class swc_record
 {
 public:
     using id_type = int;
+    using coord_type = double;
 
-    // FIXME: enum's are not completely type-safe, since they can accept
-    // anything that can be casted to their underlying type.
-    //
     // More on SWC files: http://research.mssm.edu/cnic/swc.html
-    enum kind {
+    enum class kind {
         undefined = 0,
         soma,
         axon,
@@ -31,9 +32,9 @@ public:
     };
 
     // swc records assume zero-based indexing; root's parent remains -1
-    swc_record(kind type, int id,
-                float x, float y, float z, float r,
-                int parent_id)
+    swc_record(swc_record::kind type, int id,
+               coord_type x, coord_type y, coord_type z, coord_type r,
+               int parent_id)
         : type_(type)
         , id_(id)
         , x_(x)
@@ -46,7 +47,7 @@ public:
     }
 
     swc_record()
-        : type_(swc_record::undefined)
+        : type_(swc_record::kind::undefined)
         , id_(0)
         , x_(0)
         , y_(0)
@@ -122,41 +123,46 @@ public:
         return parent_id_;
     }
 
-    float x() const
+    coord_type x() const
     {
         return x_;
     }
 
-    float y() const
+    coord_type y() const
     {
         return y_;
     }
 
-    float z() const
+    coord_type z() const
     {
         return z_;
     }
 
-    float radius() const
+    coord_type radius() const
     {
         return r_;
     }
 
-    float diameter() const
+    coord_type diameter() const
     {
         return 2*r_;
     }
 
+    nest::mc::point<coord_type> coord() const
+    {
+        return nest::mc::point<coord_type>(x_, y_, z_);
+    }
+
     void renumber(id_type new_id, std::map<id_type, id_type> &idmap);
 
 private:
     void check_consistency() const;
 
-    kind type_;         // record type
-    id_type id_;        // record id
-    float x_, y_, z_;   // record coordinates
-    float r_;           // record radius
-    id_type parent_id_; // record parent's id
+    kind type_;             // record type
+    id_type id_;            // record id
+    coord_type x_, y_, z_;  // record coordinates
+    coord_type r_;          // record radius
+    id_type parent_id_;     // record parent's id
 };
 
 
@@ -401,12 +407,13 @@ struct swc_io_clean
 };
 
 template<typename T = swc_io_clean>
- typename T::record_range_type swc_get_records(std::istream &is)
+typename T::record_range_type swc_get_records(std::istream &is)
 {
     return typename T::record_range_type(is);
 }
 
+cell swc_read_cell(std::istream &is);
+
 } // namespace io
 } // namespace mc
 } // namespace nest
-
diff --git a/tests/test_algorithms.cpp b/tests/test_algorithms.cpp
index cfe058a3c8b92d930c739fbbde3f5a3bad6f634c..6503c07d9a413bf2e90f8cbf151b0df1e3e5949b 100644
--- a/tests/test_algorithms.cpp
+++ b/tests/test_algorithms.cpp
@@ -169,3 +169,196 @@ TEST(algorithms, is_positive)
         )
     );
 }
+
+TEST(algorithms, has_contiguous_segments)
+{
+    //
+    //       0
+    //       |
+    //       1
+    //       |
+    //       2
+    //      /|\.
+    //     3 7 4
+    //    /     \.
+    //   5       6
+    //
+    EXPECT_FALSE(
+        nest::mc::algorithms::has_contiguous_segments(
+            std::vector<int>{0, 0, 1, 2, 2, 3, 4, 2}
+        )
+    );
+
+    //
+    //       0
+    //       |
+    //       1
+    //       |
+    //       2
+    //      /|\.
+    //     3 6 5
+    //    /     \.
+    //   4       7
+    //
+    EXPECT_FALSE(
+        nest::mc::algorithms::has_contiguous_segments(
+            std::vector<int>{0, 0, 1, 2, 3, 2, 2, 5}
+        )
+    );
+
+    //
+    //       0
+    //       |
+    //       1
+    //       |
+    //       2
+    //      /|\.
+    //     3 7 5
+    //    /     \.
+    //   4       6
+    //
+    EXPECT_TRUE(
+        nest::mc::algorithms::has_contiguous_segments(
+            std::vector<int>{0, 0, 1, 2, 3, 2, 5, 2}
+        )
+    );
+
+    //
+    //         0
+    //         |
+    //         1
+    //        / \.
+    //       2   7
+    //      / \.
+    //     3   5
+    //    /     \.
+    //   4       6
+    //
+    EXPECT_TRUE(
+        nest::mc::algorithms::has_contiguous_segments(
+            std::vector<int>{0, 0, 1, 2, 3, 2, 5, 1}
+        )
+    );
+
+    // Soma-only list
+    EXPECT_TRUE(
+        nest::mc::algorithms::has_contiguous_segments(
+            std::vector<int>{0}
+        )
+    );
+
+    // Empty list
+    EXPECT_TRUE(
+        nest::mc::algorithms::has_contiguous_segments(
+            std::vector<int>{}
+        )
+    );
+}
+
+TEST(algorithms, child_count)
+{
+    {
+        //
+        //        0
+        //       /|\.
+        //      1 4 6
+        //     /  |  \.
+        //    2   5   7
+        //   /         \.
+        //  3           8
+        //             / \.
+        //            9   11
+        //           /     \.
+        //          10      12
+        //                   \.
+        //                    13
+        //
+        std::vector<int> parent_index =
+            { 0, 0, 1, 2, 0, 4, 0, 6, 7, 8, 9, 8, 11, 12 };
+        std::vector<int> expected_child_count =
+            { 3, 1, 1, 0, 1, 0, 1, 1, 2, 1, 0, 1, 1, 0 };
+
+        // auto count = nest::mc::algorithms::child_count(parent_index);
+        EXPECT_EQ(expected_child_count,
+                  nest::mc::algorithms::child_count(parent_index));
+    }
+
+}
+
+TEST(algorithms, branches)
+{
+    using namespace nest::mc;
+
+    {
+        //
+        //        0
+        //       /|\.
+        //      1 4 6
+        //     /  |  \.
+        //    2   5   7
+        //   /         \.
+        //  3           8
+        //             / \.
+        //            9   11
+        //           /     \.
+        //          10      12
+        //                   \.
+        //                    13
+        //
+        std::vector<int> parent_index =
+            { 0, 0, 1, 2, 0, 4, 0, 6, 7, 8, 9, 8, 11, 12 };
+        std::vector<int> expected_branches =
+            { 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5 };
+
+        auto actual_branches = algorithms::branches_fast(parent_index);
+        EXPECT_EQ(expected_branches, actual_branches);
+    }
+
+    {
+        //
+        //    0
+        //    |
+        //    1
+        //    |
+        //    2
+        //    |
+        //    3
+        //
+        std::vector<int> parent_index =
+            { 0, 0, 1, 2 };
+        std::vector<int> expected_branches =
+            { 0, 1, 1, 1 };
+
+        auto actual_branches = algorithms::branches_fast(parent_index);
+        EXPECT_EQ(expected_branches, actual_branches);
+    }
+
+    {
+        //
+        //    0
+        //    |
+        //    1
+        //    |
+        //    2
+        //   / \.
+        //  3   4
+        //       \.
+        //        5
+        //
+        std::vector<int> parent_index =
+            { 0, 0, 1, 2, 2, 4 };
+        std::vector<int> expected_branches =
+            { 0, 1, 1, 2, 3, 3 };
+
+        auto actual_branches = algorithms::branches_fast(parent_index);
+        EXPECT_EQ(expected_branches, actual_branches);
+    }
+
+    {
+        std::vector<int> parent_index = { 0 };
+        std::vector<int> expected_branches = { 0 };
+
+        auto actual_branches = algorithms::branches_fast(parent_index);
+        EXPECT_EQ(expected_branches, actual_branches);
+    }
+}
diff --git a/tests/test_point.cpp b/tests/test_point.cpp
index 9666a1387f895d408778f40afc6b07db5363bec6..b5bfeb9c1783a6c921ca97f3eb6ae4afd535c311 100644
--- a/tests/test_point.cpp
+++ b/tests/test_point.cpp
@@ -12,6 +12,9 @@ TEST(point, construction)
     {
         // default constructor
         point<float> p;
+
+        EXPECT_FALSE(p.is_set());
+
         // expect NaN, which returns false when comparing for equality
         EXPECT_NE(p.x, p.x);
         EXPECT_NE(p.y, p.y);
@@ -36,10 +39,7 @@ TEST(point, construction)
 
         // copy constructor
         auto p2 = p1;
-
-        EXPECT_EQ(p1.x, p2.x);
-        EXPECT_EQ(p1.y, p2.y);
-        EXPECT_EQ(p1.z, p2.z);
+        EXPECT_EQ(p1, p2);
     }
 }
 
@@ -64,9 +64,7 @@ TEST(point, addition)
 
     auto p = p1 + p2;
 
-    EXPECT_EQ(p.x, 2);
-    EXPECT_EQ(p.y, 4);
-    EXPECT_EQ(p.z, 6);
+    EXPECT_EQ(point<double>(2, 4, 6), p);
 }
 
 TEST(point, subtraction)
@@ -77,9 +75,7 @@ TEST(point, subtraction)
 
     auto p = p1 - p2;
 
-    EXPECT_EQ(p.x, 0);
-    EXPECT_EQ(p.y, 0);
-    EXPECT_EQ(p.z, 0);
+    EXPECT_EQ(point<double>(0, 0, 0), p);
 }
 
 TEST(point, scalar_prod)
@@ -89,9 +85,7 @@ TEST(point, scalar_prod)
 
     auto p = 0.5 * p1;
 
-    EXPECT_EQ(p.x, 0.5);
-    EXPECT_EQ(p.y, 1.0);
-    EXPECT_EQ(p.z, 1.5);
+    EXPECT_EQ(point<double>(0.5, 1.0, 1.5), p);
 }
 
 TEST(point, norm)
@@ -114,4 +108,3 @@ TEST(point, dot)
 
     EXPECT_EQ(dot(p1,p2), 2.);
 }
-
diff --git a/tests/test_swcio.cpp b/tests/test_swcio.cpp
index 3de060ed4a69c446167d07c372ee0c872255ee30..17a836c2065b0a56954d26fa3e1297cbfc16de45 100644
--- a/tests/test_swcio.cpp
+++ b/tests/test_swcio.cpp
@@ -3,10 +3,12 @@
 #include <iostream>
 #include <fstream>
 #include <numeric>
+#include <type_traits>
 #include <vector>
 
 #include "gtest.h"
 
+#include <cell.hpp>
 #include <swcio.hpp>
 
 // SWC tests
@@ -36,43 +38,43 @@ TEST(swc_record, construction)
     {
         // invalid id
         EXPECT_THROW(swc_record record(
-                         swc_record::custom, -3, 1., 1., 1., 1., 5),
+                         swc_record::kind::custom, -3, 1., 1., 1., 1., 5),
                      std::invalid_argument);
     }
 
     {
         // invalid parent id
         EXPECT_THROW(swc_record record(
-                         swc_record::custom, 0, 1., 1., 1., 1., -5),
+                         swc_record::kind::custom, 0, 1., 1., 1., 1., -5),
                      std::invalid_argument);
     }
 
     {
         // invalid radius
         EXPECT_THROW(swc_record record(
-                         swc_record::custom, 0, 1., 1., 1., -1., -1),
+                         swc_record::kind::custom, 0, 1., 1., 1., -1., -1),
                      std::invalid_argument);
     }
 
     {
         // parent_id > id
         EXPECT_THROW(swc_record record(
-                         swc_record::custom, 0, 1., 1., 1., 1., 2),
+                         swc_record::kind::custom, 0, 1., 1., 1., 1., 2),
                      std::invalid_argument);
     }
 
     {
         // parent_id == id
         EXPECT_THROW(swc_record record(
-                         swc_record::custom, 0, 1., 1., 1., 1., 0),
+                         swc_record::kind::custom, 0, 1., 1., 1., 1., 0),
                      std::invalid_argument);
     }
 
     {
         // check standard construction by value
-        swc_record record(swc_record::custom, 0, 1., 1., 1., 1., -1);
+        swc_record record(swc_record::kind::custom, 0, 1., 1., 1., 1., -1);
         EXPECT_EQ(record.id(), 0);
-        EXPECT_EQ(record.type(), swc_record::custom);
+        EXPECT_EQ(record.type(), swc_record::kind::custom);
         EXPECT_EQ(record.x(), 1.);
         EXPECT_EQ(record.y(), 1.);
         EXPECT_EQ(record.z(), 1.);
@@ -83,7 +85,7 @@ TEST(swc_record, construction)
 
     {
         // check copy constructor
-        swc_record record_orig(swc_record::custom, 0, 1., 1., 1., 1., -1);
+        swc_record record_orig(swc_record::kind::custom, 0, 1., 1., 1., 1., -1);
         swc_record record(record_orig);
         expect_record_equals(record_orig, record);
     }
@@ -95,9 +97,9 @@ TEST(swc_record, comparison)
 
     {
         // check comparison operators
-        swc_record record0(swc_record::custom, 0, 1., 1., 1., 1., -1);
-        swc_record record1(swc_record::custom, 0, 2., 3., 4., 5., -1);
-        swc_record record2(swc_record::custom, 1, 2., 3., 4., 5., -1);
+        swc_record record0(swc_record::kind::custom, 0, 1., 1., 1., 1., -1);
+        swc_record record1(swc_record::kind::custom, 0, 2., 3., 4., 5., -1);
+        swc_record record2(swc_record::kind::custom, 1, 2., 3., 4., 5., -1);
         EXPECT_EQ(record0, record1);
         EXPECT_LT(record0, record2);
         EXPECT_GT(record2, record1);
@@ -131,6 +133,31 @@ TEST(swc_parser, invalid_input)
         swc_record record;
         EXPECT_THROW(is >> record, swc_parse_error);
     }
+
+    {
+        // Non-contiguous numbering in branches is considered invalid
+        //        1
+        //       / \
+        //      2   3
+        //     /
+        //    4
+        std::stringstream is;
+        is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
+        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "3 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "4 1 14.566132 34.873772 7.857000 0.717830 2\n";
+
+        std::vector<swc_record> records;
+        try {
+            for (auto c : swc_get_records<swc_io_clean>(is)) {
+                records.push_back(std::move(c));
+            }
+
+            FAIL() << "expected swc_parse_error, none was thrown\n";
+        } catch (const swc_parse_error &e) {
+            SUCCEED();
+        }
+    }
 }
 
 
@@ -162,7 +189,7 @@ TEST(swc_parser, valid_input)
         swc_record record;
         EXPECT_NO_THROW(is >> record);
         EXPECT_EQ(0, record.id());    // zero-based indexing
-        EXPECT_EQ(swc_record::soma, record.type());
+        EXPECT_EQ(swc_record::kind::soma, record.type());
         EXPECT_FLOAT_EQ(14.566132, record.x());
         EXPECT_FLOAT_EQ(34.873772, record.y());
         EXPECT_FLOAT_EQ( 7.857000, record.z());
@@ -173,9 +200,9 @@ TEST(swc_parser, valid_input)
     {
         // check valid input with a series of records
         std::vector<swc_record> records_orig = {
-            swc_record(swc_record::soma, 0,
+            swc_record(swc_record::kind::soma, 0,
                         14.566132, 34.873772, 7.857000, 0.717830, -1),
-            swc_record(swc_record::dendrite, 1,
+            swc_record(swc_record::kind::dendrite, 1,
                         14.566132+1, 34.873772+1, 7.857000+1, 0.717830+1, -1)
         };
 
@@ -225,37 +252,37 @@ TEST(swc_parser, input_cleaning)
         // Check duplicates
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
 
-        EXPECT_EQ(2u, swc_get_records(is).size());
+        EXPECT_EQ(2u, swc_get_records<swc_io_clean>(is).size());
     }
 
     {
         // Check multiple trees
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
         is << "3 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "4 2 14.566132 34.873772 7.857000 0.717830 1\n";
 
-        auto records = swc_get_records(is);
+        auto records = swc_get_records<swc_io_clean>(is);
         EXPECT_EQ(2u, records.size());
     }
 
     {
         // Check unsorted input
         std::stringstream is;
-        is << "3 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "3 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "4 2 14.566132 34.873772 7.857000 0.717830 1\n";
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
 
         std::array<swc_record::id_type, 4> expected_id_list = {{ 0, 1, 2, 3 }};
 
         auto expected_id = expected_id_list.cbegin();
-        for (auto c : swc_get_records(is)) {
+        for (auto c : swc_get_records<swc_io_clean>(is)) {
             EXPECT_EQ(*expected_id, c.id());
             ++expected_id;
         }
@@ -268,11 +295,11 @@ TEST(swc_parser, input_cleaning)
         // Check holes in numbering
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "21 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "31 1 14.566132 34.873772 7.857000 0.717830 21\n";
-        is << "41 1 14.566132 34.873772 7.857000 0.717830 21\n";
-        is << "51 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "61 1 14.566132 34.873772 7.857000 0.717830 51\n";
+        is << "21 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "31 2 14.566132 34.873772 7.857000 0.717830 21\n";
+        is << "41 2 14.566132 34.873772 7.857000 0.717830 21\n";
+        is << "51 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "61 2 14.566132 34.873772 7.857000 0.717830 51\n";
 
         std::array<swc_record::id_type, 6> expected_id_list =
             {{ 0, 1, 2, 3, 4, 5 }};
@@ -281,7 +308,7 @@ TEST(swc_parser, input_cleaning)
 
         auto expected_id = expected_id_list.cbegin();
         auto expected_parent = expected_parent_list.cbegin();
-        for (auto c : swc_get_records(is)) {
+        for (auto c : swc_get_records<swc_io_clean>(is)) {
             EXPECT_EQ(*expected_id, c.id());
             EXPECT_EQ(*expected_parent, c.parent());
             ++expected_id;
@@ -302,9 +329,9 @@ TEST(swc_record_ranges, raw)
         // Check valid usage
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "3 1 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "3 2 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "4 2 14.566132 34.873772 7.857000 0.717830 1\n";
 
         std::vector<swc_record> records;
         for (auto c : swc_get_records<swc_io_raw>(is)) {
@@ -356,9 +383,9 @@ TEST(swc_record_ranges, raw)
         // Check parse error context
         std::stringstream is;
         is << "1 1 14.566132 34.873772 7.857000 0.717830 -1\n";
-        is << "2 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "2 2 14.566132 34.873772 7.857000 0.717830 1\n";
         is << "3 10 14.566132 34.873772 7.857000 0.717830 1\n";
-        is << "4 1 14.566132 34.873772 7.857000 0.717830 1\n";
+        is << "4 2 14.566132 34.873772 7.857000 0.717830 1\n";
 
         std::vector<swc_record> records;
         try {
@@ -379,3 +406,84 @@ TEST(swc_record_ranges, raw)
         EXPECT_TRUE(swc_get_records<swc_io_clean>(is).empty());
     }
 }
+
+TEST(swc_io, cell_construction)
+{
+    using namespace nest::mc;
+
+    {
+        //
+        //    0
+        //    |
+        //    1
+        //    |
+        //    2
+        //   / \.
+        //  3   4
+        //       \.
+        //        5
+        //
+
+        std::stringstream is;
+        is << "1 1 0 0 0 2.1 -1\n";
+        is << "2 2 0.1 1.2 1.2 1.3 1\n";
+        is << "3 2 1.0 2.0 2.2 1.1 2\n";
+        is << "4 2 1.5 3.3 1.3 2.2 3\n";
+        is << "5 2 2.5 5.3 2.5 0.7 3\n";
+        is << "6 2 3.5 2.3 3.7 3.4 5\n";
+
+        using point_type = point<double>;
+        std::vector<point_type> points = {
+            { 0.0, 0.0, 0.0 },
+            { 0.1, 1.2, 1.2 },
+            { 1.0, 2.0, 2.2 },
+            { 1.5, 3.3, 1.3 },
+            { 2.5, 5.3, 2.5 },
+            { 3.5, 2.3, 3.7 },
+        };
+
+        cell cell = io::swc_read_cell(is);
+        EXPECT_TRUE(cell.has_soma());
+        EXPECT_EQ(4, 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());
+        EXPECT_EQ(norm(points[2]-points[4]) + norm(points[4]-points[5]),
+                  cell.cable(3)->length());
+
+
+        // Check each segment separately
+        EXPECT_TRUE(cell.segment(0)->is_soma());
+        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) {
+            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());
+
+
+        // Check the radii
+        EXPECT_EQ(1.3, cell.cable(1)->radius(0));
+        EXPECT_EQ(1.1, cell.cable(1)->radius(1));
+
+        EXPECT_EQ(1.1, cell.cable(2)->radius(0));
+        EXPECT_EQ(2.2, cell.cable(2)->radius(1));
+
+        EXPECT_EQ(1.1, cell.cable(3)->radius(0));
+        EXPECT_EQ(3.4, cell.cable(3)->radius(1));
+
+        auto len_ratio = norm(points[2]-points[4]) / cell.cable(3)->length();
+        EXPECT_NEAR(.7, cell.cable(3)->radius(len_ratio), 1e-15);
+
+        // Double-check radii at joins are equal
+        EXPECT_EQ(cell.cable(1)->radius(1),
+                  cell.cable(2)->radius(0));
+
+        EXPECT_EQ(cell.cable(1)->radius(1),
+                  cell.cable(3)->radius(0));
+    }
+}
diff --git a/tests/test_tree.cpp b/tests/test_tree.cpp
index 9bb320d1e4cf5f1b0e8b1f5e320384f32935d728..a9b923170e14a42edab6a1deb070cb380e8d2378 100644
--- a/tests/test_tree.cpp
+++ b/tests/test_tree.cpp
@@ -30,8 +30,17 @@ TEST(cell_tree, from_parent_index) {
         EXPECT_EQ(tree.num_segments(), 1u);
         EXPECT_EQ(tree.num_children(0), 0u);
     }
-    // tree with two segments off the root node
+
     {
+        //
+        //        0               0
+        //       / \             / \
+        //      1   4      =>   1   2
+        //     /     \
+        //    2       5
+        //   /
+        //  3
+        //
         std::vector<int> parent_index =
             {0, 0, 1, 2, 0, 4};
         cell_tree tree(parent_index);
@@ -43,9 +52,18 @@ TEST(cell_tree, from_parent_index) {
         EXPECT_EQ(tree.num_children(2), 0u);
     }
     {
-        // tree with three segments off the root node
+        //
+        //        0               0
+        //       /|\             /|\
+        //      1 4 6      =>   1 2 3
+        //     /  |  \
+        //    2   5   7
+        //   /         \
+        //  3           8
+        //
         std::vector<int> parent_index =
             {0, 0, 1, 2, 0, 4, 0, 6, 7, 8};
+
         cell_tree tree(parent_index);
         EXPECT_EQ(tree.num_segments(), 4u);
         // the root has 3 children
@@ -54,9 +72,29 @@ TEST(cell_tree, from_parent_index) {
         EXPECT_EQ(tree.num_children(1), 0u);
         EXPECT_EQ(tree.num_children(2), 0u);
         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));
     }
     {
-        // tree with three segments off the root node, and another 2 segments off of the third branch from the root node
+        //
+        //        0               0
+        //       /|\             /|\
+        //      1 4 6      =>   1 2 3
+        //     /  |  \             / \
+        //    2   5   7           4   5
+        //   /         \
+        //  3           8
+        //             / \
+        //            9   11
+        //           /     \
+        //          10     12
+        //                   \
+        //                   13
+        //
         std::vector<int> parent_index =
             {0, 0, 1, 2, 0, 4, 0, 6, 7, 8, 9, 8, 11, 12};
         cell_tree tree(parent_index);
@@ -70,6 +108,14 @@ TEST(cell_tree, from_parent_index) {
         EXPECT_EQ(tree.num_children(2), 0u);
         EXPECT_EQ(tree.num_children(4), 0u);
         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));
     }
     {
         //