From 85ee79c8a0299f8a9ba918607a34836ac0ca17c4 Mon Sep 17 00:00:00 2001
From: bcumming <bcumming@cscs.ch>
Date: Fri, 18 Mar 2016 16:46:38 +0100
Subject: [PATCH] start working on compartment model

---
 src/compartment.hpp | 127 +++++++++++++++++++++++++++++++++
 src/math.hpp        |  26 +++++++
 src/point.hpp       |  68 ++++++++++++++++++
 src/segment.hpp     | 168 ++++++++++++++++++++++++++++++++++++++++++++
 src/util.hpp        |  10 +++
 5 files changed, 399 insertions(+)
 create mode 100644 src/compartment.hpp
 create mode 100644 src/math.hpp
 create mode 100644 src/point.hpp
 create mode 100644 src/segment.hpp

diff --git a/src/compartment.hpp b/src/compartment.hpp
new file mode 100644
index 00000000..350caed3
--- /dev/null
+++ b/src/compartment.hpp
@@ -0,0 +1,127 @@
+#pragma once
+
+#include <cmath>
+
+#include <vector>
+
+#include "point.hpp"
+
+/*
+    We start with a high-level description of the cell
+    - list of branches of the cell
+        - soma, dendrites, axons
+        - spatial locations if provided
+            - bare minimum spatial information required is length and radius
+              at each end for each of the branches, and a soma radius
+        - model properties of each branch
+            - mechanisms
+            - clamps
+            - synapses
+        - list of compartments if they have been provided
+
+    This description is not used for solving the system
+    From the description we can then build a cell solver
+    - e.g. the FVM formulation
+    - e.g. Green's functions
+
+*/
+
+namespace nestmc {
+
+template <typename T>
+T constexpr pi() {
+    return 3.141592653589793238462643383279502;
+}
+
+template <typename T>
+class compartment {
+    using value_type = T;
+    using point_type = point<value_type>;
+
+    constexpr compartment()
+    :   p1_{point_type()},
+        p2_{point_type()},
+        radius1_{std::numeric_limits<value_type>::quiet_NaN()},
+        radius2_{std::numeric_limits<value_type>::quiet_NaN()}
+    {}
+
+    constexpr compartment(
+        point_type const& p1,
+        point_type const& p2,
+        value_type r1,
+        value_type r2
+    )
+    :   p1_{p1},
+        p2_{p2},
+        radius1_{r1},
+        radius2_{r2}
+    {}
+
+    value_type length() const {
+        return norm(p1_-p2_);
+    }
+
+    value_type area() const {
+        return volume_frustrum(length(), radius1_, radius2_);
+    }
+
+    value_type volume() const {
+        return volume_frustrum(length(), radius1_, radius2_);
+    }
+
+    constexpr point_type midpoint() const {
+        return 0.5*(p1_+p2_);
+    }
+
+    constexpr point_type midradius() const {
+        return 0.5*(radius1_+radius2_);
+    }
+
+    private :
+
+    value_type area_frustrum(
+        value_type L,
+        value_type r1,
+        value_type r2
+    ) const
+    {
+        auto dr = r1 - r2;
+        return pi<double>() * (r1+r2) * std::sqrt(L*L + dr*dr);
+    }
+
+    value_type volume_frustrum(
+        value_type L,
+        value_type r1,
+        value_type r2
+    ) const
+    {
+        auto meanr = (r1+r2) / 2.;
+        return pi<double>() * meanr * meanr * L;
+    }
+
+    point_type p1_;
+    point_type p2_;
+    value_type radius1_;
+    value_type radius2_;
+};
+
+class segment {
+
+    private :
+
+    double length_;
+    double radius_start_;
+    double radius_end_;
+    std::vector<compartment> compartments_;
+    segmentKind kind_;
+};
+
+class abstract_cell {
+    abstract_cell() = default;
+
+    private :
+};
+
+} // namespace nestmc 
+
+
diff --git a/src/math.hpp b/src/math.hpp
new file mode 100644
index 00000000..d9368249
--- /dev/null
+++ b/src/math.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <cmath>
+
+namespace nestmc {
+
+    template <typename T>
+    T constexpr pi() {
+        return 3.141592653589793238462643383279502;
+    }
+
+    template <typename T>
+    T area_frustrum(T L, T r1, T r2)
+    {
+        auto dr = r1 - r2;
+        return pi<double>() * (r1+r2) * sqrt(L*L + dr*dr);
+    }
+
+    template <typename T>
+    T volume_frustrum(T L, T r1, T r2)
+    {
+        auto meanr = (r1+r2) / 2.;
+        return pi<double>() * meanr * meanr * L;
+    }
+
+} // namespace nestmc
diff --git a/src/point.hpp b/src/point.hpp
new file mode 100644
index 00000000..fc3f0dae
--- /dev/null
+++ b/src/point.hpp
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <limits>
+#include <ostream>
+
+template <typename T>
+struct point {
+    using value_type = T;
+    value_type x;
+    value_type y;
+    value_type z;
+
+    constexpr point(T a, T b, T c)
+    : x(a), y(b), z(c)
+    {}
+
+    // initialize to NaN by default
+    constexpr point()
+    : x(std::numeric_limits<T>::quiet_NaN()),
+      y(std::numeric_limits<T>::quiet_NaN()),
+      z(std::numeric_limits<T>::quiet_NaN())
+    {}
+};
+
+template <typename T>
+constexpr point<T>  operator+ (
+    point<T> const& lhs,
+    point<T> const& rhs)
+{
+    return point<T>(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);
+}
+
+template <typename T>
+constexpr point<T>  operator- (
+    point<T> const& lhs,
+    point<T> const& rhs)
+{
+    return point<T>(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z);
+}
+
+template <typename T>
+constexpr point<T> operator* (
+    T alpha,
+    point<T> const& p)
+{
+    return point<T>(alpha*p.x, alpha*p.y, alpha*p.z);
+}
+
+template <typename T>
+T norm(point<T> const& p)
+{
+    return sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
+}
+
+template <typename T>
+constexpr T dot(
+    point<T> const& lhs,
+    point<T> const& rhs)
+{
+    return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z;
+}
+
+template <typename T>
+std::ostream& operator << (std::ostream& o, point<T> const& p) {
+    return o << "[" << p.x << ", " << p.y << ", " << p.z << "]";
+}
+
+
diff --git a/src/segment.hpp b/src/segment.hpp
new file mode 100644
index 00000000..6cefbd78
--- /dev/null
+++ b/src/segment.hpp
@@ -0,0 +1,168 @@
+#pragma once
+
+#include <cmath>
+
+#include <vector>
+
+#include "math.hpp"
+#include "point.hpp"
+#include "util.hpp"
+
+/*
+    We start with a high-level description of the cell
+    - list of branches of the cell
+        - soma, dendrites, axons
+        - spatial locations if provided
+            - bare minimum spatial information required is length and radius
+              at each end for each of the branches, and a soma radius
+        - model properties of each branch
+            - mechanisms
+            - clamps
+            - synapses
+        - list of compartments if they have been provided
+
+    This description is not used for solving the system
+    From the description we can then build a cell solver
+    - e.g. the FVM formulation
+    - e.g. Green's functions
+
+*/
+
+namespace nestmc {
+
+enum class segmentKind {
+    soma,
+    dendrite,
+    axon
+};
+
+class segment {
+    public:
+
+    using value_type = double;
+    using point_type = point<value_type>;
+
+    segmentKind kind() const {
+        return kind_;
+    }
+
+    virtual value_type volume() const = 0;
+    virtual value_type area()  const = 0;
+
+    virtual ~segment() = default;
+
+    protected:
+
+    segmentKind kind_;
+};
+
+class spherical_segment : public segment
+{
+    public :
+
+    using base = segment;
+    using base::kind_;
+    using base::value_type;
+    using base::point_type;
+
+    spherical_segment() = delete;
+
+    spherical_segment(value_type r)
+    :   radius_{r}
+    {
+        kind_ = segmentKind::soma;
+    }
+
+    spherical_segment(value_type r, point_type const &c)
+    :   spherical_segment(r)
+    {
+        center_ = c;
+        kind_ = segmentKind::soma;
+    }
+
+    value_type volume() const override
+    {
+        return 4./3. * pi<value_type>() * radius_ * radius_ * radius_;
+    }
+
+    value_type area() const override
+    {
+        return 4. * pi<value_type>() * radius_ * radius_;
+    }
+
+    virtual ~spherical_segment() = default;
+
+    private :
+
+    // store the center and radius of the soma
+    // note that the center may be undefined
+    value_type radius_;
+    point_type center_;
+};
+
+class frustrum_segment : public segment
+{
+    public :
+
+    using segment::kind_;
+    using base = segment;
+    using base::value_type;
+    using base::point_type;
+
+    frustrum_segment() = delete;
+
+    frustrum_segment(
+        segmentKind k,
+        value_type r1,
+        value_type r2,
+        value_type len
+    ) {
+        r1_ = r1;
+        r2_ = r2;
+        length_ = len;
+        kind_ = k;
+        assert(k==segmentKind::dendrite || k ==segmentKind::axon);
+    }
+
+    frustrum_segment(
+        segmentKind k,
+        value_type r1,
+        value_type r2,
+        point_type const& p1,
+        point_type const& p2
+    )
+    : frustrum_segment(k, r1, r2, norm(p1-p2))
+    {
+        p1_ = p1;
+        p2_ = p2;
+    }
+
+    value_type volume() const override
+    {
+        return volume_frustrum(length_, r1_, r2_);
+    }
+    value_type area()   const override
+    {
+        return area_frustrum(length_, r1_, r2_);
+    }
+
+    virtual ~frustrum_segment() = default;
+
+    private :
+
+    value_type length_;
+    value_type r1_;
+    value_type r2_;
+    point_type p1_;
+    point_type p2_;
+};
+
+using segment_ptr = std::unique_ptr<segment>;
+
+template <typename T, typename... Args>
+segment_ptr make_segment(Args&&... args) {
+    return segment_ptr(new T(std::forward<Args>(args)...));
+}
+
+} // namespace nestmc
+
diff --git a/src/util.hpp b/src/util.hpp
index 17a3a49b..580981be 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -11,6 +11,7 @@ using memory::util::blue;
 using memory::util::cyan;
 */
 
+#include <memory>
 #include <ostream>
 #include <vector>
 
@@ -26,3 +27,12 @@ operator << (std::ostream &o, std::vector<T>const& v)
     return o;
 }
 
+namespace util {
+    // just because we aren't using C++14, doesn't mean we shouldn't go
+    // without make_unique
+    template <typename T, typename... Args>
+    std::unique_ptr<T> make_unique(Args&&... args) {
+        return std::unique_ptr<T>(new T(std::forward<Args>(args) ...));
+    }
+}
+
-- 
GitLab