From 6f06ea41c34a20af80005a1bf00e7920cf97f6d5 Mon Sep 17 00:00:00 2001
From: bcumming <bcumming@cscs.ch>
Date: Wed, 25 May 2016 11:58:19 +0200
Subject: [PATCH] add extra validation test for swc from file

---
 src/cell.cpp         | 36 ++++++++++++++++++++++++++++++++++++
 src/cell.hpp         |  6 ++++++
 src/segment.hpp      | 20 ++++++++++++++++++++
 src/util.hpp         | 15 +++++++++++++++
 tests/test_swcio.cpp | 28 ++++++++++++++++++++++++++++
 5 files changed, 105 insertions(+)

diff --git a/src/cell.cpp b/src/cell.cpp
index a6986f06..8fdd1bb6 100644
--- a/src/cell.cpp
+++ b/src/cell.cpp
@@ -195,5 +195,41 @@ std::vector<int> const& cell::segment_parents() const
     return parents_;
 }
 
+// Rough and ready comparison of two cells.
+// We don't use an operator== because equality of two cells is open to
+// interpretation. For example, it is possible to have two viable representations
+// of a cell: with and without location information for the cables.
+//
+// Checks that two cells have the same
+//  - number and type of segments
+//  - volume and area properties of each segment
+//  - number of compartments in each segment
+bool cell_basic_equality(cell const& lhs, cell const& rhs)
+{
+    if(lhs.num_segments() != rhs.num_segments()) {
+        return false;
+    }
+    if(lhs.segment_parents() != rhs.segment_parents()) {
+        return false;
+    }
+    for(auto 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())
+            {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
 } // namespace mc
 } // namespace nest
diff --git a/src/cell.hpp b/src/cell.hpp
index ba5f9b6b..fece1349 100644
--- a/src/cell.hpp
+++ b/src/cell.hpp
@@ -123,6 +123,12 @@ class cell {
     std::vector<std::pair<segment_location, i_clamp>> stimulii_;
 };
 
+// Checks that two cells have the same
+//  - number and type of segments
+//  - volume and area properties of each segment
+//  - number of compartments in each segment
+bool cell_basic_equality(cell const& lhs, cell const& rhs);
+
 // create a cable by forwarding cable construction parameters provided by the user
 template <typename... Args>
 cable_segment* cell::add_cable(cell::index_type parent, Args ...args)
diff --git a/src/segment.hpp b/src/segment.hpp
index fd1d8ded..decb0cdd 100644
--- a/src/segment.hpp
+++ b/src/segment.hpp
@@ -76,6 +76,16 @@ class segment {
         return nullptr;
     }
 
+    virtual const cable_segment* as_cable() const
+    {
+        return nullptr;
+    }
+
+    virtual const soma_segment* as_soma() const
+    {
+        return nullptr;
+    }
+
     virtual bool is_placeholder() const
     {
         return false;
@@ -230,6 +240,11 @@ class soma_segment : public segment
         return this;
     }
 
+    const soma_segment* as_soma() const override
+    {
+        return this;
+    }
+
     /// soma has one and one only compartments
     int num_compartments() const override
     {
@@ -359,6 +374,11 @@ class cable_segment : public segment
         return this;
     }
 
+    const cable_segment* as_cable() const override
+    {
+        return this;
+    }
+
     int num_compartments() const override
     {
         return num_compartments_;
diff --git a/src/util.hpp b/src/util.hpp
index 706ab7da..afa029ff 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -45,6 +45,21 @@ std::ostream& print(std::ostream &o, std::vector<T>const& v)
     return o;
 }
 
+template <typename T>
+bool operator ==(const std::vector<T>& lhs, const std::vector<T>& rhs)
+{
+    if(lhs.size() != rhs.size()) {
+        return false;
+    }
+    return std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+template <typename T>
+bool operator !=(const std::vector<T>& lhs, const std::vector<T>& rhs)
+{
+    return !(lhs==rhs);
+}
+
 namespace nest {
 namespace mc {
 namespace util {
diff --git a/tests/test_swcio.cpp b/tests/test_swcio.cpp
index 679260d6..6968fd43 100644
--- a/tests/test_swcio.cpp
+++ b/tests/test_swcio.cpp
@@ -487,3 +487,31 @@ TEST(swc_io, cell_construction)
                   cell.cable(3)->radius(0));
     }
 }
+
+// check that simple ball and stick model with one dendrite attached to a soma
+// which is used in the validation tests can be loaded from file and matches
+// the one generated with the C++ interface
+TEST(swc_parser, from_file_ball_and_stick)
+{
+    auto fname = "../data/ball_and_stick.swc";
+    std::ifstream fid(fname);
+    if(!fid.is_open()) {
+        std::cerr << "unable to open file " << fname << "... skipping test\n";
+        return;
+    }
+
+    // read the file into a cell object
+    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_compartments(), 2u);
+
+    // make an equivalent cell via C++ interface
+    nest::mc::cell local_cell;
+    local_cell.add_soma(6.30785);
+    local_cell.add_cable(0, nest::mc::segmentKind::dendrite, 0.5, 0.5, 200);
+
+    EXPECT_TRUE(nest::mc::cell_basic_equality(local_cell, cell));
+}
+
-- 
GitLab