Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Soma a single class used by both mutable and immutable #366

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions binds/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pybind11_add_module(_morphio SYSTEM
bind_immutable.cpp
bindings_utils.cpp
bind_misc.cpp
bind_soma.cpp
bind_mutable.cpp
bind_vasculature.cpp
)
Expand Down
27 changes: 0 additions & 27 deletions binds/python/bind_immutable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,33 +213,6 @@ void bind_immutable_module(py::module& m) {
&morphio::EndoplasmicReticulum::filamentCounts,
"Returns the number of filaments for each neuronal section");


py::class_<morphio::Soma>(m, "Soma")
.def(py::init<const morphio::Soma&>())
.def_property_readonly(
"points",
[](morphio::Soma* soma) { return span_array_to_ndarray(soma->points()); },
"Returns the coordinates (x,y,z) of all soma point")
.def_property_readonly(
"diameters",
[](morphio::Soma* soma) { return span_to_ndarray(soma->diameters()); },
"Returns the diameters of all soma points")

.def_property_readonly(
"center",
[](morphio::Soma* soma) { return py::array(3, soma->center().data()); },
"Returns the center of gravity of the soma points")
.def_property_readonly("max_distance",
&morphio::Soma::maxDistance,
"Return the maximum distance between the center of gravity "
"and any of the soma points")
.def_property_readonly("type", &morphio::Soma::type, "Returns the soma type")

.def_property_readonly("surface",
&morphio::Soma::surface,
"Returns the soma surface\n\n"
"Note: the soma surface computation depends on the soma type");

