Skip to content
Snippets Groups Projects
compartment.hpp 3.47 KiB
#pragma once

#include <iterator>
#include <utility>

#include "common_types.hpp"

namespace nest {
namespace mc {

/// Defines the simplest type of compartment
/// The compartment is a conic frustrum
struct compartment {
    using value_type = double;
    using size_type = cell_local_size_type;
    using value_pair = std::pair<value_type, value_type>;

    compartment() = delete;

    compartment(
        size_type idx,
        value_type len,
        value_type r1,
        value_type r2
    )
    :   index{idx},
        radius{r1, r2},
        length{len}
    {}


    size_type index;
    std::pair<value_type, value_type> radius;
    value_type length;
};

/// The simplest type of compartment iterator :
///     - divide a segment into n compartments of equal length
///     - assume that the radius varies linearly from one end of the segment
///       to the other
class compartment_iterator :
    public std::iterator<std::forward_iterator_tag, compartment>
{

    public:

    using base = std::iterator<std::forward_iterator_tag, compartment>;
    using size_type = base::value_type::size_type;
    using real_type = base::value_type::value_type;

    compartment_iterator() = delete;

    compartment_iterator(
        size_type idx,
        real_type len,
        real_type rad,
        real_type delta_rad
    )
    :   index_(idx),
        radius_(rad),
        delta_radius_(delta_rad),
        length_(len)
    { }

    compartment_iterator(compartment_iterator const& other) = default;

    compartment_iterator& operator++()
    {
        index_++;
        radius_ += delta_radius_;
        return *this;
    }

    compartment_iterator operator++(int)
    {
        compartment_iterator ret(*this);
        operator++();
        return ret;
    }

    compartment operator*() const
    {
        return
            compartment(
                index_, length_, radius_, radius_ + delta_radius_
            );
    }

    bool operator==(compartment_iterator const& other) const
    {
        return other.index_ == index_;
    }

    bool operator!=(compartment_iterator const& other) const
    {
        return !operator==(other);
    }

    private :

    size_type index_;
    real_type radius_;
    const real_type delta_radius_;
    const real_type length_;
};

class compartment_range {
public:
    using size_type = compartment_iterator::size_type;
    using real_type = compartment_iterator::real_type;

    compartment_range(
        size_type num_compartments,
        real_type radius_L,
        real_type radius_R,
        real_type length
    )
    :   num_compartments_(num_compartments),
        radius_L_(radius_L),
        radius_R_(radius_R),
        length_(length)
    {}

    compartment_iterator begin() const
    {
        return {0, compartment_length(), radius_L_, delta_radius()};
    }

    compartment_iterator cbegin() const
    {
        return begin();
    }

    /// With 0-based indexing compartment number "num_compartments_" is
    /// one past the end
    compartment_iterator end() const
    {
        return {num_compartments_, 0, 0, 0};
    }
    compartment_iterator cend() const
    {
        return end();
    }

    real_type delta_radius() const
    {
        return (radius_R_ - radius_L_) / num_compartments_;
    }

    real_type compartment_length() const
    {
        return length_ / num_compartments_;
    }

    private:

    size_type num_compartments_;
    real_type radius_L_;
    real_type radius_R_;
    real_type length_;
};

} // namespace mc
} // namespace nest