py::class_<morphio::Section>(m, "Section")
.def("__str__",
[](const morphio::Section& section) {
Expand Down
41 changes: 2 additions & 39 deletions binds/python/bind_mutable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ void bind_mutable_module(py::module& m) {
py::return_value_policy::reference)
.def_property_readonly(
"soma",
static_cast<std::shared_ptr<morphio::mut::Soma>& (morphio::mut::Morphology::*) ()>(
&morphio::mut::Morphology::soma),
[](const morphio::mut::Morphology& self) { return self.soma(); },
"Returns a reference to the soma object\n\n"
"Note: multiple morphologies can share the same Soma "
"instance")
Expand Down Expand Up @@ -132,7 +131,7 @@ void bind_mutable_module(py::module& m) {
.def_property_readonly("version", &morphio::mut::Morphology::version, "Returns the version")

.def("remove_unifurcations",
static_cast<void (morphio::mut::Morphology::*) ()>(
static_cast<void (morphio::mut::Morphology::*)()>(
&morphio::mut::Morphology::removeUnifurcations),
"Fixes the morphology single child sections and issues warnings"
"if the section starts and ends are inconsistent")
Expand Down Expand Up @@ -455,42 +454,6 @@ void bind_mutable_module(py::module& m) {
"point_level_properties"_a,
"section_type"_a = morphio::SectionType::SECTION_UNDEFINED);

py::class_<morphio::mut::Soma, std::shared_ptr<morphio::mut::Soma>>(m, "Soma")
.def(py::init<const morphio::Property::PointLevel&>())
.def_property(
"points",
[](morphio::mut::Soma* soma) {
return py::array(static_cast<py::ssize_t>(soma->points().size()),
soma->points().data());
},
[](morphio::mut::Soma* soma, py::array_t<morphio::floatType> _points) {
soma->points() = array_to_points(_points);
},
"Returns the coordinates (x,y,z) of all soma point")
.def_property(
"diameters",
[](morphio::mut::Soma* soma) {
return py::array(static_cast<py::ssize_t>(soma->diameters().size()),
soma->diameters().data());
},
[](morphio::mut::Soma* soma, py::array_t<morphio::floatType> _diameters) {
soma->diameters() = _diameters.cast<std::vector<morphio::floatType>>();
},
"Returns the diameters of all soma points")
.def_property_readonly("type", &morphio::mut::Soma::type, "Returns the soma type")
.def_property_readonly("surface",
&morphio::mut::Soma::surface,
"Returns the soma surface\n\n"
"Note: the soma surface computation depends on the soma type")
.def_property_readonly("max_distance",
&morphio::mut::Soma::maxDistance,
"Return the maximum distance between the center of gravity "
"and any of the soma points")
.def_property_readonly(
"center",
[](morphio::mut::Soma* soma) { return py::array(3, soma->center().data()); },
"Returns the center of gravity of the soma points");

py::class_<morphio::mut::EndoplasmicReticulum>(m, "EndoplasmicReticulum")
.def(py::init<>())
.def(py::init<const std::vector<uint32_t>&,
Expand Down
58 changes: 58 additions & 0 deletions binds/python/bind_soma.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@

#include <pybind11/numpy.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <morphio/soma.h>
#include <morphio/types.h>

#include "bind_soma.h"
#include "bindings_utils.h"

namespace py = pybind11;

void bind_soma_module(py::module& m) {
py::class_<morphio::Soma, std::shared_ptr<morphio::Soma>>(m, "Soma")
.def(py::init<const morphio::Soma&>())

.def(py::init<const morphio::Property::PointLevel&>())

.def_property(
"points",
[](morphio::Soma* soma) {
return py::array(static_cast<py::ssize_t>(soma->points().size()),
soma->points().data());
},
[](morphio::Soma* soma, py::array_t<morphio::floatType> points) {
soma->points() = array_to_points(points);
},
"Returns the coordinates (x,y,z) of all soma point")

.def_property(
"diameters",
[](morphio::Soma* soma) {
return py::array(static_cast<py::ssize_t>(soma->diameters().size()),
soma->diameters().data());
},
[](morphio::Soma* soma, py::array_t<morphio::floatType> _diameters) {
soma->diameters() = _diameters.cast<std::vector<morphio::floatType>>();
},
"Returns the diameters of all soma points")

.def_property_readonly(
"center",
[](morphio::Soma* soma) { return py::array(3, soma->center().data()); },
"Returns the center of gravity of the soma points")

.def_property_readonly("max_distance",
&morphio::Soma::maxDistance,
"Return the maximum distance between the center of gravity "
"and any of the soma points")

.def_property_readonly("type", &morphio::Soma::type, "Returns the soma type")

.def_property_readonly("surface",
&morphio::Soma::surface,
"Returns the soma surface\n\n"
"Note: the soma surface computation depends on the soma type");
}
4 changes: 4 additions & 0 deletions binds/python/bind_soma.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once
#include <pybind11/pybind11.h>

void bind_soma_module(pybind11::module& m);
1 change: 0 additions & 1 deletion binds/python/bindings_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ py::array_t<morphio::floatType> span_to_ndarray(const morphio::range<const T>& s
return py::array(buffer_info);
}


/**
* @brief "Casts" a Cpp sequence to a python array (no memory copies)
* Python capsule handles void pointers to objects and makes sure
Expand Down
2 changes: 2 additions & 0 deletions binds/python/morphio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

#include "bind_immutable.h"
#include "bind_misc.h"
#include "bind_soma.h"
#include "bind_mutable.h"
#include "bind_vasculature.h"

namespace py = pybind11;

PYBIND11_MODULE(_morphio, m) {
bind_misc(m);
bind_soma_module(m);
bind_immutable_module(m);

py::module mut_module = m.def_submodule("mut");
Expand Down
1 change: 1 addition & 0 deletions include/morphio/morphology.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ class Morphology
const MorphologyVersion& version() const;

protected:

friend class mut::Morphology;
Morphology(const Property::Properties& properties, unsigned int options);

Expand Down
3 changes: 2 additions & 1 deletion include/morphio/mut/morphology.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
#include <morphio/exceptions.h>
#include <morphio/mut/endoplasmic_reticulum.h>
#include <morphio/mut/mitochondria.h>

#include <morphio/mut/modifiers.h>
#include <morphio/mut/soma.h>
#include <morphio/soma.h>
#include <morphio/properties.h>
#include <morphio/types.h>

Expand Down
70 changes: 0 additions & 70 deletions include/morphio/mut/soma.h

This file was deleted.

44 changes: 29 additions & 15 deletions include/morphio/soma.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <morphio/properties.h>
#include <morphio/morphology.h>
#include <morphio/types.h>

Expand All @@ -25,22 +26,33 @@ namespace morphio {
*
* @version unstable
*/
class Soma
struct Soma
{
public:
Soma() = default;
Soma(const Soma& soma) = default;

explicit Soma(const Property::Properties& properties);
explicit Soma(const Property::PointLevel& point_properties);

/// Return the coordinates (x,y,z) of all soma points
range<const Point> points() const noexcept {
return properties_->_somaLevel._points;
std::vector<Point>& points() noexcept {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So… this makes things mutable, is this still the right place then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that there is no readonly/mutable duality with these changes, I thought I might leave it in morphio/soma.h. But you are right, it can be moved to mut too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose one could say that the Morphology proper is the (im)mutable entity, in which case the placement of the soma would be fine. But then makes me wonder, shouldn't the section class receive the same treatment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this is an experiment to check if I can pull this through. pybind11 is giving me hell at the time being...
If it will work, yes, I don't see why not do the same for sections and reduce the complexity of the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although with sections, the switching from leveraging the ranges to copying the data so that a section data structure is created the same way for both mut/readonly, will result in quite a performance penalty. With soma it doesn't really matter given that it is just one and with very few points.

return properties_._points;
}
const std::vector<Point>& points() const noexcept {
return properties_._points;
}

/// Return the diameters of all soma points
range<const floatType> diameters() const noexcept {
return properties_->_somaLevel._diameters;
std::vector<morphio::floatType>& diameters() noexcept {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

return properties_._diameters;
}
const std::vector<morphio::floatType>& diameters() const noexcept {
return properties_._diameters;
}

/// Return the soma type
SomaType type() const noexcept {
return properties_->_cellLevel._somaType;
return soma_type_;
}

/// Return the center of gravity of the soma points
Expand All @@ -64,16 +76,18 @@ class Soma
*/
floatType maxDistance() const;

/// Return soma properties
Property::PointLevel& properties() noexcept {
return properties_;
}
const Property::PointLevel& properties() const noexcept {
return properties_;
}

private:
explicit Soma(const std::shared_ptr<Property::Properties>& properties);
// TODO: find out why the following line does not work
// when friend class Morphology; is removed
// template <typename Property>
// friend const morphio::Soma morphio::Morphology::soma() const;
friend class Morphology;
friend class mut::Soma;

std::shared_ptr<Property::Properties> properties_;
SomaType soma_type_ = SOMA_UNDEFINED;
Property::PointLevel properties_;
};

} // namespace morphio
3 changes: 1 addition & 2 deletions include/morphio/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Section;
template <class T>
class SectionBase;

class Soma;
struct Soma;

namespace Property {
struct Properties;
Expand All @@ -45,7 +45,6 @@ class MitoSection;
class Mitochondria;
class Morphology;
class Section;
class Soma;
} // namespace mut

using SectionRange = std::pair<size_t, size_t>;
Expand Down
2 changes: 1 addition & 1 deletion morphio/mut/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .._morphio import Soma
from .._morphio.mut import (Morphology,
Section,
Soma,
MitoSection,
Mitochondria,
GlialCell,
Expand Down
1 change: 0 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ set(MORPHIO_SOURCES
mut/modifiers.cpp
mut/morphology.cpp
mut/section.cpp
mut/soma.cpp
mut/writers.cpp
point_utils.cpp
properties.cpp
Expand Down
Loading