├── .clang-format ├── .github └── workflows │ ├── check-sdist.yml │ ├── clang_format_check.yaml │ ├── coverage_test.yaml │ ├── docstring_check.yaml │ ├── publish-sdist-wheels.yml │ └── run-tests.yml ├── .gitignore ├── .gitmodules ├── .readthedocs.yaml ├── 3rdparty └── CMakeLists.txt ├── AUTHORS.txt ├── CHANGELOG.md ├── CMake ├── CodeCoverage.cmake ├── CompilerFlags.cmake └── MorphIOConfig.cmake ├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE.txt ├── MANIFEST.in ├── README.rst ├── binds └── python │ ├── CMakeLists.txt │ ├── bind_enums.cpp │ ├── bind_enums.h │ ├── bind_immutable.cpp │ ├── bind_immutable.h │ ├── bind_misc.cpp │ ├── bind_misc.h │ ├── bind_mutable.cpp │ ├── bind_mutable.h │ ├── bind_vasculature.cpp │ ├── bind_vasculature.h │ ├── bind_warnings_exceptions.cpp │ ├── bind_warnings_exceptions.h │ ├── bindings_utils.cpp │ ├── bindings_utils.h │ ├── generated │ ├── .clang-format │ └── docstrings.h │ └── morphio.cpp ├── ci ├── check_clang_format.sh ├── check_generated_docstrings.sh ├── coverage_test.sh ├── cpp_test.sh ├── hdf5-build.sh └── python_test.sh ├── doc ├── Makefile ├── README.md └── source │ ├── Doxyfile │ ├── DoxygenLayout.xml │ ├── _templates │ └── doxygen_page.rst_t │ ├── conf.py │ ├── cpp.rst │ ├── doxygen │ └── .gitignore │ ├── footer.html │ ├── glia.rst │ ├── header.html │ ├── images │ ├── section_segment.svg │ ├── sections.svg │ └── swc │ │ ├── sequential.svg │ │ ├── sphere.svg │ │ ├── split.svg │ │ ├── three_pt.svg │ │ └── two_pt.svg │ ├── index.rst │ ├── install.rst │ ├── logo │ └── BBP-MorphIO.jpg │ ├── markers.rst │ ├── mitochondria.rst │ ├── morphology.rst │ ├── python.rst │ ├── reticulum.rst │ ├── specification.rst │ ├── specification_neurolucida.rst │ └── warnings.rst ├── examples ├── getting_started.ipynb └── getting_started_mutable.ipynb ├── include └── morphio │ ├── collection.h │ ├── dendritic_spine.h │ ├── endoplasmic_reticulum.h │ ├── enums.h │ ├── errorMessages.h │ ├── exceptions.h │ ├── glial_cell.h │ ├── mito_section.h │ ├── mitochondria.h │ ├── morphology.h │ ├── mut │ ├── dendritic_spine.h │ ├── endoplasmic_reticulum.h │ ├── glial_cell.h │ ├── mito_section.h │ ├── mitochondria.h │ ├── modifiers.h │ ├── morphology.h │ ├── section.h │ ├── soma.h │ └── writers.h │ ├── properties.h │ ├── section.h │ ├── section_base.h │ ├── section_iterators.hpp │ ├── soma.h │ ├── types.h │ ├── vasc │ ├── iterators.hpp │ ├── properties.h │ ├── section.h │ └── vasculature.h │ ├── vector_types.h │ ├── version.h │ └── warning_handling.h ├── morphio ├── __init__.py ├── mut │ └── __init__.py └── vasculature │ └── __init__.py ├── pyproject.toml ├── scripts └── check-clang-format-all ├── setup.py ├── src ├── CMakeLists.txt ├── collection.cpp ├── dendritic_spine.cpp ├── endoplasmic_reticulum.cpp ├── enums.cpp ├── errorMessages.cpp ├── error_message_generation.cpp ├── error_message_generation.h ├── glial_cell.cpp ├── mito_section.cpp ├── mitochondria.cpp ├── morphology.cpp ├── mut │ ├── dendritic_spine.cpp │ ├── endoplasmic_reticulum.cpp │ ├── glial_cell.cpp │ ├── mito_section.cpp │ ├── mitochondria.cpp │ ├── modifiers.cpp │ ├── morphology.cpp │ ├── section.cpp │ ├── soma.cpp │ ├── writer_asc.cpp │ ├── writer_hdf5.cpp │ ├── writer_swc.cpp │ ├── writer_utils.cpp │ └── writer_utils.h ├── point_utils.cpp ├── point_utils.h ├── properties.cpp ├── readers │ ├── NeurolucidaLexer.inc │ ├── morphologyASC.cpp │ ├── morphologyASC.h │ ├── morphologyHDF5.cpp │ ├── morphologyHDF5.h │ ├── morphologySWC.cpp │ ├── morphologySWC.h │ ├── utils.cpp │ ├── utils.h │ ├── vasculatureHDF5.cpp │ └── vasculatureHDF5.h ├── section.cpp ├── shared_utils.cpp ├── shared_utils.hpp ├── soma.cpp ├── vasc │ ├── properties.cpp │ ├── section.cpp │ └── vasculature.cpp ├── version.cpp.in └── warning_handling.cpp └── tests ├── CMakeLists.txt ├── data ├── annotations.asc ├── astrocyte.h5 ├── circle_contour.asc ├── complexe.swc ├── disconnected_neurite.swc ├── h5 │ ├── empty.h5 │ ├── merged.h5 │ ├── non-valid.h5 │ ├── v1 │ │ ├── Neuron-no-soma.h5 │ │ ├── Neuron.h5 │ │ ├── endoplasmic-reticulum.h5 │ │ ├── glia.h5 │ │ ├── glia_empty_perimeters.h5 │ │ ├── glia_soma_only.h5 │ │ ├── glia_wrong_sized_perimeters.h5 │ │ ├── h5v1.4.h5 │ │ ├── incorrect_point_columns.h5 │ │ ├── incorrect_structure_columns.h5 │ │ ├── make-dendritic-spine.py │ │ ├── merged.h5 │ │ ├── metadata_group_only.h5 │ │ ├── mitochondria.h5 │ │ ├── monodim.h5 │ │ ├── reversed_NRN_neurite_order.h5 │ │ ├── simple-broken-section-type.h5 │ │ ├── simple-dendritric-spine.h5 │ │ ├── simple-negative-section-type.h5 │ │ ├── simple-single-point-soma.h5 │ │ ├── simple-two-point-soma.h5 │ │ ├── simple.h5 │ │ ├── single-neurite.h5 │ │ ├── soma_after_dendrite.h5 │ │ ├── soma_no_neurites.h5 │ │ ├── three-point-soma-two-offset.h5 │ │ ├── two_child_unmerged.h5 │ │ └── unknown_section_type_structure.h5 │ ├── v2 │ │ └── Neuron.h5 │ ├── vasculature-broken-section-type.h5 │ ├── vasculature1.h5 │ └── vasculature2.h5 ├── invalid-incomplete.asc ├── iterators.asc ├── marker-with-string.asc ├── markers.asc ├── mono-type.asc ├── multiple_point_section.asc ├── multiple_soma.swc ├── nested_single_children.asc ├── neurite_wrong_root_point.swc ├── no_soma.swc ├── nrn-order-already-sorted.h5 ├── nrn_ordering.swc ├── pia.asc ├── reversed_NRN_neurite_order.swc ├── sections-block.asc ├── simple-all-types.swc ├── simple-heterogeneous-neurite.swc ├── simple-trailing-space.swc ├── simple-windows-eol.swc ├── simple-with-font.asc ├── simple-with-image-coord.asc ├── simple.asc ├── simple.swc ├── simple.unknown ├── simple2.asc ├── single_point_root.asc ├── soma_cylinders.swc ├── soma_multiple_frustums.swc ├── soma_single_frustum.swc ├── soma_three_points_cylinder.swc ├── spine.asc └── three_point_soma.swc ├── main.cpp ├── requirement_tests.txt ├── test_0_API.py ├── test_10_vasculature.py ├── test_11_collection.py ├── test_1_swc.py ├── test_2_neurolucida.py ├── test_3_h5.py ├── test_4_immut.py ├── test_5_mut.py ├── test_6_writers.py ├── test_7_modifiers.py ├── test_8_all_morphologies.py ├── test_9_surfaces.py ├── test_collection.cpp ├── test_enums.cpp ├── test_immutable_morphology.cpp ├── test_mitochondria.cpp ├── test_morphology_readers.cpp ├── test_mutable_morphology.cpp ├── test_point_utils.cpp ├── test_properties.cpp ├── test_soma.cpp ├── test_swc_reader.cpp ├── test_utilities.cpp ├── test_vasculature_morphology.cpp ├── test_vector_utils.cpp └── utils.py /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -2 3 | AlignAfterOpenBracket: Align 4 | AlignConsecutiveAssignments: false 5 | AlignConsecutiveDeclarations: false 6 | AlignEscapedNewlinesLeft: true 7 | AlignOperands: true 8 | AlignTrailingComments: true 9 | AllowAllParametersOfDeclarationOnNextLine: true 10 | AllowShortBlocksOnASingleLine: false 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: Empty 13 | AllowShortIfStatementsOnASingleLine: false 14 | AllowShortLoopsOnASingleLine: false 15 | AlwaysBreakBeforeMultilineStrings: true 16 | AlwaysBreakTemplateDeclarations: true 17 | BasedOnStyle: WebKit 18 | BinPackArguments: false 19 | BinPackParameters: false 20 | BraceWrapping: 21 | AfterClass: true 22 | AfterControlStatement: false 23 | AfterEnum: false 24 | AfterExternBlock: false 25 | AfterFunction: false 26 | AfterNamespace: false 27 | AfterStruct: false 28 | AfterUnion: false 29 | BeforeCatch: false 30 | BeforeElse: false 31 | BreakBeforeBraces: Custom 32 | BreakBeforeBinaryOperators: false 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializersBeforeComma: true 35 | BreakStringLiterals: true 36 | ColumnLimit: 100 37 | CommentPragmas: '^ IWYU pragma:' 38 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 39 | ConstructorInitializerIndentWidth: 4 40 | ContinuationIndentWidth: 4 41 | Cpp11BracedListStyle: true 42 | DerivePointerAlignment: false 43 | DerivePointerBinding: true 44 | ExperimentalAutoDetectBinPacking: false 45 | FixNamespaceComments: true 46 | ForEachMacros: [ foreach, ] 47 | IncludeCategories: 48 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 49 | Priority: 2 50 | - Regex: '^(<|"(gtest|isl|json)/)' 51 | Priority: 3 52 | - Regex: '.*' 53 | Priority: 1 54 | IncludeIsMainRegex: '$' 55 | IndentCaseLabels: false 56 | IndentWidth: 4 57 | IndentWrappedFunctionNames: false 58 | KeepEmptyLinesAtTheStartOfBlocks: false 59 | Language: Cpp 60 | MaxEmptyLinesToKeep: 2 61 | NamespaceIndentation: None 62 | PenaltyBreakAssignment: 40 63 | PenaltyBreakBeforeFirstCallParameter: 100 64 | PenaltyBreakComment: 60 65 | PenaltyBreakFirstLessLess: 120 66 | PenaltyBreakString: 1000 67 | PenaltyExcessCharacter: 1000000 68 | PenaltyReturnTypeOnItsOwnLine: 200 69 | PointerAlignment: Left 70 | PointerBindsToType: true 71 | ReflowComments: true 72 | SortIncludes: true 73 | SpaceAfterCStyleCast: true 74 | SpaceAfterTemplateKeyword: true 75 | SpaceBeforeAssignmentOperators: true 76 | SpaceBeforeCpp11BracedList: false 77 | SpaceBeforeCtorInitializerColon: false 78 | SpaceBeforeInheritanceColon: false 79 | SpaceBeforeParens: ControlStatements 80 | SpaceBeforeRangeBasedForLoopColon: true 81 | SpaceInEmptyParentheses: false 82 | SpacesBeforeTrailingComments: 2 83 | SpacesInAngles: false # '< ' style 84 | SpacesInContainerLiterals: false 85 | SpacesInCStyleCastParentheses: false 86 | SpacesInParentheses: false # '(' style 87 | SpacesInSquareBrackets: false 88 | Standard: Cpp11 89 | TabWidth: 4 90 | UseTab: Never 91 | ... 92 | -------------------------------------------------------------------------------- /.github/workflows/check-sdist.yml: -------------------------------------------------------------------------------- 1 | name: Check that `sdist` builds and installs 2 | on: [pull_request, push] 3 | 4 | env: 5 | apt_options: -o Acquire::Retries=3 6 | 7 | jobs: 8 | build_sdist: 9 | name: Build sdist 10 | runs-on: ubuntu-latest 11 | 12 | # Run on external PRs, but not internal PRs as they'll be run by the push 13 | if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | submodules: 'true' 19 | 20 | - name: Set up Python 3.10 21 | uses: actions/setup-python@v5 22 | with: 23 | python-version: '3.10' 24 | 25 | - name: Build a source tarball 26 | run: 27 | python setup.py sdist 28 | 29 | - name: Test tarball 30 | run: | 31 | sudo apt-get ${{env.apt_options}} update -y 32 | sudo apt-get ${{env.apt_options}} install -y libhdf5-dev 33 | pip install -r tests/requirement_tests.txt 34 | pip install dist/* 35 | pytest -s -v tests 36 | -------------------------------------------------------------------------------- /.github/workflows/clang_format_check.yaml: -------------------------------------------------------------------------------- 1 | name: clang-format-check 2 | on: [pull_request, push] 3 | 4 | env: 5 | apt_options: -o Acquire::Retries=3 6 | 7 | jobs: 8 | build: 9 | name: clang-format-check 10 | runs-on: ubuntu-22.04 11 | 12 | # Run on external PRs, but not internal PRs as they'll be run by the push 13 | if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository 14 | 15 | steps: 16 | - name: Fetch repository 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 2 20 | - name: Install packages 21 | run: | 22 | sudo apt-get ${{env.apt_options}} update -y 23 | sudo apt-get ${{env.apt_options}} install -y python3-venv 24 | - name: check_clang_format 25 | run: ci/check_clang_format.sh 26 | -------------------------------------------------------------------------------- /.github/workflows/coverage_test.yaml: -------------------------------------------------------------------------------- 1 | name: coverage-test 2 | on: [pull_request, push] 3 | 4 | env: 5 | CC: gcc-9 6 | CXX: g++-9 7 | apt_options: -o Acquire::Retries=3 8 | 9 | jobs: 10 | build: 11 | name: coverage-test 12 | runs-on: ubuntu-20.04 13 | 14 | # Run on external PRs, but not internal PRs as they'll be run by the push 15 | if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v4 20 | - name: Fetch repository 21 | run: git fetch --prune --unshallow 22 | 23 | - name: Get submodules 24 | run: git submodule update --init --force --recursive 25 | 26 | - name: Install packages 27 | run: | 28 | sudo apt-get ${{env.apt_options}} update -y 29 | sudo apt-get ${{env.apt_options}} install -y build-essential libhdf5-dev lcov language-pack-de 30 | - name: Build and run unittests 31 | run: | 32 | locale -a 33 | ci/coverage_test.sh 34 | 35 | - name: Upload Coverage to Coveralls 36 | uses: coverallsapp/github-action@master 37 | with: 38 | github-token: ${{ secrets.GITHUB_TOKEN }} 39 | path-to-lcov: build/build-coverage/coverage.info 40 | -------------------------------------------------------------------------------- /.github/workflows/docstring_check.yaml: -------------------------------------------------------------------------------- 1 | name: docstring-check 2 | on: [pull_request, push] 3 | 4 | env: 5 | apt_options: -o Acquire::Retries=3 6 | 7 | jobs: 8 | build: 9 | name: docstring-check 10 | runs-on: ubuntu-20.04 11 | 12 | # Run on external PRs, but not internal PRs as they'll be run by the push 13 | if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository 14 | 15 | steps: 16 | - name: Fetch repository 17 | uses: actions/checkout@v4 18 | with: 19 | submodules: recursive 20 | - name: Install packages 21 | run: | 22 | sudo apt-get ${{env.apt_options}} update -y 23 | sudo apt-get ${{env.apt_options}} install -y build-essential libhdf5-dev python3-venv libclang1-12 24 | - name: Check docstrings 25 | run: | 26 | export LIBCLANG_PATH=/usr/lib/x86_64-linux-gnu/libclang-12.so 27 | ci/check_generated_docstrings.sh || true 28 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | on: [pull_request, push] 3 | 4 | env: 5 | apt_options: -o Acquire::Retries=3 6 | 7 | jobs: 8 | build: 9 | name: Run tests on ${{ matrix.os }}.${{ matrix.compiler.CC }} 10 | runs-on: ${{ matrix.os }} 11 | 12 | # Run on external PRs, but not internal PRs as they'll be run by the push 13 | if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository 14 | 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest, macos-latest] 18 | compiler: 19 | - {CC: clang, CXX: clang++} 20 | - {CC: gcc, CXX: g++} 21 | exclude: 22 | - os: macos-latest 23 | compiler: {CC: gcc, CXX: g++} 24 | 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@v4 28 | with: 29 | submodules: 'true' 30 | 31 | - name: Setup python 32 | uses: actions/setup-python@v5 33 | with: 34 | python-version: '3.10' 35 | 36 | - name: Install packages on Linux 37 | if: runner.os == 'Linux' 38 | run: | 39 | sudo apt-get ${{env.apt_options}} update -y 40 | sudo apt-get ${{env.apt_options}} install -y build-essential libhdf5-dev language-pack-de 41 | 42 | - name: Install packages on MacOS 43 | if: runner.os == 'macOS' 44 | run: | 45 | # { work around https://github.com/actions/setup-python/issues/577 46 | #brew update 47 | #brew --version 48 | export HOMEBREW_NO_AUTO_UPDATE=1 49 | # } 50 | brew install cmake || true # macos image has cmake installed, but a new version may exist; ignore it if so 51 | brew install hdf5 52 | 53 | - name: Build and run unittests 54 | env: 55 | CC: ${{ matrix.compiler.CC }} 56 | CXX: ${{ matrix.compiler.CXX }} 57 | run: | 58 | locale -a 59 | ./ci/python_test.sh 60 | ./ci/cpp_test.sh 61 | ./ci/cpp_test.sh "-DMORPHIO_USE_DOUBLE=ON" 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python wheels 2 | *.whl 3 | 4 | .eggs/ 5 | bin/ 6 | src/version.cpp 7 | morphio.egg-info/ 8 | MorphIO.egg-info/ 9 | .venv 10 | 11 | *.pyc 12 | 13 | # Compiled Object files 14 | *.slo 15 | *.lo 16 | *.o 17 | *.obj 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Compiled Dynamic libraries 24 | *.so 25 | *.dylib 26 | *.dll 27 | 28 | # Fortran module files 29 | *.mod 30 | 31 | # Compiled Static libraries 32 | *.lai 33 | *.la 34 | *.a 35 | *.lib 36 | 37 | # Executables 38 | *.exe 39 | *.out 40 | *.app 41 | 42 | # Custom 43 | .tags 44 | build/ 45 | .*.swp 46 | *.idea 47 | ci/venv* 48 | cmake-build* 49 | env* 50 | venv-clang-format/ 51 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "3rdparty/HighFive"] 2 | path = 3rdparty/HighFive 3 | url = https://github.com/BlueBrain/HighFive.git 4 | [submodule "3rdparty/pybind11"] 5 | path = binds/python/pybind11 6 | url = https://github.com/pybind/pybind11.git 7 | [submodule "3rdparty/GSL_LITE"] 8 | path = 3rdparty/GSL_LITE 9 | url = https://github.com/martinmoene/gsl-lite.git 10 | [submodule "3rdparty/lexertl14"] 11 | path = 3rdparty/lexertl14 12 | url = https://github.com/BenHanson/lexertl14 13 | [submodule "3rdparty/Catch2"] 14 | path = 3rdparty/Catch2 15 | url = https://github.com/catchorg/Catch2.git 16 | [submodule "3rdparty/ghc_filesystem"] 17 | path = 3rdparty/ghc_filesystem 18 | url = https://github.com/gulrak/filesystem.git 19 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | submodules: 9 | include: all 10 | recursive: true 11 | 12 | # it appears that the conda `cmake` finds `conda` installed packages 13 | # fine, but if cmake is installed through `pyproject.toml`, that CMake 14 | # doesn't find HDF5, if the hdf5 headers are available by the system, then 15 | # it works 16 | build: 17 | os: "ubuntu-20.04" 18 | apt_packages: 19 | - libhdf5-dev 20 | tools: 21 | python: "3.9" 22 | 23 | sphinx: 24 | configuration: doc/source/conf.py 25 | 26 | python: 27 | install: 28 | - method: pip 29 | path: . 30 | extra_requirements: 31 | - docs 32 | -------------------------------------------------------------------------------- /3rdparty/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(HDF5 REQUIRED) 2 | 3 | if (NOT EXTERNAL_HIGHFIVE) 4 | set(HIGHFIVE_EXAMPLES OFF CACHE BOOL "" FORCE) 5 | set(HIGHFIVE_UNIT_TESTS OFF CACHE BOOL "" FORCE) 6 | set(HIGHFIVE_USE_BOOST OFF CACHE BOOL "" FORCE) 7 | set(HIGHFIVE_USE_INSTALL_DEPS ON CACHE BOOL "" FORCE) 8 | add_subdirectory(HighFive) 9 | target_include_directories(HighFive SYSTEM INTERFACE) 10 | endif() 11 | 12 | add_subdirectory(GSL_LITE) 13 | target_include_directories(gsl-lite SYSTEM INTERFACE) 14 | 15 | add_library(lexertl INTERFACE) 16 | target_include_directories(lexertl SYSTEM INTERFACE lexertl14/include) 17 | 18 | add_subdirectory(ghc_filesystem) 19 | 20 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | Adrien Devresse 2 | Ahmet Bilgili 3 | Aleksei Sanin 4 | Alexander Dietz 5 | Alexandru Săvulescu 6 | Andrew Hale 7 | Antonio Bellotta 8 | Arseny V. Povolotsky 9 | Ben Beasley 10 | Benoît Coste 11 | Chevtchenko Grigori 12 | Cyrille Favreau 13 | Daniel Nachbaur 14 | Eleftherios Zisis 15 | Fernando Pereira 16 | Jafet Villafranca 17 | Jean-Denis Courcol 18 | Juan Hernando Vieites 19 | Matthias Wolf 20 | Mike Gevaert (maintainer) 21 | Mohamed-Ghaith Kaabi 22 | Nicolas Cornu 23 | Pablo Toharia 24 | Raphael Dumusc 25 | Snigda Dagar 26 | Stefan Eilemann 27 | Thomas Delemontex 28 | Tristan Carel 29 | -------------------------------------------------------------------------------- /CMake/CompilerFlags.cmake: -------------------------------------------------------------------------------- 1 | if (WIN32) 2 | set(FLAGS "${FLAGS} /DH5_BUILT_AS_DYNAMIC_LIB") 3 | 4 | # Exception handling 5 | # s: Enables standard C++ stack unwinding. 6 | # c: [assume] functions declared as extern "C" never throw a C++ exception. 7 | set(FLAGS "${FLAGS} /EHsc") 8 | 9 | # get access to M_PI constant 10 | set(FLAGS "${FLAGS} /D_USE_MATH_DEFINES") 11 | 12 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 13 | # Taken from https://github.com/BlueBrain/hpc-coding-conventions/blob/master/cpp/cmake/bob.cmake#L192-L255 14 | if(${PROJECT_NAME}_CXX_WARNINGS) 15 | if(${PROJECT_NAME}_WERROR) 16 | set(FLAGS "${FLAGS} -Werror") 17 | endif() 18 | set(FLAGS "${FLAGS} -Weverything") 19 | # Using std=c++11, no need for 98 compat 20 | set(FLAGS "${FLAGS} -Wno-c++98-compat") 21 | set(FLAGS "${FLAGS} -Wno-c++98-compat-pedantic") 22 | 23 | # allow static objects 24 | set(FLAGS "${FLAGS} -Wno-global-constructors") 25 | set(FLAGS "${FLAGS} -Wno-exit-time-destructors") 26 | 27 | set(FLAGS "${FLAGS} -Wno-documentation") 28 | set(FLAGS "${FLAGS} -Wno-documentation-unknown-command") 29 | 30 | set(FLAGS "${FLAGS} -Wno-padded") 31 | set(FLAGS "${FLAGS} -Wno-weak-vtables") 32 | set(FLAGS "${FLAGS} -Wno-covered-switch-default") 33 | set(FLAGS "${FLAGS} -Wno-poison-system-directories") 34 | endif() 35 | if(APPLE) 36 | set(FLAGS "${FLAGS} -Wno-undef") 37 | if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "8.0.0") 38 | set(FLAGS "${FLAGS} -fcomment-block-commands=file") 39 | endif() 40 | else() 41 | if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "5.0.0") 42 | set(FLAGS "${FLAGS} -fcomment-block-commands=file") 43 | endif() 44 | if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "5.0.0") 45 | set(FLAGS "${FLAGS} -fcomment-block-commands=file") 46 | endif() 47 | endif() 48 | 49 | elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") 50 | if(${PROJECT_NAME}_CXX_WARNINGS) 51 | if(${PROJECT_NAME}_WERROR) 52 | set(FLAGS "${FLAGS} -Werror") 53 | endif() 54 | set(FLAGS "${FLAGS} -Wall") 55 | set(FLAGS "${FLAGS} -Wcast-align") 56 | set(FLAGS "${FLAGS} -Wconversion") 57 | set(FLAGS "${FLAGS} -Wdouble-promotion") 58 | set(FLAGS "${FLAGS} -Wextra") 59 | set(FLAGS "${FLAGS} -Wformat=2") 60 | set(FLAGS "${FLAGS} -Wnon-virtual-dtor") 61 | set(FLAGS "${FLAGS} -Wold-style-cast") 62 | set(FLAGS "${FLAGS} -Woverloaded-virtual") 63 | set(FLAGS "${FLAGS} -Wshadow") 64 | set(FLAGS "${FLAGS} -Wsign-conversion") 65 | set(FLAGS "${FLAGS} -Wunused") 66 | set(FLAGS "${FLAGS} -Wuseless-cast") 67 | if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "6.0") 68 | set(FLAGS "${FLAGS} -Wduplicated-cond") 69 | set(FLAGS "${FLAGS} -Wmisleading-indentation") 70 | set(FLAGS "${FLAGS} -Wnull-dereference") 71 | endif() 72 | if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "7.0") 73 | set(FLAGS "${FLAGS} -Wduplicated-branches") 74 | set(FLAGS "${FLAGS} -Wlogical-op") 75 | set(FLAGS "${FLAGS} -Wrestrict") 76 | endif() 77 | if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "8.0") 78 | set(FLAGS "${FLAGS} -Wclass-memaccess") 79 | endif() 80 | endif() 81 | elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel") 82 | 83 | else() 84 | message(WARNING "Unexpected compiler type ${CMAKE_CXX_COMPILER_ID}") 85 | endif() 86 | -------------------------------------------------------------------------------- /CMake/MorphIOConfig.cmake: -------------------------------------------------------------------------------- 1 | include(CMakeFindDependencyMacro) 2 | 3 | find_dependency(gsl-lite) 4 | find_dependency(HighFive) 5 | 6 | include("${CMAKE_CURRENT_LIST_DIR}/MorphIOTargets.cmake") 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | #allow using of HDF5_ROOT for building with a custom HDF5 version 3 | cmake_policy(SET CMP0074 NEW) 4 | project(MorphIO VERSION 2.0.0) 5 | 6 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 7 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 8 | set(CMAKE_VERBOSE_MAKEFILE ON) 9 | 10 | option(BUILD_BINDINGS "Build the python bindings" ON) 11 | option(MorphIO_CXX_WARNINGS "Compile C++ with warnings" ON) 12 | option(MorphIO_WERROR "If compiled with warnings, additionally activate '-Werror'" ON) 13 | option(EXTERNAL_CATCH2 "Use Catch2 from external source" OFF) 14 | option(EXTERNAL_HIGHFIVE "Use HighFive from external source" OFF) 15 | option(EXTERNAL_PYBIND11 "Use pybind11 from external source" OFF) 16 | option(MORPHIO_TESTS "Build tests" ON) 17 | option(MORPHIO_USE_DOUBLE "Use doubles instead of floats" OFF) 18 | 19 | if (NOT DEFINED MORPHIO_ENABLE_COVERAGE) 20 | if (CMAKE_BUILD_TYPE STREQUAL "Debug") 21 | set(MORPHIO_ENABLE_COVERAGE ON) 22 | else() 23 | set(MORPHIO_ENABLE_COVERAGE OFF) 24 | endif() 25 | endif() 26 | 27 | if(MORPHIO_USE_DOUBLE) 28 | add_definitions(-DMORPHIO_USE_DOUBLE) 29 | message("Floating Point Type: double") 30 | else() 31 | message("Floating Point Type: float") 32 | endif() 33 | 34 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake) 35 | include(CompilerFlags) 36 | 37 | set(CMAKE_CXX_FLAGS "${FLAGS}") 38 | 39 | set(CMAKE_CXX_STANDARD 14) 40 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 41 | 42 | if (EXTERNAL_HIGHFIVE) 43 | find_package(HighFive REQUIRED) 44 | endif() 45 | if (EXTERNAL_PYBIND11) 46 | find_package(pybind11 REQUIRED CONFIG) 47 | endif() 48 | set(MORPHIO_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include/) 49 | 50 | add_subdirectory(3rdparty) 51 | add_subdirectory(src) 52 | 53 | if(BUILD_BINDINGS) 54 | add_subdirectory(binds/python) 55 | endif(BUILD_BINDINGS) 56 | 57 | include(GNUInstallDirs) 58 | 59 | install( 60 | DIRECTORY ${MORPHIO_INCLUDE_DIR} 61 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 62 | ) 63 | 64 | install( 65 | EXPORT MorphIOTargets 66 | NAMESPACE MorphIO:: 67 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MorphIO 68 | ) 69 | 70 | install( 71 | FILES ${CMAKE_CURRENT_LIST_DIR}/CMake/MorphIOConfig.cmake 72 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MorphIO 73 | ) 74 | 75 | 76 | if (MORPHIO_TESTS) 77 | enable_testing() 78 | if (EXTERNAL_CATCH2) 79 | find_package(Catch2 REQUIRED) 80 | else() 81 | add_subdirectory(3rdparty/Catch2) 82 | include(3rdparty/Catch2/contrib/Catch.cmake) 83 | endif() 84 | add_subdirectory(tests) 85 | endif() 86 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # MorphIO c++ 2 | graft src 3 | graft include 4 | include CMakeLists.txt 5 | 6 | # MorphIO submodule dependencies 7 | include 3rdparty/GSL_LITE/CMakeLists.txt 3rdparty/GSL_LITE/gsl-lite.natvis 8 | recursive-include 3rdparty/GSL_LITE/cmake * 9 | recursive-include 3rdparty/GSL_LITE/include * 10 | 11 | include 3rdparty/HighFive/CMakeLists.txt 12 | recursive-include 3rdparty/HighFive/include * 13 | recursive-include 3rdparty/HighFive/CMake * 14 | recursive-include 3rdparty/HighFive/doc * 15 | 16 | include 3rdparty/lexertl14/CMakeLists.txt 17 | recursive-include 3rdparty/lexertl14/include/lexertl * 18 | 19 | # ghc::filesystem 20 | recursive-include 3rdparty/ghc_filesystem/include * 21 | recursive-include 3rdparty/ghc_filesystem/cmake * 22 | include 3rdparty/ghc_filesystem/CMakeLists.txt 23 | include 3rdparty/ghc_filesystem/LICENSE 24 | 25 | # pybind11 for python bindings 26 | recursive-include binds/python/pybind11/include * 27 | recursive-include binds/python/pybind11/tools *.cmake 28 | include binds/python/pybind11/CMakeLists.txt 29 | include binds/python/pybind11/LICENSE 30 | 31 | # setuptools_scm forces all SCM files to be packaged into sdist 32 | # we need to manually exclude them to prevent their inclusion 33 | # see https://github.com/pypa/setuptools_scm/issues/190 34 | prune ci 35 | prune doc 36 | prune tests 37 | prune scripts 38 | prune examples 39 | 40 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. warning:: 2 | The Blue Brain Project concluded in December 2024, so development has ceased under the BlueBrain GitHub organization. 3 | Future development will take place at: https://github.com/openbraininstitute/MorphIO 4 | 5 | .. image:: doc/source/logo/BBP-MorphIO.jpg 6 | 7 | 8 | |license| |docs| 9 | 10 | MorphIO 11 | ======= 12 | 13 | Documentation 14 | ------------- 15 | 16 | MorphIO documentation is built and hosted on `readthedocs `_. 17 | 18 | * `latest snapshot `_ 19 | * `latest release `_ 20 | 21 | Introduction 22 | ------------ 23 | 24 | MorphIO is a library for reading and writing neuron morphology files. It supports the following 25 | formats: 26 | 27 | * SWC 28 | * ASC (aka. neurolucida) 29 | * H5 v1 30 | * H5 v2 is not supported anymore, see `H5v2`_ 31 | 32 | It provides 3 C++ classes that are the starting point of every morphology analysis: 33 | 34 | * ``Soma``: contains the information related to the soma. 35 | 36 | * ``Section``: a section is the succession of points between two bifurcations. To the bare minimum 37 | the ``Section`` object will contain the section type, the position and diameter of each point. 38 | 39 | * ``Morphology``: the morphology object contains general information about the loaded cell 40 | but also provides accessors to the different sections. 41 | 42 | One important concept is that MorphIO is split into a *read-only* part and a *read/write* one. 43 | 44 | 45 | H5v2 46 | ==== 47 | 48 | Starting at version 2.6.0, the file format ``h5v2`` is no longer supported. If you have 49 | morphologies in this format, you can convert them to h5v1 with: 50 | 51 | .. code-block:: bash 52 | 53 | pip install "morphio<2.6" "morph-tool==2.3.0" 54 | 55 | and then: 56 | 57 | .. code-block:: bash 58 | 59 | # single file, OUTPUT must end with `.h5` 60 | morph-tool convert file INPUTFILE OUTPUT 61 | # bulk conversion 62 | morph-tool convert folder -ext h5 INPUTDIR OUTPUTDIR 63 | 64 | 65 | Contributing 66 | ============ 67 | If you want to improve the project or you see any issue, every contribution is welcome. 68 | Please check the `contribution guidelines `_ for more 69 | information. 70 | 71 | Acknowledgements 72 | ================ 73 | The development of this software was supported by funding to the Blue Brain Project, a research center of the École polytechnique fédérale de Lausanne (EPFL), from the Swiss government’s ETH Board of the Swiss Federal Institutes of Technology. 74 | 75 | This research was supported by the EBRAINS research infrastructure, funded from the European Union’s Horizon 2020 Framework Programme for Research and Innovation under the Specific Grant Agreement No. 945539 (Human Brain Project SGA3). 76 | 77 | License 78 | ======= 79 | MorphIO is licensed under the terms of the Apache License 2.0. 80 | See LICENSE.txt for further details. 81 | 82 | Copyright (c) 2013-2024 Blue Brain Project/EPFL 83 | 84 | .. |license| image:: https://img.shields.io/pypi/l/morphio 85 | :target: https://github.com/BlueBrain/morphio/blob/master/COPYING.LESSER 86 | 87 | .. |docs| image:: https://readthedocs.org/projects/morphio/badge/?version=latest 88 | :target: https://morphio.readthedocs.io/ 89 | :alt: documentation status 90 | 91 | -------------------------------------------------------------------------------- /binds/python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (NOT EXTERNAL_PYBIND11) 2 | add_subdirectory(pybind11 EXCLUDE_FROM_ALL) 3 | endif() 4 | 5 | pybind11_add_module(_morphio SYSTEM 6 | morphio.cpp 7 | 8 | bind_enums.cpp 9 | bind_immutable.cpp 10 | bind_misc.cpp 11 | bind_mutable.cpp 12 | bind_vasculature.cpp 13 | bind_warnings_exceptions.cpp 14 | bindings_utils.cpp 15 | ) 16 | 17 | target_link_libraries(_morphio 18 | PRIVATE morphio_static 19 | PRIVATE pybind11::module 20 | ) 21 | -------------------------------------------------------------------------------- /binds/python/bind_enums.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | 9 | enum IterType { DEPTH_FIRST, BREADTH_FIRST, UPSTREAM }; 10 | 11 | void bind_enums(pybind11::module&); 12 | -------------------------------------------------------------------------------- /binds/python/bind_immutable.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | 9 | void bind_immutable(pybind11::module& m); 10 | -------------------------------------------------------------------------------- /binds/python/bind_misc.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | 9 | void bind_misc(pybind11::module&); 10 | -------------------------------------------------------------------------------- /binds/python/bind_mutable.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | void bind_mutable(pybind11::module& m); 22 | -------------------------------------------------------------------------------- /binds/python/bind_vasculature.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | 9 | void bind_vasculature(pybind11::module&); 10 | -------------------------------------------------------------------------------- /binds/python/bind_warnings_exceptions.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | 9 | void bind_warnings_exceptions(pybind11::module&); 10 | -------------------------------------------------------------------------------- /binds/python/bindings_utils.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include "bindings_utils.h" 6 | 7 | #include 8 | 9 | #include // py::array_t 10 | 11 | #include 12 | #include 13 | 14 | #include // morphio::MorphioError 15 | #include 16 | 17 | namespace py = pybind11; 18 | 19 | namespace { 20 | 21 | void _raise_if_wrong_shape(const py::buffer_info& info) { 22 | const auto& shape = info.shape; 23 | if (shape.size() != 2 || info.shape[1] != 3) { 24 | std::string shape_str; 25 | for (unsigned int i = 0; i < shape.size(); ++i) { 26 | shape_str += std::to_string(shape[i]); 27 | if (i != shape.size() - 1) { 28 | shape_str += ", "; 29 | } 30 | } 31 | throw morphio::MorphioError("Wrong array shape. Expected: (X, 3), got: (" + shape_str + 32 | ")"); 33 | } 34 | } 35 | } // anonymous namespace 36 | 37 | morphio::Points array_to_points(const py::array_t& buf) { 38 | py::buffer_info info = buf.request(); 39 | _raise_if_wrong_shape(info); 40 | morphio::Points points; 41 | points.reserve(static_cast(info.shape[0])); 42 | 43 | for (int i = 0; i < info.shape[0]; ++i) { 44 | points.push_back({*buf.data(i, 0), *buf.data(i, 1), *buf.data(i, 2)}); 45 | } 46 | return points; 47 | } 48 | 49 | py::array_t span_array_to_ndarray( 50 | const morphio::range>& span) { 51 | const void* ptr = static_cast(span.data()); 52 | const auto buffer_info = py::buffer_info( 53 | // Cast from (const void*) to (void*) for function signature matching 54 | const_cast(ptr), /* Pointer to buffer */ 55 | sizeof(morphio::floatType), /* Size of one scalar */ 56 | py::format_descriptor::format(), /* Python struct-style format 57 | descriptor */ 58 | 2, /* Number of dimensions */ 59 | 60 | // Forced cast to prevent error: 61 | // template argument deduction/substitution failed */ 62 | {static_cast(span.size()), 3}, /* buffer dimentions */ 63 | {sizeof(morphio::floatType) * 3, /* Strides (in bytes) for each index */ 64 | sizeof(morphio::floatType)}); 65 | return py::array(buffer_info); 66 | } 67 | -------------------------------------------------------------------------------- /binds/python/bindings_utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | namespace py = pybind11; 27 | 28 | morphio::Points array_to_points(const py::array_t& buf); 29 | py::array_t span_array_to_ndarray( 30 | const morphio::range& span); 31 | 32 | template 33 | py::array_t span_to_ndarray(const morphio::range& span) { 34 | const void* ptr = static_cast(span.data()); 35 | const auto buffer_info = py::buffer_info( 36 | // Cast from (const void*) to (void*) for function signature matching 37 | const_cast(ptr), /* Pointer to buffer */ 38 | sizeof(T), /* Size of one scalar */ 39 | py::format_descriptor::format(), /* Python struct-style format descriptor */ 40 | 1, /* Number of dimensions */ 41 | 42 | // Forced cast to prevent error: 43 | // template argument deduction/substitution failed */ 44 | {static_cast(span.size())}, /* buffer dimentions */ 45 | {sizeof(T)}); /* Strides (in bytes) for each index */ 46 | return py::array(buffer_info); 47 | } 48 | 49 | 50 | /** 51 | * @brief "Casts" a Cpp sequence to a python array (no memory copies) 52 | * Python capsule handles void pointers to objects and makes sure 53 | * that they will remain alive. 54 | * 55 | * https://github.com/pybind/pybind11/issues/1042#issuecomment-325941022 56 | */ 57 | template 58 | inline py::array_t as_pyarray(Sequence&& seq) { 59 | // Move entire object to heap. Memory handled via Python capsule 60 | Sequence* seq_ptr = new Sequence(std::move(seq)); 61 | // Capsule shall delete sequence object when done 62 | auto capsule = py::capsule(seq_ptr, [](void* p) { delete reinterpret_cast(p); }); 63 | 64 | return py::array(static_cast(seq_ptr->size()), // shape of array 65 | seq_ptr->data(), // c-style contiguous strides for Sequence 66 | capsule // numpy array references this parent 67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /binds/python/generated/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | DisableFormat: true 3 | SortIncludes: false 4 | ... 5 | -------------------------------------------------------------------------------- /binds/python/morphio.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | #include "bind_enums.h" 8 | #include "bind_immutable.h" 9 | #include "bind_misc.h" 10 | #include "bind_mutable.h" 11 | #include "bind_vasculature.h" 12 | #include "bind_warnings_exceptions.h" 13 | 14 | 15 | namespace py = pybind11; 16 | 17 | #if defined(__clang__) 18 | #pragma clang diagnostic push 19 | #pragma clang diagnostic ignored "-Wunknown-warning-option" 20 | #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" 21 | #endif 22 | 23 | PYBIND11_MODULE(_morphio, m) { 24 | bind_enums(m); 25 | bind_warnings_exceptions(m); 26 | bind_misc(m); 27 | 28 | bind_immutable(m); 29 | 30 | py::module mut_module = m.def_submodule("mut"); 31 | bind_mutable(mut_module); 32 | 33 | py::module vasc_module = m.def_submodule("vasculature"); 34 | bind_vasculature(vasc_module); 35 | } 36 | 37 | #if defined(__clang__) 38 | #pragma clang diagnostic pop 39 | #endif 40 | -------------------------------------------------------------------------------- /ci/check_clang_format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Install the desired clang-format, check the lines 4 | # changed by this diff are formatted correctly 5 | 6 | set -euo pipefail 7 | 8 | VENV=venv-clang-format 9 | CLANG_FORMAT_VERSION=9.0.0 10 | 11 | if [[ ! -d $VENV ]]; then 12 | python3 -mvenv "$VENV" 13 | "$VENV/bin/pip" install --upgrade pip 14 | "$VENV/bin/pip" install clang-format=="$CLANG_FORMAT_VERSION" 15 | fi 16 | 17 | set +u # ignore errors in virtualenv's activate 18 | source "$VENV/bin/activate" 19 | set -u 20 | 21 | changes=$(git-clang-format 'HEAD~1') 22 | if [[ $(echo "$changes" | grep -n1 'changed files') ]]; then 23 | echo "The following files require changes to pass the current clang-format" 24 | echo "$changes" 25 | echo "Run ./ci/check_clang_format.sh to apply the required changes to your repo" 26 | exit 1 27 | fi 28 | -------------------------------------------------------------------------------- /ci/check_generated_docstrings.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check the generated docstrings 4 | # 5 | # pybind11 ships with mkdoc.py which extracts python docstrings 6 | # from the C++ doxygen comments. This is beneficial for maintaining 7 | # consistency and reducing duplication. 8 | # 9 | # In order to enable morphio to be built without enforcing clang 10 | # as a dependency (required by mkdoc.py), we include the generated 11 | # docstrings in source control. 12 | # 13 | # In order to ensure they are being kept up-to-date, the CI process 14 | # regenerates them and checks there are no diffs. 15 | 16 | set -x 17 | set -euo pipefail 18 | 19 | if [[ -z $LIBCLANG_PATH ]]; then 20 | echo "Expect a \$LIBCLANG_PATH in the environment, it should have the path to the libclang.so" 21 | exit -1 22 | fi 23 | 24 | 25 | VERSION=no-reserved 26 | PACKAGE=git+https://github.com/mgeplf/pybind11_mkdoc.git@$VERSION 27 | #PACKAGE=git+https://github.com/pybind/pybind11_mkdoc.git@master 28 | 29 | VENV=build/venv-docstrings 30 | if [[ ! -d $VENV ]]; then 31 | python3 -mvenv "$VENV" 32 | $VENV/bin/pip install -U pip setuptools wheel 33 | $VENV/bin/pip install 'clang==12.0.1' # keep in sync w/ .github/workflows/docstring_check.yaml 34 | $VENV/bin/python -m pip install $PACKAGE 35 | fi 36 | 37 | DOCSTRING_PATH=./binds/python/generated/docstrings.h 38 | rm -f $DOCSTRING_PATH 39 | 40 | $VENV/bin/python -m pybind11_mkdoc \ 41 | -o $DOCSTRING_PATH \ 42 | -Wno-pragma-once-outside-header \ 43 | -ferror-limit=100000 \ 44 | -I/usr/include/hdf5/serial \ 45 | -I./3rdparty/HighFive/include \ 46 | -I./3rdparty/GSL_LITE/include \ 47 | -I./include \ 48 | ./include/morphio/mut/*.h \ 49 | ./include/morphio/vasc/*.h \ 50 | ./include/morphio/*.h 51 | 52 | # fail if there are diffs in the generated docstrings 53 | git diff --exit-code -- ./binds/python/generated/docstrings.h 54 | -------------------------------------------------------------------------------- /ci/coverage_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This builds coverage information, including HTML output 4 | 5 | set -euxo pipefail 6 | 7 | if [ $# -ge 1 ]; then 8 | EXTRA_OPTIONS=$1 9 | else 10 | EXTRA_OPTIONS="" 11 | fi 12 | 13 | BUILD_DIR=build/build-coverage 14 | 15 | rm -rf "$BUILD_DIR" 16 | mkdir -p "$BUILD_DIR" 17 | pushd "$BUILD_DIR" 18 | 19 | cmake \ 20 | -DCMAKE_BUILD_TYPE=Debug \ 21 | -DHIGHFIVE_EXAMPLES=OFF \ 22 | -DHIGHFIVE_UNIT_TESTS=OFF \ 23 | -G"Unix Makefiles" \ 24 | ${EXTRA_OPTIONS} \ 25 | ../.. 26 | 27 | make -j all coverage 28 | -------------------------------------------------------------------------------- /ci/cpp_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This file runs the C++ tests, as well as compiling the code with warnings on 4 | # so that errors should be caught quicker. Extra options can be passed in via $1 5 | # i.e. : ./cpp_test.sh "-DMORPHIO_USE_DOUBLE=ON" 6 | 7 | set -euxo pipefail 8 | 9 | BUILD_DIR=build/cpp_test 10 | 11 | if [ $# -ge 1 ]; then 12 | EXTRA_OPTIONS=$1 13 | else 14 | EXTRA_OPTIONS="" 15 | fi 16 | 17 | rm -rf $BUILD_DIR 18 | mkdir -p $BUILD_DIR 19 | pushd $BUILD_DIR 20 | cmake -DMorphIO_CXX_WARNINGS=ON -G "${CMAKE_GENERATOR:-Unix Makefiles}" ${EXTRA_OPTIONS} ../.. 21 | cmake --build . -j 22 | ctest -VV 23 | popd 24 | -------------------------------------------------------------------------------- /ci/hdf5-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -x 3 | 4 | : "${UNIXY_HDF5_VERSION:=1.14.3}" 5 | : "${CIBW_ARCHS_MACOS:=$(uname -m)}" 6 | 7 | export INPUT=$(cd $(dirname "$1") && pwd -P)/$(basename "$1") 8 | export OUTPUT="$INPUT/install-$CIBW_ARCHS_MACOS" 9 | 10 | 11 | function download_unpack_hdf5 { 12 | pushd "$INPUT" 13 | local name=CMake-hdf5-$UNIXY_HDF5_VERSION.tar.gz 14 | if [[ ! -e $name ]]; then 15 | echo "Downloading & unpacking HDF5 ${UNIXY_HDF5_VERSION}" 16 | curl -fsSLO "https://hdf-wordpress-1.s3.amazonaws.com/wp-content/uploads/manual/HDF5/HDF5_${UNIXY_HDF5_VERSION//\./_}/src/$name" 17 | fi 18 | tar xzf "$name" 19 | popd 20 | } 21 | 22 | if [[ "$OSTYPE" == "darwin"* ]]; then 23 | NPROC=$(sysctl -n hw.ncpu) 24 | else 25 | NPROC=$(nproc) 26 | fi 27 | 28 | INSTALL="$OUTPUT/install" 29 | 30 | if [[ -f "$INSTALL/lib/libhdf5.a" ]]; then 31 | echo "using cached build" 32 | else 33 | if [[ "$OSTYPE" == "darwin"* ]]; then 34 | export CC="/usr/bin/clang" 35 | export CXX="/usr/bin/clang" 36 | export CFLAGS="$CFLAGS -arch $CIBW_ARCHS_MACOS" 37 | export CPPFLAGS="$CPPFLAGS -arch $CIBW_ARCHS_MACOS" 38 | export CXXFLAGS="$CXXFLAGS -arch $CIBW_ARCHS_MACOS" 39 | fi 40 | 41 | echo "Building & installing hdf5" 42 | download_unpack_hdf5 43 | 44 | cmake -B "$OUTPUT/build" -G'Unix Makefiles' \ 45 | -DCMAKE_BUILD_TYPE=RelWithDebInfo \ 46 | -DBUILD_SHARED_LIBS=OFF \ 47 | -DHDF5_BUILD_UTILS=OFF \ 48 | -DHDF5_BUILD_HL_LIB=OFF \ 49 | -DHDF5_BUILD_EXAMPLES=OFF \ 50 | -DBUILD_TESTING=OFF \ 51 | -DHDF5_BUILD_TOOLS=OFF \ 52 | -DHDF5_ENABLE_SZIP_ENCODING=OFF \ 53 | -DHDF5_ENABLE_Z_LIB_SUPPORT=OFF \ 54 | -DCMAKE_INSTALL_PREFIX="$INSTALL" \ 55 | -S "$INPUT/CMake-hdf5-$UNIXY_HDF5_VERSION/hdf5-$UNIXY_HDF5_VERSION" 56 | 57 | cmake --build "$OUTPUT/build" -j "$NPROC" 58 | cmake --install "$OUTPUT/build" 59 | fi 60 | 61 | find "$OUTPUT" 62 | -------------------------------------------------------------------------------- /ci/python_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | VENV=env 6 | 7 | function create_venv() 8 | { 9 | if [[ "$OSTYPE" != "msys" ]]; then 10 | rm -rf "$VENV" 11 | python3 -mvenv "$VENV" 12 | 13 | set +u # ignore errors in virtualenv's activate 14 | source "$VENV/bin/activate" 15 | set -u 16 | 17 | $VENV/bin/pip install --upgrade pip setuptools wheel 18 | fi 19 | } 20 | 21 | # in tree install 22 | create_venv 23 | 24 | $VENV/bin/pip -v install --force . 25 | $VENV/bin/pip -v install -r tests/requirement_tests.txt 26 | 27 | 28 | pushd $(pwd)/tests 29 | pytest . 30 | popd 31 | 32 | deactivate 33 | 34 | # sdist install 35 | DIST_DIR="$VENV/dist" 36 | mkdir -p "$DIST_DIR" 37 | create_venv 38 | 39 | python3 -m pip install build 40 | python3 -m build . --outdir "$DIST_DIR" 41 | python3 -m pip install "$DIST_DIR"/morphio*.tar.gz 42 | python3 -m pip install -r tests/requirement_tests.txt 43 | 44 | pushd $(pwd)/tests 45 | pytest . 46 | popd 47 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | # @source/build_intersphinx_objects.sh 15 | 16 | .PHONY: help Makefile 17 | 18 | # Catch-all target: route all unknown targets to Sphinx using the new 19 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 20 | %: Makefile 21 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 22 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | ### Local doc building 2 | 3 | For building documentation locally, make sure you have `sphinx-bluebrain-theme` and `doxygen`. 4 | 5 | ```bash 6 | pip install sphinx-bluebrain-theme 7 | ``` 8 | 9 | and 10 | 11 | ```bash 12 | # for Linux 13 | sudo apt install doxygen 14 | # for MacOS 15 | brew install doxygen 16 | ``` 17 | -------------------------------------------------------------------------------- /doc/source/_templates/doxygen_page.rst_t: -------------------------------------------------------------------------------- 1 | {{ title }} 2 | {{ "=" * title | length }} 3 | 4 | .. iframe:: ../cpp/{{ file }} 5 | -------------------------------------------------------------------------------- /doc/source/cpp.rst: -------------------------------------------------------------------------------- 1 | C++ API 2 | ======= 3 | 4 | .. toctree:: 5 | :hidden: 6 | :glob: 7 | 8 | cpp/** 9 | -------------------------------------------------------------------------------- /doc/source/doxygen/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/doc/source/doxygen/.gitignore -------------------------------------------------------------------------------- /doc/source/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /doc/source/glia.rst: -------------------------------------------------------------------------------- 1 | Glia 2 | ==== 3 | 4 | MorphIO also support reading and writing glia (such as astrocytes) from/to disk according to the 5 | `H5 specification `__ 6 | 7 | 8 | .. code-block:: python 9 | 10 | import morphio 11 | 12 | # Immutable 13 | immutable_glia = morphio.GlialCell("astrocyte.h5") 14 | 15 | # Mutable 16 | empty_glia = morphio.mut.GlialCell() 17 | mutable_glia = morphio.mut.GlialCell("astrocyte.h5") 18 | -------------------------------------------------------------------------------- /doc/source/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $projectname: $title 10 | $title 11 | 19 | 20 | $extrastylesheet 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | .. image:: logo/BBP-MorphIO.jpg 2 | 3 | .. include:: ../../README.rst 4 | :start-line: 2 5 | 6 | .. toctree:: 7 | :hidden: 8 | 9 | Home 10 | install 11 | morphology 12 | glia 13 | mitochondria 14 | reticulum 15 | markers 16 | warnings 17 | python 18 | cpp 19 | specification 20 | specification_neurolucida 21 | -------------------------------------------------------------------------------- /doc/source/install.rst: -------------------------------------------------------------------------------- 1 | Install 2 | ======= 3 | 4 | Dependencies 5 | ------------ 6 | 7 | To build MorphIO from sources, the following dependencies are required: 8 | 9 | * cmake >= 3.2 10 | * libhdf5-dev 11 | * A C++11 compiler 12 | 13 | Debian: 14 | 15 | .. code-block:: shell 16 | 17 | sudo apt install cmake libhdf5-dev 18 | 19 | Red Hat: 20 | 21 | .. code-block:: shell 22 | 23 | sudo yum install cmake3.x86_64 hdf5-devel.x86_64 24 | 25 | Max OS: 26 | 27 | .. code-block:: shell 28 | 29 | brew install hdf5 cmake 30 | 31 | 32 | Install as a C++ library 33 | ------------------------ 34 | 35 | For manual installation: 36 | 37 | .. code-block:: shell 38 | 39 | git clone git@github.com:bluebrain/morphio.git --recursive 40 | cd morphio 41 | mkdir build && cd build 42 | cmake .. 43 | make install 44 | 45 | To use the installed library: 46 | 47 | .. code-block:: CMake 48 | 49 | find_package(MorphIO REQUIRED) 50 | target_link_libraries(mylib MorphIO::morphio) 51 | 52 | 53 | Install as a Python package 54 | --------------------------- 55 | 56 | The python binding can directly be installed using pip: 57 | 58 | .. code-block:: shell 59 | 60 | pip install morphio 61 | -------------------------------------------------------------------------------- /doc/source/logo/BBP-MorphIO.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/doc/source/logo/BBP-MorphIO.jpg -------------------------------------------------------------------------------- /doc/source/mitochondria.rst: -------------------------------------------------------------------------------- 1 | .. _mitochondria-readme: 2 | 3 | Mitochondria 4 | ============ 5 | 6 | It is also possible to read and write mitochondria from/to the h5 files (*SWC and ASC are not 7 | supported*). As mitochondria can be represented as trees, one can define the concept of 8 | *mitochondrial section* similar to neuronal section and end up with a similar API. The morphology 9 | object has a *mitochondria* handle method that exposes the basic methods: 10 | 11 | * ``root_sections``: returns the section ID of the starting mitochondrial section of each 12 | mitochondrion. 13 | * ``section(id)``: returns a given mitochondrial section 14 | * ``append_section``: creates a new mitochondrial section 15 | * ``depth_begin``: a depth first iterator 16 | * ``breadth_begin``: a breadth first iterator 17 | * ``upstream_begin``: an upstream iterator 18 | 19 | .. code-block:: python 20 | 21 | from morphio import MitochondriaPointLevel, PointLevel, SectionType 22 | from morphio.mut import Morphology 23 | 24 | morpho = Morphology() 25 | 26 | # A neuronal section that will store mitochondria 27 | section = morpho.append_root_section( 28 | PointLevel([[2, 2, 2], [3, 3, 3]], [4, 4], [5, 5]), 29 | SectionType.axon) 30 | 31 | # Creating a new mitochondrion 32 | mito_id = morpho.mitochondria.append_section( 33 | -1, 34 | MitochondriaPointLevel([section.id, section.id], # section id hosting the mitochondria point 35 | [0.5, 0.6], # relative distance between the start of the section and the point 36 | [10, 20] # mitochondria diameters 37 | )) 38 | 39 | # Appending a new mitochondrial section to the previous one 40 | morpho.mitochondria.append_section( 41 | mito_id, MitochondriaPointLevel([0, 0, 0, 0], 42 | [0.6, 0.7, 0.8, 0.9], 43 | [20, 30, 40, 50])) 44 | 45 | # Iteration works the same as iteration on neuronal sections 46 | first_root = morpho.mitochondria.root_sections[0] 47 | for section_id in morpho.mitochondria.depth_begin(first_root): 48 | section = morpho.mitochondria.section(section_id) 49 | print('relative_path_length - diameter') 50 | for relative_path_length, diameter in zip(section.diameters, 51 | section.relative_path_lengths): 52 | print("{} - {}".format(relative_path_length, diameter)) 53 | 54 | Reading mithochondria from H5 files: 55 | 56 | .. code-block:: python 57 | 58 | from morphio import Morphology 59 | 60 | morpho = Morphology("file_with_mithochondria.h5") 61 | 62 | for mitochondrial_section in morpho.mitochondria.root_sections: 63 | print('{neurite_id}, {relative_path_lengths}, {diameters}'.format( 64 | neurite_id=mitochondrial_section.neurite_section_ids, 65 | relative_path_lengths=mitochondrial_section.relative_path_lengths, 66 | diameters=mitochondrial_section.diameters)) 67 | 68 | print("Number of children: {}".format(len(mitochondrial_section.children))) 69 | -------------------------------------------------------------------------------- /doc/source/python.rst: -------------------------------------------------------------------------------- 1 | Python API 2 | ========== 3 | 4 | Immutable objects 5 | ***************** 6 | 7 | .. automodule:: morphio 8 | 9 | Mutable objects 10 | *************** 11 | 12 | .. automodule:: morphio.mut 13 | -------------------------------------------------------------------------------- /doc/source/reticulum.rst: -------------------------------------------------------------------------------- 1 | Endoplasmic reticulum 2 | ===================== 3 | 4 | Endoplasmic reticulum can also be stored and written to H5 file. The specification is part of the 5 | `BBP morphology documentation `__ 6 | There is one endoplasmic reticulum object per morphology. It contains 4 attributes. Each attribute 7 | is an array and each line refers to the value of the attribute for a specific neuronal section. 8 | 9 | * section_index: Each row of this dataset represents the index of a neuronal section. Each row of 10 | the other properties (eg. volume) refer to the part of the reticulum present in the 11 | corresponding section for each row. 12 | * volume: One column dataset indexed by section_index. Contains volumes of the reticulum per each 13 | corresponding section it lies in. 14 | * surface_area: Similar to the volume dataset, this dataset represents the surface area of the 15 | reticulum in each section in the section_index dataset. 16 | * filament_count: This 1 column dataset is composed of integers that represent the number of 17 | filaments in the segment of the reticulum lying in the section referenced by the corresponding 18 | row in the section_index dataset. 19 | 20 | Reading endoplasmic reticula from H5 files 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | 23 | .. code-block:: python 24 | 25 | from morphio import Morphology 26 | 27 | morpho = Morphology('/my/file') 28 | reticulum = morpho.endoplasmic_reticulum 29 | print('{indices}, {volumes}, {areas}, {counts}'.format( 30 | indices=reticulum.section_indices, 31 | volumes=reticulum.volumes, 32 | areas=reticulum.surface_areas, 33 | counts=reticulum.filament_counts)) 34 | 35 | Writing endoplasmic reticula from H5 files 36 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | 38 | .. code-block:: python 39 | 40 | neuron = Morphology() 41 | 42 | reticulum = neuron.endoplasmic_reticulum 43 | reticulum.section_indices = [1, 1] 44 | reticulum.volumes = [2, 2] 45 | reticulum.surface_areas = [3, 3] 46 | reticulum.filament_counts = [4, 4] 47 | neuron.write('/my/out/file.h5') # Has to be written to h5 48 | -------------------------------------------------------------------------------- /doc/source/warnings.rst: -------------------------------------------------------------------------------- 1 | Warnings 2 | ======== 3 | 4 | MorphIO attempts to faithfully represent what is loaded from a morphology file. 5 | However, as a morphology is loaded, deviations from the specification and oddities can be noted - these are considered warnings. 6 | By default, the warnings are printed to the console, if no handler is specified. 7 | The recommendation is to provide a handler when loading or creating morphologies: 8 | 9 | .. code-block:: python 10 | 11 | warning_handler = morphio.WarningHandlerCollector() 12 | morph = Morphology('path/to/morph.swc', warning_handler=warning_handler) 13 | for w in warning_handler.get_all(): 14 | print(w.warning.line_numbers) 15 | 16 | Maximum number of warnings 17 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 | The maximum number of warnings can be set as: 19 | 20 | .. code-block:: python 21 | 22 | import morphio 23 | 24 | # Will stop displaying warnings after 100 warnings 25 | morphio.set_maximum_warnings(100) 26 | 27 | # Will never stop displaying warnings 28 | morphio.set_maximum_warnings(-1) 29 | 30 | # Warnings won't be displayed 31 | morphio.set_maximum_warnings(0) 32 | 33 | Ignore warnings 34 | ~~~~~~~~~~~~~~~ 35 | 36 | A type of warning can be ignored as shown below. For the complete list of warning types see :class:`morphio.Warning`. 37 | 38 | .. code-block:: python 39 | 40 | # ignore single warning 41 | morphio.set_ignored_warning(morphio.Warning.wrong_root_point, True) 42 | # stop ignoring it 43 | morphio.set_ignored_warning(morphio.Warning.wrong_root_point, False) 44 | # ignore a list of warnings 45 | morphio.set_ignored_warning([morphio.Warning.no_soma_found, 46 | morphio.Warning.zero_diameter], True) 47 | # stop ignoring them 48 | morphio.set_ignored_warning([morphio.Warning.no_soma_found, 49 | morphio.Warning.zero_diameter], False) 50 | 51 | For safety reasons you might want to disable warnings only for construction of morphology, and enable it back 52 | afterwards: 53 | 54 | .. code-block:: python 55 | 56 | try: 57 | morphio.set_ignored_warning(morphio.Warning.wrong_root_point, True) 58 | m = morphio.Morphology('path/to/morph') 59 | finally: 60 | morphio.set_ignored_warning(morphio.Warning.wrong_root_point, False) 61 | 62 | 63 | Raise warnings 64 | ~~~~~~~~~~~~~~ 65 | If you want MorphIO to be rigid and fail on any morphology anomaly, you can switch to raise warnings as errors. 66 | This way they also can be caught programmatically. 67 | 68 | .. code-block:: python 69 | 70 | morphio.set_raise_warnings(True) 71 | 72 | For safety reasons you might want to raise warnings only for construction of morphology, and disable it back 73 | afterwards: 74 | 75 | .. code-block:: python 76 | 77 | try: 78 | morphio.set_raise_warnings(True) 79 | m = morphio.Morphology('path/to/morph') 80 | finally: 81 | morphio.set_raise_warnings(False) 82 | 83 | If you care only about some types of warnings then you need to ignore others: 84 | 85 | .. code-block:: python 86 | 87 | try: 88 | morphio.set_raise_warnings(True) 89 | # warnings you are not interested in 90 | morphio.set_ignored_warning([morphio.Warning.wrong_root_point, ...], True) 91 | m = morphio.Morphology('path/to/morph') 92 | finally: 93 | morphio.set_ignored_warning([morphio.Warning.wrong_root_point, ...], False) 94 | morphio.set_raise_warnings(False) 95 | -------------------------------------------------------------------------------- /include/morphio/dendritic_spine.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include // SomaType 11 | #include // Morphology 12 | #include // EndoplasmicReticulum, Mitochondria 13 | 14 | namespace morphio { 15 | 16 | /** Class to represent morphologies of dendritic spines */ 17 | class DendriticSpine: public Morphology 18 | { 19 | public: 20 | explicit DendriticSpine(const std::string& source); 21 | 22 | const std::vector& postSynapticDensity() const 23 | noexcept; 24 | 25 | protected: 26 | friend class mut::DendriticSpine; 27 | explicit DendriticSpine(const Property::Properties& properties); 28 | 29 | private: 30 | Soma soma() const; 31 | Mitochondria mitochondria() const; 32 | const EndoplasmicReticulum endoplasmicReticulum() const; 33 | const std::vector& annotations() const; 34 | const std::vector& markers() const; 35 | const SomaType& somaType() const; 36 | }; 37 | 38 | } // namespace morphio 39 | -------------------------------------------------------------------------------- /include/morphio/endoplasmic_reticulum.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include // floatType 8 | 9 | #include // uint32_t 10 | #include // std::shared_ptr 11 | #include // std::move 12 | #include // std::vector 13 | 14 | #include // Property 15 | 16 | namespace morphio { 17 | /** 18 | * The entry-point class to access endoplasmic reticulum data 19 | * 20 | * Spec https://bbpteam.epfl.ch/documentation/projects/Morphology%20Documentation/latest/h5v1.html 21 | **/ 22 | class EndoplasmicReticulum 23 | { 24 | public: 25 | /** 26 | Returns the list of neuronal section indices 27 | **/ 28 | const std::vector& sectionIndices() const; 29 | 30 | /** 31 | Returns the volumes for each neuronal section 32 | **/ 33 | const std::vector& volumes() const; 34 | 35 | /** 36 | Returns the surface areas for each neuronal section 37 | **/ 38 | const std::vector& surfaceAreas() const; 39 | 40 | /** 41 | Returns the number of filaments for each neuronal section 42 | **/ 43 | const std::vector& filamentCounts() const; 44 | 45 | private: 46 | explicit EndoplasmicReticulum(std::shared_ptr properties) 47 | : properties_(std::move(properties)) {} 48 | std::shared_ptr properties_; 49 | 50 | friend class Morphology; 51 | friend class morphio::mut::EndoplasmicReticulum; 52 | }; 53 | } // namespace morphio 54 | -------------------------------------------------------------------------------- /include/morphio/errorMessages.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include // std::shared_ptr 8 | #include // std::vector 9 | 10 | #include // Warning 11 | #include // ErrorAndWarningHandler 12 | 13 | namespace morphio { 14 | 15 | /** Set the maximum number of warnings to be printed; -1 for unlimited **/ 16 | void set_maximum_warnings(int n_warnings); 17 | /** Set whether to interpet warning as errors **/ 18 | void set_raise_warnings(bool is_raise); 19 | /** Set a warning to ignore **/ 20 | void set_ignored_warning(enums::Warning warning, bool ignore = true); 21 | /** Set an array of warnings to ignore **/ 22 | void set_ignored_warning(const std::vector& warning, bool ignore = true); 23 | 24 | std::shared_ptr getWarningHandler(); 25 | 26 | } // namespace morphio 27 | -------------------------------------------------------------------------------- /include/morphio/exceptions.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | #include // std::runtime_error 7 | 8 | namespace morphio { 9 | 10 | /** Base class of all morphio errors */ 11 | class MorphioError: public std::runtime_error 12 | { 13 | public: 14 | explicit MorphioError(const std::string& _msg) 15 | : std::runtime_error(_msg) {} 16 | }; 17 | 18 | class NotImplementedError: public MorphioError 19 | { 20 | public: 21 | explicit NotImplementedError(const std::string& _msg) 22 | : MorphioError(_msg) {} 23 | }; 24 | 25 | class RawDataError: public MorphioError 26 | { 27 | public: 28 | explicit RawDataError(const std::string& _msg) 29 | : MorphioError(_msg) {} 30 | }; 31 | 32 | class UnknownFileType: public MorphioError 33 | { 34 | public: 35 | explicit UnknownFileType(const std::string& _msg) 36 | : MorphioError(_msg) {} 37 | }; 38 | 39 | class SomaError: public MorphioError 40 | { 41 | public: 42 | explicit SomaError(const std::string& _msg) 43 | : MorphioError(_msg) {} 44 | }; 45 | 46 | class IDSequenceError: public RawDataError 47 | { 48 | public: 49 | explicit IDSequenceError(const std::string& _msg) 50 | : RawDataError(_msg) {} 51 | }; 52 | 53 | class MultipleTrees: public RawDataError 54 | { 55 | public: 56 | explicit MultipleTrees(const std::string& _msg) 57 | : RawDataError(_msg) {} 58 | }; 59 | 60 | class MissingParentError: public RawDataError 61 | { 62 | public: 63 | explicit MissingParentError(const std::string& _msg) 64 | : RawDataError(_msg) {} 65 | }; 66 | 67 | class SectionBuilderError: public RawDataError 68 | { 69 | public: 70 | explicit SectionBuilderError(const std::string& _msg) 71 | : RawDataError(_msg) {} 72 | }; 73 | 74 | class WriterError: public MorphioError 75 | { 76 | public: 77 | explicit WriterError(const std::string& _msg) 78 | : MorphioError(_msg) {} 79 | }; 80 | } // namespace morphio 81 | -------------------------------------------------------------------------------- /include/morphio/glial_cell.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace morphio { 13 | 14 | /** Class to represent morphologies of glial cells */ 15 | class GlialCell: public Morphology 16 | { 17 | public: 18 | explicit GlialCell(const std::string& source); 19 | 20 | private: 21 | Soma soma() const; 22 | }; 23 | } // namespace morphio 24 | -------------------------------------------------------------------------------- /include/morphio/mito_section.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include // uint32_t 8 | #include // std::shared_ptr 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace morphio { 16 | using mito_upstream_iterator = upstream_iterator_t; 17 | using mito_breadth_iterator = morphio::breadth_iterator_t; 18 | using mito_depth_iterator = morphio::depth_iterator_t; 19 | 20 | /** Mitochondria section */ 21 | class MitoSection: public SectionBase 22 | { 23 | using SectionId = Property::MitoSection; 24 | using PointAttribute = Property::MitoDiameter; 25 | 26 | public: 27 | /** 28 | Depth first search iterator 29 | **/ 30 | mito_depth_iterator depth_begin() const; 31 | mito_depth_iterator depth_end() const; 32 | 33 | /** 34 | Breadth first search iterator 35 | **/ 36 | mito_breadth_iterator breadth_begin() const; 37 | mito_breadth_iterator breadth_end() const; 38 | 39 | /** 40 | Upstream first search iterator 41 | **/ 42 | mito_upstream_iterator upstream_begin() const; 43 | mito_upstream_iterator upstream_end() const; 44 | 45 | /** 46 | * Returns list of neuronal section IDs associated to each point 47 | **/ 48 | range neuriteSectionIds() const; 49 | 50 | /** 51 | * Returns list of section's point diameters 52 | **/ 53 | range diameters() const; 54 | 55 | /** 56 | * Returns list of relative distances between the start 57 | * of the neuronal section and each point of the mitochondrial section\n 58 | * Note: - a relative distance of 0 means the mitochondrial point is at the 59 | * beginning of the neuronal section 60 | * - a relative distance of 1 means the mitochondrial point is at the 61 | * end of the neuronal section 62 | **/ 63 | range relativePathLengths() const; 64 | 65 | /** 66 | * Return true if the both sections have the same neuriteSectionIds, diameters and relativePathLengths 67 | */ 68 | bool hasSameShape(const MitoSection& other) const noexcept; 69 | 70 | protected: 71 | MitoSection(uint32_t id, const std::shared_ptr& morphology) 72 | : SectionBase(id, morphology) {} 73 | friend MitoSection Mitochondria::section(uint32_t) const; 74 | friend class SectionBase; 75 | friend class mut::MitoSection; 76 | }; 77 | } // namespace morphio 78 | -------------------------------------------------------------------------------- /include/morphio/mitochondria.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include // Morphology 11 | #include // Property 12 | 13 | namespace morphio { 14 | /** 15 | * The entry-point class to access mitochondrial data 16 | * 17 | * By design, it is the equivalent of the Morphology class but at the 18 | * mitochondrial level. As the Morphology class, it implements a section accessor 19 | * and a root section accessor returning views on the Properties object for the 20 | * queried mitochondrial section. 21 | **/ 22 | class Mitochondria 23 | { 24 | public: 25 | /// Return the Section with the given id. 26 | MitoSection section(uint32_t id) const; 27 | 28 | /// Return a vector of all root sections 29 | std::vector rootSections() const; 30 | 31 | /** Return a vector containing all section objects 32 | * 33 | * Notes: 34 | * Soma is not included 35 | **/ 36 | std::vector sections() const; 37 | 38 | private: 39 | explicit Mitochondria(const std::shared_ptr& properties) 40 | : properties_(properties) {} 41 | std::shared_ptr properties_; 42 | 43 | friend class Morphology; 44 | }; 45 | } // namespace morphio 46 | -------------------------------------------------------------------------------- /include/morphio/mut/dendritic_spine.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include // mut::Morphology 11 | #include // Property 12 | 13 | namespace morphio { 14 | namespace mut { 15 | 16 | /** Mutable(editable) morphio::DendriticSpine */ 17 | class DendriticSpine: public Morphology 18 | { 19 | public: 20 | DendriticSpine(); 21 | explicit DendriticSpine(const std::string& source); 22 | 23 | 24 | /// Returns the post synaptic density values 25 | std::vector& postSynapticDensity() noexcept; 26 | 27 | /// Returns the post synaptic density values 28 | const std::vector& postSynapticDensity() const 29 | noexcept; 30 | }; 31 | 32 | } // namespace mut 33 | } // namespace morphio 34 | -------------------------------------------------------------------------------- /include/morphio/mut/endoplasmic_reticulum.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace morphio { 11 | namespace mut { 12 | /** Mutable(editable) morphio::EndoplasmicReticulum */ 13 | class EndoplasmicReticulum 14 | { 15 | public: 16 | EndoplasmicReticulum() = default; 17 | EndoplasmicReticulum(const EndoplasmicReticulum& endoplasmicReticulum) = default; 18 | 19 | EndoplasmicReticulum(const std::vector& section_indices, 20 | const std::vector& volumes, 21 | const std::vector& surface_areas, 22 | const std::vector& filament_counts); 23 | 24 | explicit EndoplasmicReticulum(const morphio::EndoplasmicReticulum& endoplasmic_reticulum); 25 | 26 | 27 | /** 28 | Returns the list of neuronal section indices 29 | **/ 30 | const std::vector& sectionIndices() const noexcept; 31 | std::vector& sectionIndices() noexcept; 32 | 33 | /** 34 | Returns the volumes for each neuronal section 35 | **/ 36 | const std::vector& volumes() const noexcept; 37 | std::vector& volumes() noexcept; 38 | 39 | /** 40 | Returns the surface areas for each neuronal section 41 | **/ 42 | const std::vector& surfaceAreas() const noexcept; 43 | std::vector& surfaceAreas() noexcept; 44 | 45 | /** 46 | Returns the number of filaments for each neuronal section 47 | **/ 48 | const std::vector& filamentCounts() const noexcept; 49 | std::vector& filamentCounts() noexcept; 50 | 51 | /** 52 | Returns the data structure that stores ER data 53 | This data structure is used to create the immutable object 54 | **/ 55 | Property::EndoplasmicReticulumLevel buildReadOnly() const noexcept; 56 | 57 | private: 58 | morphio::Property::EndoplasmicReticulumLevel properties_; 59 | explicit EndoplasmicReticulum(const morphio::Property::EndoplasmicReticulumLevel&); 60 | }; 61 | } // namespace mut 62 | } // namespace morphio 63 | -------------------------------------------------------------------------------- /include/morphio/mut/glial_cell.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include // std::string 8 | 9 | #include // mut::Morphology 10 | 11 | namespace morphio { 12 | namespace mut { 13 | 14 | /** Mutable(editable) morphio::GlialCell */ 15 | class GlialCell: public Morphology 16 | { 17 | public: 18 | GlialCell(); 19 | explicit GlialCell(const std::string& source); 20 | }; 21 | 22 | } // namespace mut 23 | } // namespace morphio 24 | -------------------------------------------------------------------------------- /include/morphio/mut/modifiers.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | namespace morphio { 8 | namespace mut { 9 | 10 | class Morphology; 11 | 12 | namespace modifiers { 13 | /** 14 | Only the first and last points of each sections are kept 15 | **/ 16 | void two_points_sections(morphio::mut::Morphology& morpho); 17 | 18 | /** 19 | Remove duplicated points 20 | **/ 21 | void no_duplicate_point(morphio::mut::Morphology& morpho); 22 | 23 | /** 24 | Reduce the soma to a sphere placed at the center of gravity of soma points 25 | and whose radius is the averaged distance between the soma points and the 26 | center of gravity 27 | **/ 28 | void soma_sphere(morphio::mut::Morphology& morpho); 29 | 30 | /** Reorders neurites of morphology according to NEURON simulator */ 31 | void nrn_order(morphio::mut::Morphology& morpho); 32 | 33 | } // namespace modifiers 34 | 35 | } // namespace mut 36 | 37 | } // namespace morphio 38 | -------------------------------------------------------------------------------- /include/morphio/mut/soma.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include // Property 8 | #include // morphio::soma 9 | 10 | namespace morphio { 11 | namespace mut { 12 | /** Mutable(editable) morphio::Soma */ 13 | class Soma 14 | { 15 | public: 16 | Soma() = default; 17 | Soma(const Soma& soma) = default; 18 | 19 | explicit Soma(const Property::PointLevel& pointProperties); 20 | explicit Soma(const morphio::Soma& soma); 21 | 22 | /// Return the coordinates (x,y,z) of all soma points 23 | std::vector& points() noexcept { 24 | return point_properties_._points; 25 | } 26 | const std::vector& points() const noexcept { 27 | return point_properties_._points; 28 | } 29 | 30 | /// Return the diameters of all soma points 31 | std::vector& diameters() noexcept { 32 | return point_properties_._diameters; 33 | } 34 | const std::vector& diameters() const noexcept { 35 | return point_properties_._diameters; 36 | } 37 | 38 | /// Return the soma type 39 | const SomaType& type() const noexcept { 40 | return soma_type_; 41 | } 42 | 43 | /// Return the soma type 44 | SomaType& type() noexcept { 45 | return soma_type_; 46 | } 47 | 48 | /** 49 | * Return the center of gravity of the soma points 50 | **/ 51 | Point center() const; 52 | 53 | /** 54 | Return the soma surface 55 | Note: the soma surface computation depends on the soma type 56 | **/ 57 | floatType surface() const; 58 | 59 | /** 60 | * Return the maximum distance between the center of gravity and any of 61 | * the soma points 62 | */ 63 | floatType maxDistance() const; 64 | 65 | Property::PointLevel& properties() noexcept { 66 | return point_properties_; 67 | } 68 | const Property::PointLevel& properties() const noexcept { 69 | return point_properties_; 70 | } 71 | 72 | private: 73 | friend class Morphology; 74 | 75 | SomaType soma_type_ = SOMA_UNDEFINED; 76 | Property::PointLevel point_properties_; 77 | }; 78 | 79 | } // namespace mut 80 | } // namespace morphio 81 | -------------------------------------------------------------------------------- /include/morphio/mut/writers.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace morphio { 11 | namespace mut { 12 | namespace writer { 13 | 14 | /** Save morphology in SWC format */ 15 | void swc(const Morphology& morphology, 16 | const std::string& filename, 17 | std::shared_ptr handler); 18 | 19 | /** Save morphology in ASC format */ 20 | void asc(const Morphology& morphology, 21 | const std::string& filename, 22 | std::shared_ptr handler); 23 | 24 | /** Save morphology in H5 format */ 25 | void h5(const Morphology& morphology, 26 | const std::string& filename, 27 | std::shared_ptr handler); 28 | 29 | } // namespace writer 30 | } // end namespace mut 31 | } // end namespace morphio 32 | -------------------------------------------------------------------------------- /include/morphio/section.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // std::shared_ptr 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace morphio { 12 | 13 | using upstream_iterator = upstream_iterator_t
; 14 | using breadth_iterator = breadth_iterator_t; 15 | using depth_iterator = depth_iterator_t; 16 | 17 | /** 18 | * A class to represent a morphological section. 19 | * 20 | * A Section is an unbranched piece of a morphological skeleton. 21 | * This class provides functions to query information about the sample points 22 | * that compose the section and functions to obtain the parent and children 23 | * sections. 24 | * 25 | * The cell soma is also considered a section, but some functions have 26 | * special meaning for it. 27 | * 28 | * Sections cannot be directly created, but are returned by several 29 | * morphio::Morphology and morphio::Section methods. 30 | * 31 | * This is a lightweight object with STL container style thread safety. 32 | * It is also safe to use a section after the morphology from where it comes 33 | * has been deallocated. The morphological data will be kept as long as there 34 | * is a Section referring to it. 35 | */ 36 | class Section: public SectionBase
37 | { 38 | using SectionId = Property::Section; 39 | using PointAttribute = Property::Point; 40 | 41 | public: 42 | /// Depth first iterator 43 | depth_iterator depth_begin() const { 44 | return depth_iterator(*this); 45 | } 46 | depth_iterator depth_end() const { 47 | return depth_iterator(); 48 | } 49 | 50 | /// Breadth first iterator 51 | breadth_iterator breadth_begin() const { 52 | return breadth_iterator(*this); 53 | } 54 | breadth_iterator breadth_end() const { 55 | return breadth_iterator(); 56 | } 57 | 58 | /// Upstream iterator 59 | upstream_iterator upstream_begin() const { 60 | return upstream_iterator(*this); 61 | } 62 | upstream_iterator upstream_end() const { 63 | return upstream_iterator(); 64 | } 65 | 66 | /** 67 | * Return a view 68 | (https://github.com/isocpp/CppCoreGuidelines/blob/master/docs/gsl-intro.md#gslspan-what-is-gslspan-and-what-is-it-for) 69 | to this section's point coordinates 70 | **/ 71 | range points() const { 72 | return get(); 73 | } 74 | 75 | /** 76 | * Return a view 77 | (https://github.com/isocpp/CppCoreGuidelines/blob/master/docs/gsl-intro.md#gslspan-what-is-gslspan-and-what-is-it-for) 78 | to this section's point diameters 79 | **/ 80 | range diameters() const { 81 | return get(); 82 | } 83 | 84 | /** 85 | * Return a view 86 | (https://github.com/isocpp/CppCoreGuidelines/blob/master/docs/gsl-intro.md#gslspan-what-is-gslspan-and-what-is-it-for) 87 | to this section's point perimeters 88 | **/ 89 | range perimeters() const { 90 | return get(); 91 | } 92 | 93 | /// Return the morphological type of this section (dendrite, axon, ...) 94 | SectionType type() const { 95 | return properties_->get()[id_]; 96 | } 97 | 98 | /** 99 | * Return true if the sections of the tree downstream (downstream = true) or upstream 100 | * (donwstream = false) have the same section type as the current section. 101 | */ 102 | bool isHeterogeneous(bool downstream = true) const; 103 | 104 | /// Return true if the both sections have the same points, diameters and perimeters 105 | bool hasSameShape(const Section& other) const noexcept; 106 | 107 | friend class mut::Section; 108 | friend Section Morphology::section(uint32_t) const; 109 | friend class SectionBase
; 110 | 111 | protected: 112 | Section(uint32_t id, const std::shared_ptr& properties) 113 | : SectionBase(id, properties) {} 114 | }; 115 | 116 | } // namespace morphio 117 | 118 | std::ostream& operator<<(std::ostream& os, const morphio::Section& section); 119 | -------------------------------------------------------------------------------- /include/morphio/soma.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace morphio { 7 | /** 8 | * A class to represent a neuron soma. 9 | * 10 | * This class provides functions to query information about the soma of a 11 | * neuron. 12 | * 13 | * Typically the soma is described as the poly-line of the projection 14 | * of the soma onto a plane, where the plane normal points in the vertical 15 | * direction in the local coordinate system of the morphology. In other cases 16 | * the poly-line is not projected onto a plane, but is an approximation of 17 | * the countour of the soma as seen in an orhogonal projection down the 18 | * vertical axis (this is basically the same as before, but the vertical 19 | * coordinate is not 0 for all the points). 20 | * This class can also be used for both descriptions as well as somas simply 21 | * approximated as spheres. 22 | * 23 | * The coordinates system used by a soma will be in the same as the 24 | * brain::Morphology from where it comes. 25 | * 26 | * @version unstable 27 | */ 28 | class Soma 29 | { 30 | public: 31 | /// Return the coordinates (x,y,z) of all soma points 32 | range points() const noexcept { 33 | return properties_->_somaLevel._points; 34 | } 35 | 36 | /// Return the diameters of all soma points 37 | range diameters() const noexcept { 38 | return properties_->_somaLevel._diameters; 39 | } 40 | 41 | /// Return the soma type 42 | SomaType type() const noexcept { 43 | return properties_->_cellLevel._somaType; 44 | } 45 | 46 | /// Return the center of gravity of the soma points 47 | Point center() const; 48 | 49 | /** 50 | * Return the soma volume\n" 51 | * Note: the soma volume computation depends on the soma type 52 | **/ 53 | floatType volume() const; 54 | 55 | /** 56 | * Return the soma surface\n" 57 | * Note: the soma surface computation depends on the soma type 58 | **/ 59 | floatType surface() const; 60 | 61 | /** 62 | * Return the maximum distance between the center of gravity and any of 63 | * the soma points 64 | */ 65 | floatType maxDistance() const; 66 | 67 | private: 68 | explicit Soma(const std::shared_ptr& properties); 69 | // TODO: find out why the following line does not work 70 | // when friend class Morphology; is removed 71 | // template 72 | // friend const morphio::Soma morphio::Morphology::soma() const; 73 | friend class Morphology; 74 | friend class mut::Soma; 75 | 76 | std::shared_ptr properties_; 77 | }; 78 | 79 | } // namespace morphio 80 | -------------------------------------------------------------------------------- /include/morphio/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // std::pair 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace morphio { 10 | 11 | using namespace enums; 12 | 13 | class DendriticSpine; 14 | class EndoplasmicReticulum; 15 | class MitoSection; 16 | class Mitochondria; 17 | class Morphology; 18 | class Section; 19 | 20 | template 21 | class SectionBase; 22 | 23 | class Soma; 24 | 25 | namespace Property { 26 | struct Properties; 27 | } // namespace Property 28 | 29 | /** Functionality for vasculature (blood) **/ 30 | namespace vasculature { 31 | class Section; 32 | class Vasculature; 33 | } // namespace vasculature 34 | 35 | /** Functionality for mutating(editing) of morphologies **/ 36 | namespace mut { 37 | class DendriticSpine; 38 | class EndoplasmicReticulum; 39 | class MitoSection; 40 | class Mitochondria; 41 | class Morphology; 42 | class Section; 43 | class Soma; 44 | } // namespace mut 45 | 46 | namespace readers { 47 | /** Level of error reporting **/ 48 | enum ErrorLevel { 49 | WARNING, //!< Warning 50 | ERROR //!< Error 51 | }; 52 | } // namespace readers 53 | 54 | 55 | using SectionRange = std::pair; 56 | 57 | } // namespace morphio 58 | -------------------------------------------------------------------------------- /include/morphio/vasc/iterators.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace morphio { 12 | namespace vasculature { 13 | 14 | template 15 | class graph_iterator_t 16 | { 17 | std::set visited; 18 | std::stack container; 19 | 20 | public: 21 | using iterator_category = std::input_iterator_tag; 22 | using value_type = SectionT; 23 | using difference_type = std::ptrdiff_t; 24 | using pointer = SectionT*; 25 | using reference = SectionT&; 26 | graph_iterator_t() = default; 27 | inline explicit graph_iterator_t(const SectionT& vasculatureSection); 28 | inline explicit graph_iterator_t(const VasculatureT& vasculatureMorphology); 29 | 30 | inline bool operator==(const graph_iterator_t& other) const; 31 | inline bool operator!=(const graph_iterator_t& other) const; 32 | inline const SectionT& operator*() const; 33 | 34 | inline graph_iterator_t& operator++(); 35 | inline graph_iterator_t operator++(int); 36 | }; 37 | 38 | template 39 | inline graph_iterator_t::graph_iterator_t( 40 | const SectionT& vasculatureSection) { 41 | container.push(vasculatureSection); 42 | } 43 | 44 | template 45 | inline graph_iterator_t::graph_iterator_t( 46 | const VasculatureT& vasculatureMorphology) { 47 | const auto& sections = vasculatureMorphology.sections(); 48 | for (std::size_t i = 0; i < sections.size(); ++i) { 49 | if (sections[i].predecessors().empty()) { 50 | container.push(sections[i]); 51 | visited.insert(sections[i]); 52 | } 53 | } 54 | } 55 | 56 | template 57 | inline bool graph_iterator_t::operator==( 58 | const graph_iterator_t& other) const { 59 | return container == other.container; 60 | } 61 | 62 | template 63 | inline bool graph_iterator_t::operator!=( 64 | const graph_iterator_t& other) const { 65 | return !(*this == other); 66 | } 67 | 68 | template 69 | inline const SectionT& graph_iterator_t::operator*() const { 70 | return container.top(); 71 | } 72 | 73 | template 74 | inline graph_iterator_t& 75 | graph_iterator_t::operator++() { 76 | const auto& section = *(*this); 77 | container.pop(); 78 | const auto& neighbors = section.neighbors(); 79 | for (auto it = neighbors.rbegin(); it != neighbors.rend(); ++it) { 80 | if (visited.find(*it) == visited.end()) { 81 | container.push(*it); 82 | visited.insert(*it); 83 | } 84 | } 85 | return *this; 86 | } 87 | 88 | template 89 | inline graph_iterator_t 90 | graph_iterator_t::operator++(int) { 91 | graph_iterator_t retval = *this; 92 | ++(*this); 93 | return retval; 94 | } 95 | 96 | } // namespace vasculature 97 | } // namespace morphio 98 | -------------------------------------------------------------------------------- /include/morphio/vasc/section.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include // std::ostream 8 | #include // std::shared_ptr 9 | #include // std::vector 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace morphio { 16 | namespace vasculature { 17 | /** Vasculature section */ 18 | class Section 19 | { 20 | using SectionId = property::VascSection; 21 | using PointAttribute = property::Point; 22 | 23 | public: 24 | Section(const Section& section) = default; 25 | 26 | Section& operator=(const Section& section); 27 | 28 | Section(uint32_t id, const std::shared_ptr& morphology); 29 | 30 | bool operator==(const Section& section) const; 31 | bool operator!=(const Section& section) const; 32 | bool operator<(const Section& other) const; 33 | 34 | /** 35 | Returns a list of predecessors or parents of the section 36 | **/ 37 | std::vector
predecessors() const; 38 | 39 | /** 40 | Returns a list of successors or children of the section 41 | **/ 42 | std::vector
successors() const; 43 | 44 | /** 45 | Returns a list of all neighbors of the section 46 | **/ 47 | std::vector
neighbors() const; 48 | 49 | /** Return the ID of this section. */ 50 | uint32_t id() const noexcept; 51 | 52 | /** 53 | Euclidian distance between first and last point of the section 54 | **/ 55 | floatType length() const; 56 | 57 | graph_iterator begin() const; 58 | graph_iterator end() const; 59 | 60 | /** 61 | * Return a view 62 | (https://github.com/isocpp/CppCoreGuidelines/blob/master/docs/gsl-intro.md#gslspan-what-is-gslspan-and-what-is-it-for) 63 | to this section's point coordinates 64 | **/ 65 | range points() const; 66 | 67 | /** 68 | * Return a view 69 | (https://github.com/isocpp/CppCoreGuidelines/blob/master/docs/gsl-intro.md#gslspan-what-is-gslspan-and-what-is-it-for) 70 | to this section's point diameters 71 | **/ 72 | range diameters() const; 73 | 74 | /** 75 | * Return the morphological type of this section (artery, vein, capillary, ...) 76 | */ 77 | VascularSectionType type() const; 78 | 79 | protected: 80 | template 81 | range get() const; 82 | 83 | uint32_t id_; 84 | SectionRange range_; 85 | std::shared_ptr properties_; 86 | }; 87 | 88 | } // namespace vasculature 89 | } // namespace morphio 90 | 91 | std::ostream& operator<<(std::ostream& os, const morphio::vasculature::Section& section); 92 | -------------------------------------------------------------------------------- /include/morphio/vasc/vasculature.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #pragma once 6 | 7 | #include // std::shared_ptr 8 | #include // std::string 9 | #include // std::vector 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace morphio { 16 | namespace vasculature { 17 | 18 | using graph_iterator = graph_iterator_t; 19 | 20 | /** 21 | * The entry-point class to access vasculature(blood) data 22 | * 23 | * By design, it is the equivalent of the Morphology class but at the 24 | * vasculature level. As the Morphology class, it implements a section accessor 25 | * and a root section accessor returning views on the Properties object for the 26 | * queried vasculature section. 27 | **/ 28 | class Vasculature 29 | { 30 | public: 31 | /** @name Read API */ 32 | /** Open the given source to a vasculature file and parse it. 33 | */ 34 | explicit Vasculature(const std::string& source); 35 | 36 | Vasculature(Vasculature&&) = default; 37 | virtual ~Vasculature() = default; 38 | 39 | Vasculature& operator=(const Vasculature&) = default; 40 | Vasculature& operator=(Vasculature&&) = default; 41 | 42 | /** 43 | * Return a vector containing all section objects. 44 | **/ 45 | std::vector
sections() const; 46 | 47 | /** 48 | * Return the Section with the given id. 49 | * 50 | * @throw RawDataError if the id is out of range 51 | */ 52 | Section section(uint32_t id) const; 53 | 54 | /** 55 | * Returns a list with offsets to access data of a specific section in the points 56 | * and diameters arrays. 57 | p 58 | * Example: accessing diameters of n'th section will be located in the Vasculature::diameters 59 | * array from diameters[sectionOffsets(n)] to diameters[sectionOffsets(n+1)-1] 60 | * 61 | * Note: for convenience, the last point of this array is the points() array size 62 | * so that the above example works also for the last section. 63 | */ 64 | const std::vector sectionOffsets() const noexcept; 65 | 66 | /** 67 | * Return a vector with all points from all sections 68 | **/ 69 | inline const Points& points() const noexcept; 70 | 71 | /** 72 | * Return a vector with all diameters from all sections 73 | **/ 74 | inline const std::vector& diameters() const noexcept; 75 | 76 | /** 77 | * Return a vector with the section type of every section 78 | **/ 79 | inline const std::vector& sectionTypes() const noexcept; 80 | 81 | /** 82 | * Return a vector with all the connections between sections 83 | **/ 84 | const std::vector& sectionConnectivity() const 85 | noexcept; 86 | 87 | 88 | /** graph iterator pointing to the begin */ 89 | graph_iterator begin() const; 90 | /** graph iterator pointing to the end */ 91 | graph_iterator end() const; 92 | 93 | private: 94 | std::shared_ptr properties_; 95 | 96 | template 97 | inline const std::vector& get() const noexcept; 98 | }; 99 | 100 | template 101 | inline const std::vector& Vasculature::get() const noexcept { 102 | return properties_->get(); 103 | } 104 | 105 | inline const Points& Vasculature::points() const noexcept { 106 | return get(); 107 | } 108 | 109 | inline const std::vector& Vasculature::diameters() const noexcept { 110 | return get(); 111 | } 112 | 113 | inline const std::vector& Vasculature::sectionTypes() const noexcept { 114 | return get(); 115 | } 116 | 117 | } // namespace vasculature 118 | } // namespace morphio 119 | -------------------------------------------------------------------------------- /include/morphio/vector_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // M_PI 5 | #include 6 | 7 | #include 8 | 9 | namespace morphio { 10 | 11 | template 12 | using range = gsl::span; 13 | 14 | #ifdef MORPHIO_USE_DOUBLE 15 | using floatType = double; 16 | constexpr floatType epsilon = 1e-6; 17 | constexpr floatType PI = M_PI; 18 | constexpr int FLOAT_PRECISION_PRINT = 17; 19 | 20 | #else 21 | /** Type of float to use. Can be double or float depending on MORPHIO_USE_DOUBLE */ 22 | using floatType = float; 23 | /** A really small value that is used to measure how close are two values */ 24 | constexpr floatType epsilon = 1e-6F; 25 | constexpr floatType PI = static_cast(M_PI); 26 | constexpr int FLOAT_PRECISION_PRINT = 9; 27 | #endif 28 | 29 | /** An array of size 3 for x,y,z coordinates */ 30 | using Point = std::array; 31 | /** An array of points */ 32 | using Points = std::vector; 33 | 34 | } // namespace morphio 35 | -------------------------------------------------------------------------------- /include/morphio/version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // std::uint32_t 4 | #include 5 | #include // std::tuple 6 | 7 | namespace morphio { 8 | 9 | // A tuple (file format (std::string), major version, minor version) 10 | using MorphologyVersion = std::tuple; 11 | 12 | std::string getVersionString(); 13 | 14 | 15 | } // namespace morphio 16 | -------------------------------------------------------------------------------- /morphio/__init__.py: -------------------------------------------------------------------------------- 1 | import platform 2 | 3 | 4 | if platform.system() == "Windows": 5 | # the plan is to leverage the h5py inclusion of hdf5 dll; this way 6 | # there cannot be a mismatch between version, when using windows, 7 | # and MorphIO doesn't need to build hdf5 8 | import h5py as _h5py 9 | if (1, 14) != _h5py.version.hdf5_version_tuple[:2]: 10 | raise RuntimeError(f'HDF5 library version mismatch. 1.14.x != {_h5py.version.hdf5_version}') 11 | del _h5py 12 | 13 | 14 | from ._morphio import ( 15 | Annotation, 16 | AnnotationType, 17 | CellFamily, 18 | CellLevel, 19 | Collection, 20 | DendriticSpine, 21 | EndoplasmicReticulum, 22 | GlialCell, 23 | IDSequenceError, 24 | IterType, 25 | LogLevel, 26 | MissingParentError, 27 | MitoSection, 28 | Mitochondria, 29 | MitochondriaPointLevel, 30 | MorphioError, 31 | Morphology, 32 | MultipleTrees, 33 | Option, 34 | PointLevel, 35 | Points, 36 | PostSynapticDensity, 37 | Properties, 38 | RawDataError, 39 | Section, 40 | SectionBuilderError, 41 | SectionLevel, 42 | SectionType, 43 | Soma, 44 | SomaError, 45 | SomaType, 46 | UnknownFileType, 47 | VasculatureSectionType, 48 | Warning, 49 | WarningHandlerCollector, 50 | WriterError, 51 | mut, 52 | ostream_redirect, 53 | set_ignored_warning, 54 | set_raise_warnings, 55 | set_maximum_warnings, 56 | vasculature, 57 | version, 58 | ) 59 | -------------------------------------------------------------------------------- /morphio/mut/__init__.py: -------------------------------------------------------------------------------- 1 | from .._morphio.mut import (Morphology, 2 | Section, 3 | Soma, 4 | MitoSection, 5 | Mitochondria, 6 | GlialCell, 7 | EndoplasmicReticulum, 8 | DendriticSpine, 9 | ) 10 | -------------------------------------------------------------------------------- /morphio/vasculature/__init__.py: -------------------------------------------------------------------------------- 1 | from .._morphio.vasculature import Vasculature, Section 2 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=24.2.0", "wheel", "cmake", "ninja"] 3 | 4 | [tool.pytest.ini_options] 5 | testpaths = ["tests"] 6 | -------------------------------------------------------------------------------- /scripts/check-clang-format-all: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | find src include -iname \*.h -o -iname \*.c -o -iname \*.cpp -o -iname \*.hpp -o -iname \*.tpp\ 4 | | xargs clang-format -style=file -i -fallback-style=none 5 | 6 | git diff > clang_format.patch 7 | 8 | # Delete if 0 size 9 | if [ ! -s clang_format.patch ] 10 | then 11 | rm clang_format.patch 12 | exit 0 13 | fi 14 | 15 | echo "The code is not formatted according to clang-format" 16 | echo "Here is the diff:" 17 | echo cat clang_format.patch 18 | echo "" 19 | cat clang_format.patch 20 | echo "" 21 | echo "Please run the following command in the root directory:" 22 | echo "find src include -iname \*.h -o -iname \*.c -o -iname \*.cpp -o -iname \*.hpp -o -iname \*.tpp | xargs clang-format -style=file -i -fallback-style=none" 23 | 24 | exit 1 25 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | '''morphio setup.py''' 2 | import os 3 | import platform 4 | import subprocess 5 | import sys 6 | 7 | from setuptools import Extension, setup 8 | from setuptools.command.build_ext import build_ext 9 | 10 | 11 | class CMakeExtension(Extension): 12 | def __init__(self, name, sourcedir=''): 13 | Extension.__init__(self, name, sources=[]) 14 | self.sourcedir = os.path.abspath(sourcedir) 15 | 16 | 17 | class CMakeBuild(build_ext): 18 | user_options = build_ext.user_options + [ 19 | ("cmake-defs=", None, "Additional CMake definitions, comma split") 20 | ] 21 | 22 | def initialize_options(self): 23 | build_ext.initialize_options(self) 24 | self.cmake_defs = None 25 | 26 | def run(self): 27 | for ext in self.extensions: 28 | self.build_extension(ext) 29 | 30 | def build_extension(self, ext): 31 | extdir = os.path.abspath( 32 | os.path.dirname(self.get_ext_fullpath(ext.name))) 33 | cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, 34 | '-DMORPHIO_VERSION_STRING=' + self.distribution.get_version(), 35 | '-DMORPHIO_TESTS=OFF', 36 | '-DPYTHON_EXECUTABLE=' + sys.executable, 37 | '-DHIGHFIVE_EXAMPLES=OFF', 38 | '-DHIGHFIVE_UNIT_TESTS=OFF', 39 | ] 40 | 41 | if self.cmake_defs: 42 | cmake_args += ["-D" + opt for opt in self.cmake_defs.split(",")] 43 | 44 | cfg = 'Debug' if self.debug else 'Release' 45 | 46 | build_args = ['--config', cfg] 47 | 48 | if "STATIC_HDF5" in os.environ: 49 | cmake_args += ["-DHDF5_USE_STATIC_LIBRARIES=True", ] 50 | 51 | cmake_args += ['-DCMAKE_BUILD_TYPE={}'.format(cfg), 52 | '-DMorphIO_CXX_WARNINGS=OFF', 53 | '-GNinja', 54 | ] 55 | 56 | if not os.path.exists(self.build_temp): 57 | os.makedirs(self.build_temp) 58 | 59 | subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp) 60 | subprocess.check_call(['cmake', '--build', '.', '--target', '_morphio'] + build_args, cwd=self.build_temp) 61 | 62 | install_requires = ['numpy>=1.14.1', 63 | ] 64 | 65 | with open('README.rst', 'r', encoding='utf-8') as f: 66 | long_description = f.read() 67 | 68 | if platform.system() == 'Windows': 69 | install_requires += ['h5py>=3,<4', # use h5py's hdf5 install so we don't have to redistribute hdf5 70 | ] 71 | 72 | setup( 73 | name='morphio', 74 | author='Blue Brain Project, EPFL', 75 | description='A neuron morphology IO library', 76 | long_description=long_description, 77 | long_description_content_type="text/x-rst", 78 | install_requires=install_requires, 79 | extras_require={ 80 | 'docs': ['sphinx-bluebrain-theme'], 81 | }, 82 | url='https://github.com/BlueBrain/MorphIO/', 83 | ext_modules=[CMakeExtension('morphio._morphio'), 84 | ], 85 | cmdclass={'build_ext': CMakeBuild, 86 | }, 87 | packages=['morphio', 'morphio.mut', 'morphio.vasculature'], 88 | license="Apache License 2.0", 89 | keywords=['computational neuroscience', 90 | 'morphology', 91 | 'neuron', 92 | 'neurolucida', 93 | 'neuromorphology', 94 | ], 95 | zip_safe=False, 96 | classifiers=[ 97 | "Intended Audience :: Education", 98 | "Intended Audience :: Science/Research", 99 | "Programming Language :: Python", 100 | "Topic :: Scientific/Engineering :: Bio-Informatics", 101 | ], 102 | use_scm_version=True, 103 | setup_requires=[ 104 | 'setuptools_scm', 105 | ], 106 | python_requires=">=3.9", 107 | ) 108 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(MORPHIO_SOURCES 2 | collection.cpp 3 | dendritic_spine.cpp 4 | endoplasmic_reticulum.cpp 5 | enums.cpp 6 | errorMessages.cpp 7 | error_message_generation.cpp 8 | glial_cell.cpp 9 | mito_section.cpp 10 | mitochondria.cpp 11 | morphology.cpp 12 | morphology.cpp 13 | mut/dendritic_spine.cpp 14 | mut/endoplasmic_reticulum.cpp 15 | mut/glial_cell.cpp 16 | mut/mito_section.cpp 17 | mut/mitochondria.cpp 18 | mut/modifiers.cpp 19 | mut/morphology.cpp 20 | mut/section.cpp 21 | mut/soma.cpp 22 | mut/writer_asc.cpp 23 | mut/writer_hdf5.cpp 24 | mut/writer_swc.cpp 25 | mut/writer_utils.cpp 26 | point_utils.cpp 27 | properties.cpp 28 | readers/morphologyASC.cpp 29 | readers/morphologyHDF5.cpp 30 | readers/morphologySWC.cpp 31 | readers/utils.cpp 32 | readers/vasculatureHDF5.cpp 33 | section.cpp 34 | shared_utils.cpp 35 | soma.cpp 36 | vasc/properties.cpp 37 | vasc/section.cpp 38 | vasc/vasculature.cpp 39 | version.cpp 40 | warning_handling.cpp 41 | ) 42 | 43 | if(NOT MORPHIO_VERSION_STRING) 44 | execute_process(COMMAND git describe --tags 45 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 46 | RESULT_VARIABLE GIT_VERSION_FAILED 47 | OUTPUT_VARIABLE MORPHIO_VERSION_STRING 48 | ERROR_VARIABLE GIT_VERSION_ERROR 49 | OUTPUT_STRIP_TRAILING_WHITESPACE) 50 | endif() 51 | 52 | configure_file ( 53 | ${CMAKE_CURRENT_SOURCE_DIR}/version.cpp.in 54 | ${CMAKE_CURRENT_SOURCE_DIR}/version.cpp 55 | ) 56 | 57 | # by default, -fPIC is only used of the dynamic library build 58 | # This forces the flag also for the static lib 59 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 60 | 61 | # Building object files only once. They will be used for the shared and static library 62 | add_library(morphio_obj OBJECT ${MORPHIO_SOURCES}) 63 | 64 | target_include_directories(morphio_obj 65 | PUBLIC 66 | ${CMAKE_SOURCE_DIR} 67 | ${CMAKE_CURRENT_SOURCE_DIR}/../include 68 | ) 69 | 70 | target_include_directories(morphio_obj 71 | SYSTEM 72 | PUBLIC 73 | $ 74 | $ 75 | $ 76 | PRIVATE 77 | $ 78 | ) 79 | 80 | set_target_properties(morphio_obj 81 | PROPERTIES 82 | CXX_STANDARD 14 83 | CXX_STANDARD_REQUIRED YES 84 | CXX_EXTENSIONS NO 85 | ) 86 | 87 | if (MORPHIO_ENABLE_COVERAGE) 88 | include(CodeCoverage) 89 | append_coverage_compiler_flags_to_target(morphio_obj) 90 | endif() 91 | 92 | 93 | if (NOT WIN32) 94 | target_compile_options(morphio_obj 95 | PRIVATE 96 | -Wall 97 | -Wextra 98 | -Wnon-virtual-dtor 99 | -pedantic 100 | ) 101 | endif() 102 | 103 | add_library(morphio_static STATIC $) 104 | add_library(morphio_shared SHARED $) 105 | 106 | set_target_properties(morphio_shared PROPERTIES OUTPUT_NAME "morphio" 107 | EXPORT_NAME "morphio" 108 | SOVERSION "0.0.0") 109 | foreach(TARGET morphio_shared morphio_static) 110 | target_include_directories(${TARGET} 111 | SYSTEM 112 | PUBLIC 113 | $ 114 | $ 115 | $ 116 | $ 117 | PRIVATE 118 | $ 119 | ) 120 | target_link_libraries(${TARGET} PUBLIC gsl-lite PRIVATE HighFive lexertl) 121 | endforeach(TARGET) 122 | 123 | install( 124 | # DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 125 | TARGETS morphio_shared 126 | EXPORT MorphIOTargets 127 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 128 | PUBLIC_HEADER DESTINATION include 129 | ) 130 | -------------------------------------------------------------------------------- /src/dendritic_spine.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include // RawDataError 6 | #include // Property 7 | 8 | #include 9 | 10 | namespace morphio { 11 | 12 | DendriticSpine::DendriticSpine(const std::string& source) 13 | : Morphology(source) { 14 | if (properties_->_cellLevel._cellFamily != CellFamily::SPINE) { 15 | throw(RawDataError("File: " + source + 16 | " is not a DendriticSpine file. It should be a H5 file of type SPINE.")); 17 | } 18 | } 19 | 20 | const std::vector& 21 | DendriticSpine::postSynapticDensity() const noexcept { 22 | return properties_->_dendriticSpineLevel._post_synaptic_density; 23 | } 24 | 25 | } // namespace morphio 26 | -------------------------------------------------------------------------------- /src/endoplasmic_reticulum.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | namespace morphio { 8 | const std::vector& EndoplasmicReticulum::sectionIndices() const { 9 | return properties_->_endoplasmicReticulumLevel._sectionIndices; 10 | } 11 | 12 | const std::vector& EndoplasmicReticulum::volumes() const { 13 | return properties_->_endoplasmicReticulumLevel._volumes; 14 | } 15 | 16 | const std::vector& EndoplasmicReticulum::surfaceAreas() const { 17 | return properties_->_endoplasmicReticulumLevel._surfaceAreas; 18 | } 19 | 20 | const std::vector& EndoplasmicReticulum::filamentCounts() const { 21 | return properties_->_endoplasmicReticulumLevel._filamentCounts; 22 | } 23 | 24 | } // namespace morphio 25 | -------------------------------------------------------------------------------- /src/enums.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | #include 7 | 8 | namespace morphio { 9 | namespace enums { 10 | 11 | /** Output stream formatter for SomaType */ 12 | std::ostream& operator<<(std::ostream& os, const SomaType v) { 13 | switch (v) { 14 | case SOMA_SINGLE_POINT: 15 | return os << "SOMA_SINGLE_POINT"; 16 | case SOMA_NEUROMORPHO_THREE_POINT_CYLINDERS: 17 | return os << "SOMA_NEUROMORPHO_THREE_POINT_CYLINDERS"; 18 | case SOMA_CYLINDERS: 19 | return os << "SOMA_CYLINDERS"; 20 | case SOMA_SIMPLE_CONTOUR: 21 | return os << "SOMA_SIMPLE_CONTOUR"; 22 | 23 | default: 24 | case SOMA_UNDEFINED: 25 | return os << "SOMA_UNDEFINED"; 26 | } 27 | } 28 | 29 | } // namespace enums 30 | } // namespace morphio 31 | -------------------------------------------------------------------------------- /src/errorMessages.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | namespace morphio { 14 | /* 15 | * Controls the maximum number of warning to be printed on screen. 16 | * 0 will print no warning 17 | * -1 will print them all 18 | */ 19 | void set_maximum_warnings(int32_t n_warnings) { 20 | auto static_handler = getWarningHandler(); 21 | static_handler->setMaxWarningCount(n_warnings); 22 | } 23 | 24 | /* Whether to raise warning as errors */ 25 | void set_raise_warnings(bool is_raise) { 26 | auto static_handler = getWarningHandler(); 27 | static_handler->setRaiseWarnings(is_raise); 28 | } 29 | 30 | /** Ignore/Unignore a specific warning message */ 31 | void set_ignored_warning(enums::Warning warning, bool ignore) { 32 | auto static_handler = getWarningHandler(); 33 | static_handler->setIgnoredWarning(warning, ignore); 34 | } 35 | 36 | /** Ignore/Unignore a specific warning message */ 37 | void set_ignored_warning(const std::vector& warnings, bool ignore) { 38 | for (auto warning : warnings) { 39 | set_ignored_warning(warning, ignore); 40 | } 41 | } 42 | 43 | std::shared_ptr getWarningHandler() { 44 | static morphio::WarningHandlerPrinter warning_handler; 45 | return {std::shared_ptr{}, &warning_handler}; 46 | } 47 | 48 | } // namespace morphio 49 | -------------------------------------------------------------------------------- /src/glial_cell.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include // for RawDataError 6 | #include 7 | 8 | namespace morphio { 9 | 10 | GlialCell::GlialCell(const std::string& source) 11 | : Morphology(source) { 12 | if (properties_->_cellLevel._cellFamily != CellFamily::GLIA) { 13 | throw(RawDataError("File: " + source + 14 | " is not a GlialCell file. It should be a H5 file the cell type GLIA.")); 15 | } 16 | } 17 | 18 | } // namespace morphio 19 | -------------------------------------------------------------------------------- /src/mito_section.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | namespace morphio { 8 | 9 | mito_depth_iterator MitoSection::depth_begin() const { 10 | return mito_depth_iterator(*this); 11 | } 12 | 13 | mito_depth_iterator MitoSection::depth_end() const { 14 | return mito_depth_iterator(); 15 | } 16 | 17 | mito_breadth_iterator MitoSection::breadth_begin() const { 18 | return mito_breadth_iterator(*this); 19 | } 20 | 21 | mito_breadth_iterator MitoSection::breadth_end() const { 22 | return mito_breadth_iterator(); 23 | } 24 | 25 | mito_upstream_iterator MitoSection::upstream_begin() const { 26 | return mito_upstream_iterator(*this); 27 | } 28 | 29 | mito_upstream_iterator MitoSection::upstream_end() const { 30 | return mito_upstream_iterator(); 31 | } 32 | 33 | range MitoSection::neuriteSectionIds() const { 34 | return get(); 35 | } 36 | 37 | range MitoSection::diameters() const { 38 | return get(); 39 | } 40 | 41 | range MitoSection::relativePathLengths() const { 42 | return get(); 43 | } 44 | 45 | bool MitoSection::hasSameShape(const MitoSection& other) const noexcept { 46 | return (other.neuriteSectionIds() == neuriteSectionIds() && other.diameters() == diameters() && 47 | other.relativePathLengths() == relativePathLengths()); 48 | } 49 | } // namespace morphio 50 | -------------------------------------------------------------------------------- /src/mitochondria.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | #include 7 | 8 | namespace morphio { 9 | MitoSection Mitochondria::section(uint32_t id) const { 10 | return {id, properties_}; 11 | } 12 | 13 | std::vector Mitochondria::sections() const { 14 | std::vector sections_; 15 | for (unsigned int i = 0; i < properties_->get().size(); ++i) { 16 | sections_.push_back(section(i)); 17 | } 18 | return sections_; 19 | } 20 | 21 | std::vector Mitochondria::rootSections() const { 22 | std::vector result; 23 | const auto& mitoChildren = properties_->children(); 24 | const auto& it = mitoChildren.find(-1); 25 | if (it != mitoChildren.end()) { 26 | const auto& children = it->second; 27 | 28 | result.reserve(children.size()); 29 | for (auto id : children) { 30 | result.push_back(section(id)); 31 | } 32 | } 33 | return result; 34 | } 35 | 36 | } // namespace morphio 37 | -------------------------------------------------------------------------------- /src/mut/dendritic_spine.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | namespace morphio { 8 | namespace mut { 9 | 10 | DendriticSpine::DendriticSpine() 11 | : Morphology() { 12 | _cellProperties->_cellFamily = CellFamily::SPINE; 13 | _cellProperties->_version = {"h5", 1, 3}; 14 | } 15 | 16 | DendriticSpine::DendriticSpine(const std::string& source) 17 | : Morphology(source) { 18 | if (_cellProperties->_cellFamily != CellFamily::SPINE) { 19 | throw(RawDataError( 20 | "File: " + source + 21 | " is not a DendriticSpine file. It should be a H5 file the cell type SPINE.")); 22 | } 23 | } 24 | 25 | std::vector& 26 | DendriticSpine::postSynapticDensity() noexcept { 27 | return _dendriticSpineLevel._post_synaptic_density; 28 | } 29 | 30 | const std::vector& 31 | DendriticSpine::postSynapticDensity() const noexcept { 32 | return _dendriticSpineLevel._post_synaptic_density; 33 | } 34 | 35 | } // namespace mut 36 | } // namespace morphio 37 | -------------------------------------------------------------------------------- /src/mut/endoplasmic_reticulum.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | #include 7 | 8 | 9 | namespace morphio { 10 | namespace mut { 11 | EndoplasmicReticulum::EndoplasmicReticulum(const std::vector& section_indices, 12 | const std::vector& volumes, 13 | const std::vector& surface_areas, 14 | const std::vector& filament_counts) { 15 | properties_._sectionIndices = section_indices; 16 | properties_._volumes = volumes; 17 | properties_._surfaceAreas = surface_areas; 18 | properties_._filamentCounts = filament_counts; 19 | } 20 | 21 | EndoplasmicReticulum::EndoplasmicReticulum( 22 | const morphio::EndoplasmicReticulum& endoplasmic_reticulum) 23 | : properties_(endoplasmic_reticulum.properties_->_endoplasmicReticulumLevel) {} 24 | 25 | const std::vector& EndoplasmicReticulum::sectionIndices() const noexcept { 26 | return properties_._sectionIndices; 27 | } 28 | std::vector& EndoplasmicReticulum::sectionIndices() noexcept { 29 | return properties_._sectionIndices; 30 | } 31 | 32 | const std::vector& EndoplasmicReticulum::volumes() const noexcept { 33 | return properties_._volumes; 34 | } 35 | 36 | std::vector& EndoplasmicReticulum::volumes() noexcept { 37 | return properties_._volumes; 38 | } 39 | 40 | const std::vector& EndoplasmicReticulum::surfaceAreas() const noexcept { 41 | return properties_._surfaceAreas; 42 | } 43 | 44 | std::vector& EndoplasmicReticulum::surfaceAreas() noexcept { 45 | return properties_._surfaceAreas; 46 | } 47 | 48 | const std::vector& EndoplasmicReticulum::filamentCounts() const noexcept { 49 | return properties_._filamentCounts; 50 | } 51 | 52 | std::vector& EndoplasmicReticulum::filamentCounts() noexcept { 53 | return properties_._filamentCounts; 54 | } 55 | 56 | Property::EndoplasmicReticulumLevel EndoplasmicReticulum::buildReadOnly() const noexcept { 57 | return properties_; 58 | } 59 | 60 | } // namespace mut 61 | } // namespace morphio 62 | -------------------------------------------------------------------------------- /src/mut/glial_cell.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | namespace morphio { 8 | namespace mut { 9 | 10 | GlialCell::GlialCell() 11 | : Morphology() { 12 | _cellProperties->_cellFamily = CellFamily::GLIA; 13 | } 14 | 15 | GlialCell::GlialCell(const std::string& source) 16 | : Morphology(source) { 17 | if (_cellProperties->_cellFamily != CellFamily::GLIA) { 18 | throw(RawDataError("File: " + source + 19 | " is not a GlialCell file. It should be a H5 file the cell type GLIA.")); 20 | } 21 | } 22 | 23 | } // namespace mut 24 | } // namespace morphio 25 | -------------------------------------------------------------------------------- /src/mut/mito_section.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | #include 7 | 8 | namespace morphio { 9 | namespace mut { 10 | MitoSection::MitoSection(Mitochondria* mitochondria, 11 | unsigned int section_id, 12 | const Property::MitochondriaPointLevel& pointProperties) 13 | : id_(section_id) 14 | , mitochondria_(mitochondria) 15 | , _mitoPoints(pointProperties) {} 16 | 17 | MitoSection::MitoSection(Mitochondria* mitochondria, 18 | unsigned int section_id, 19 | const morphio::MitoSection& section) 20 | : MitoSection(mitochondria, 21 | section_id, 22 | Property::MitochondriaPointLevel(section.properties_->_mitochondriaPointLevel, 23 | section.range_)) {} 24 | 25 | MitoSection::MitoSection(Mitochondria* mitochondria, 26 | unsigned int section_id, 27 | const MitoSection& section) 28 | : id_(section_id) 29 | , mitochondria_(mitochondria) 30 | , _mitoPoints(section._mitoPoints) {} 31 | 32 | std::shared_ptr MitoSection::appendSection( 33 | const Property::MitochondriaPointLevel& points) { 34 | unsigned int parentId = id(); 35 | 36 | std::shared_ptr ptr( 37 | new MitoSection(mitochondria_, mitochondria_->_counter, points)); 38 | 39 | uint32_t childId = mitochondria_->_register(ptr); 40 | 41 | mitochondria_->parent_[childId] = parentId; 42 | mitochondria_->children_[parentId].push_back(ptr); 43 | return ptr; 44 | } 45 | 46 | std::shared_ptr MitoSection::appendSection( 47 | const std::shared_ptr& original_section, bool recursive) { 48 | std::shared_ptr ptr( 49 | new MitoSection(mitochondria_, mitochondria_->_counter, *original_section)); 50 | unsigned int parentId = id(); 51 | uint32_t section_id = mitochondria_->_register(ptr); 52 | 53 | mitochondria_->parent_[section_id] = parentId; 54 | mitochondria_->children_[parentId].push_back(ptr); 55 | 56 | if (recursive) { 57 | for (const auto& child : original_section->children()) { 58 | ptr->appendSection(child, true); 59 | } 60 | } 61 | 62 | return ptr; 63 | } 64 | 65 | std::shared_ptr MitoSection::appendSection(const morphio::MitoSection& section, 66 | bool recursive) { 67 | std::shared_ptr ptr( 68 | new MitoSection(mitochondria_, mitochondria_->_counter, section)); 69 | unsigned int parentId = id(); 70 | uint32_t childId = mitochondria_->_register(ptr); 71 | 72 | mitochondria_->parent_[childId] = parentId; 73 | mitochondria_->children_[parentId].push_back(ptr); 74 | 75 | if (recursive) { 76 | for (const auto& child : section.children()) { 77 | ptr->appendSection(child, true); 78 | } 79 | } 80 | 81 | return ptr; 82 | } 83 | 84 | std::shared_ptr MitoSection::parent() const { 85 | return mitochondria_->sections_.at(mitochondria_->parent_.at(id())); 86 | } 87 | 88 | bool MitoSection::isRoot() const { 89 | return mitochondria_->parent_.count(id()) == 0; 90 | } 91 | 92 | bool MitoSection::hasSameShape(const MitoSection& other) const noexcept { 93 | return (other.neuriteSectionIds() == neuriteSectionIds() && other.diameters() == diameters() && 94 | other.pathLengths() == pathLengths()); 95 | } 96 | 97 | const std::vector>& MitoSection::children() const { 98 | const auto& children = mitochondria_->children_; 99 | const auto it = children.find(id()); 100 | if (it == children.end()) { 101 | static std::vector> empty; 102 | return empty; 103 | } 104 | return it->second; 105 | } 106 | 107 | } // namespace mut 108 | } // namespace morphio 109 | -------------------------------------------------------------------------------- /src/mut/modifiers.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace morphio { 12 | namespace mut { 13 | namespace modifiers { 14 | 15 | void two_points_sections(morphio::mut::Morphology& morpho) { 16 | for (auto it = morpho.depth_begin(); it != morpho.depth_end(); ++it) { 17 | std::shared_ptr section = *it; 18 | size_t size = section->points().size(); 19 | if (size < 2) { 20 | continue; 21 | } 22 | section->points() = {section->points()[0], section->points()[size - 1]}; 23 | section->diameters() = {section->diameters()[0], section->diameters()[size - 1]}; 24 | if (!section->perimeters().empty()) { 25 | section->perimeters() = {section->perimeters()[0], section->perimeters()[size - 1]}; 26 | } 27 | } 28 | } 29 | 30 | void no_duplicate_point(morphio::mut::Morphology& morpho) { 31 | for (auto it = morpho.depth_begin(); it != morpho.depth_end(); ++it) { 32 | std::shared_ptr
section = *it; 33 | size_t size = section->points().size(); 34 | 35 | if (size < 1 || (*it)->isRoot()) { 36 | continue; 37 | } 38 | 39 | section->points().erase(section->points().begin()); 40 | section->diameters().erase(section->diameters().begin()); 41 | 42 | if (!section->perimeters().empty()) { 43 | section->perimeters().erase(section->perimeters().begin()); 44 | } 45 | } 46 | } 47 | 48 | void soma_sphere(morphio::mut::Morphology& morpho) { 49 | auto soma = morpho.soma(); 50 | const auto size = static_cast(soma->points().size()); 51 | 52 | if (size < 2) { 53 | return; 54 | } 55 | 56 | floatType x = 0; 57 | floatType y = 0; 58 | floatType z = 0; 59 | floatType r = 0; 60 | 61 | for (const Point& point : soma->points()) { 62 | x += point[0] / size; 63 | y += point[1] / size; 64 | z += point[2] / size; 65 | } 66 | 67 | for (auto point : soma->points()) { 68 | #ifdef MORPHIO_USE_DOUBLE 69 | r += sqrt(pow(point[0] - x, 2) + pow(point[1] - y, 2) + pow(point[2] - z, 2)) / size; 70 | #else 71 | r += sqrtf(powf(point[0] - x, 2) + powf(point[1] - y, 2) + powf(point[2] - z, 2)) / size; 72 | #endif 73 | } 74 | 75 | soma->points() = {{x, y, z}}; 76 | soma->diameters() = {r}; 77 | } 78 | 79 | static bool NRN_order_comparator(std::shared_ptr
a, std::shared_ptr
b) { 80 | return a->type() < b->type(); 81 | } 82 | 83 | void nrn_order(morphio::mut::Morphology& morpho) { 84 | std::stable_sort(morpho._rootSections.begin(), 85 | morpho._rootSections.end(), 86 | NRN_order_comparator); 87 | } 88 | 89 | } // namespace modifiers 90 | 91 | } // namespace mut 92 | 93 | } // namespace morphio 94 | -------------------------------------------------------------------------------- /src/mut/soma.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | #include 7 | 8 | #include "../point_utils.h" // centerOfGRavity, maxDistanceToCenterOfGravity 9 | #include "../shared_utils.hpp" // _somaSurface 10 | 11 | namespace morphio { 12 | namespace mut { 13 | Soma::Soma(const Property::PointLevel& point_properties) 14 | : point_properties_(point_properties) {} 15 | 16 | Soma::Soma(const morphio::Soma& soma) 17 | : soma_type_(soma.type()) 18 | , point_properties_(soma.properties_->_somaLevel) {} 19 | 20 | Point Soma::center() const { 21 | return centerOfGravity(points()); 22 | } 23 | 24 | floatType Soma::surface() const { 25 | return _somaSurface(type(), diameters(), points()); 26 | } 27 | 28 | floatType Soma::maxDistance() const { 29 | return maxDistanceToCenterOfGravity(point_properties_._points); 30 | } 31 | 32 | } // end namespace mut 33 | } // end namespace morphio 34 | -------------------------------------------------------------------------------- /src/mut/writer_asc.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | #include // std::fixed, std::setw, std::setprecision 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../error_message_generation.h" 16 | #include "../shared_utils.hpp" 17 | #include "writer_utils.h" 18 | 19 | namespace { 20 | void write_asc_points(std::ofstream& myfile, 21 | const morphio::Points& points, 22 | const std::vector& diameters, 23 | size_t indentLevel) { 24 | for (unsigned int i = 0; i < points.size(); ++i) { 25 | myfile << std::fixed << std::setprecision(morphio::FLOAT_PRECISION_PRINT) 26 | << std::string(indentLevel, ' ') << '(' << points[i][0] << ' ' << points[i][1] << ' ' 27 | << points[i][2] << ' ' << diameters[i] << ")\n"; 28 | } 29 | } 30 | 31 | void write_asc_section(std::ofstream& myfile, 32 | const std::shared_ptr& section, 33 | size_t indentLevel) { 34 | const std::string indent(indentLevel, ' '); 35 | write_asc_points(myfile, section->points(), section->diameters(), indentLevel); 36 | 37 | if (!section->children().empty()) { 38 | auto children = section->children(); 39 | size_t nChildren = children.size(); 40 | for (unsigned int i = 0; i < nChildren; ++i) { 41 | myfile << indent << (i == 0 ? "(\n" : "|\n"); 42 | write_asc_section(myfile, children[i], indentLevel + 2); 43 | } 44 | myfile << indent << ")\n"; 45 | } 46 | } 47 | } // namespace 48 | 49 | namespace morphio { 50 | namespace mut { 51 | namespace writer { 52 | 53 | void asc(const Morphology& morph, 54 | const std::string& filename, 55 | std::shared_ptr handler) { 56 | if (details::emptyMorphology(morph, handler)) { 57 | throw morphio::WriterError(morphio::details::ErrorMessages().ERROR_EMPTY_MORPHOLOGY()); 58 | } 59 | 60 | details::validateContourSoma(morph, handler); 61 | details::checkSomaHasSameNumberPointsDiameters(*morph.soma()); 62 | details::validateHasNoMitochondria(morph, handler); 63 | details::validateHasNoPerimeterData(morph); 64 | details::validateRootPointsHaveTwoOrMorePoints(morph); 65 | 66 | std::ofstream myfile(filename); 67 | 68 | const std::shared_ptr& soma = morph.soma(); 69 | if (!soma->points().empty()) { 70 | myfile << "(\"CellBody\"\n (Color Red)\n (CellBody)\n"; 71 | write_asc_points(myfile, soma->points(), soma->diameters(), 2); 72 | myfile << ")\n\n"; 73 | } 74 | 75 | for (const std::shared_ptr
& section : morph.rootSections()) { 76 | const auto type = section->type(); 77 | if (type == SECTION_AXON) { 78 | myfile << "( (Color Cyan)\n (Axon)\n"; 79 | } else if (type == SECTION_DENDRITE) { 80 | myfile << "( (Color Red)\n (Dendrite)\n"; 81 | } else if (type == SECTION_APICAL_DENDRITE) { 82 | myfile << "( (Color Red)\n (Apical)\n"; 83 | } else { 84 | throw WriterError( 85 | morphio::details::ErrorMessages().ERROR_UNSUPPORTED_SECTION_TYPE(type)); 86 | } 87 | write_asc_section(myfile, section, 2); 88 | myfile << ")\n\n"; 89 | } 90 | 91 | myfile << "; " << details::version_string() << '\n'; 92 | } 93 | } // end namespace writer 94 | } // end namespace mut 95 | } // end namespace morphio 96 | -------------------------------------------------------------------------------- /src/mut/writer_utils.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | #include "../error_message_generation.h" 8 | #include "morphio/warning_handling.h" 9 | #include "writer_utils.h" 10 | 11 | namespace morphio { 12 | namespace mut { 13 | namespace writer { 14 | namespace details { 15 | 16 | using morphio::details::ErrorMessages; 17 | 18 | void checkSomaHasSameNumberPointsDiameters(const Soma& soma) { 19 | const size_t n_points = soma.points().size(); 20 | const size_t n_diameters = soma.diameters().size(); 21 | 22 | if (n_points != n_diameters) { 23 | throw morphio::WriterError(ErrorMessages().ERROR_VECTOR_LENGTH_MISMATCH( 24 | "soma points", n_points, "soma diameters", n_diameters)); 25 | } 26 | } 27 | 28 | bool hasPerimeterData(const morphio::mut::Morphology& morph) { 29 | return !morph.rootSections().empty() && !morph.rootSections().front()->perimeters().empty(); 30 | } 31 | 32 | std::string version_string() { 33 | return std::string("Created by MorphIO v") + getVersionString(); 34 | } 35 | 36 | bool emptyMorphology(const morphio::mut::Morphology& morph, 37 | std::shared_ptr handler) { 38 | if (morph.soma()->points().empty() && morph.rootSections().empty()) { 39 | handler->emit(std::make_shared()); 40 | return true; 41 | } 42 | return false; 43 | } 44 | 45 | void validateContourSoma(const morphio::mut::Morphology& morph, 46 | std::shared_ptr handler) { 47 | const std::shared_ptr& soma = morph.soma(); 48 | const std::vector& somaPoints = soma->points(); 49 | 50 | if (somaPoints.empty()) { 51 | handler->emit(std::make_shared()); 52 | } else if (soma->type() == SOMA_UNDEFINED) { 53 | handler->emit(std::make_shared()); 54 | } else if (soma->type() != SomaType::SOMA_SIMPLE_CONTOUR) { 55 | handler->emit(std::make_shared()); 56 | } else if (somaPoints.size() < 3) { 57 | throw WriterError(ErrorMessages().ERROR_SOMA_INVALID_CONTOUR()); 58 | } 59 | } 60 | 61 | void validateHasNoPerimeterData(const morphio::mut::Morphology& morph) { 62 | if (details::hasPerimeterData(morph)) { 63 | throw WriterError(ErrorMessages().ERROR_PERIMETER_DATA_NOT_WRITABLE()); 64 | } 65 | } 66 | 67 | void validateHasNoMitochondria(const morphio::mut::Morphology& morph, 68 | std::shared_ptr handler) { 69 | if (!morph.mitochondria().rootSections().empty()) { 70 | handler->emit(std::make_shared()); 71 | } 72 | } 73 | 74 | void validateRootPointsHaveTwoOrMorePoints(const morphio::mut::Morphology& morph) { 75 | for (const auto& root : morph.rootSections()) { 76 | if (root->points().size() < 2) { 77 | throw morphio::RawDataError("Root sections must have at least 2 points"); 78 | } 79 | } 80 | 81 | } 82 | 83 | } // namespace details 84 | } // namespace writer 85 | } // namespace mut 86 | } // namespace morphio 87 | -------------------------------------------------------------------------------- /src/mut/writer_utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace morphio { 11 | namespace mut { 12 | namespace writer { 13 | namespace details { 14 | 15 | void checkSomaHasSameNumberPointsDiameters(const morphio::mut::Soma&); 16 | bool hasPerimeterData(const morphio::mut::Morphology&); 17 | std::string version_string(); 18 | bool emptyMorphology(const morphio::mut::Morphology&, 19 | std::shared_ptr handler); 20 | void validateContourSoma(const morphio::mut::Morphology&, 21 | std::shared_ptr handler); 22 | void validateHasNoPerimeterData(const morphio::mut::Morphology&); 23 | void validateHasNoMitochondria(const morphio::mut::Morphology&, 24 | std::shared_ptr handler); 25 | void validateRootPointsHaveTwoOrMorePoints(const morphio::mut::Morphology& morph); 26 | 27 | } // namespace details 28 | } // namespace writer 29 | } // namespace mut 30 | } // namespace morphio 31 | -------------------------------------------------------------------------------- /src/point_utils.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include // std::max 6 | #include // std::sqrt 7 | #include // std::accumulate 8 | #include // ostringstream 9 | #include // std::string 10 | 11 | #include "point_utils.h" 12 | 13 | #include 14 | 15 | namespace morphio { 16 | Point subtract(const Point& left, const Point& right) { 17 | Point ret; 18 | for (size_t i = 0; i < ret.size(); ++i) { 19 | ret[i] = left[i] - right[i]; 20 | } 21 | return ret; 22 | } 23 | 24 | floatType euclidean_distance(const Point& left, const Point& right) { 25 | return std::sqrt((left[0] - right[0]) * (left[0] - right[0]) + 26 | (left[1] - right[1]) * (left[1] - right[1]) + 27 | (left[2] - right[2]) * (left[2] - right[2])); 28 | } 29 | 30 | std::string dumpPoint(const Point& point) { 31 | std::ostringstream oss; 32 | oss << point[0] << " " << point[1] << " " << point[2]; 33 | return oss.str(); 34 | } 35 | 36 | std::string dumpPoints(const range& points) { 37 | std::ostringstream oss; 38 | for (const auto& point : points) { 39 | oss << dumpPoint(point) << '\n'; 40 | } 41 | return oss.str(); 42 | } 43 | 44 | Point centerOfGravity(const range& points) { 45 | Point::value_type x = 0; 46 | Point::value_type y = 0; 47 | Point::value_type z = 0; 48 | const auto count = static_cast(points.size()); 49 | for (const auto& point : points) { 50 | x += point[0]; 51 | y += point[1]; 52 | z += point[2]; 53 | } 54 | return Point({x / count, y / count, z / count}); 55 | } 56 | 57 | floatType maxDistanceToCenterOfGravity(const Points& points) { 58 | const auto c = centerOfGravity(points); 59 | return std::accumulate(std::begin(points), 60 | std::end(points), 61 | floatType{0}, 62 | [&](floatType a, const Point& b) { 63 | return std::max(a, euclidean_distance(c, b)); 64 | }); 65 | } 66 | 67 | } // namespace morphio 68 | 69 | std::ostream& operator<<(std::ostream& os, const morphio::Point& point) { 70 | return os << morphio::dumpPoint(point); 71 | } 72 | 73 | std::ostream& operator<<(std::ostream& os, const morphio::Points& points) { 74 | return os << morphio::dumpPoints(points); 75 | } 76 | 77 | std::ostream& operator<<(std::ostream& os, const morphio::range& points) { 78 | return os << morphio::dumpPoints(points); 79 | } 80 | -------------------------------------------------------------------------------- /src/point_utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | #include // std::ostream 8 | #include // std::string 9 | 10 | #pragma once 11 | 12 | namespace morphio { 13 | Point subtract(const Point& left, const Point& right); 14 | 15 | Point centerOfGravity(const range& points); 16 | 17 | floatType maxDistanceToCenterOfGravity(const Points& points); 18 | 19 | std::string dumpPoint(const Point& point); 20 | std::string dumpPoints(const range& points); 21 | 22 | floatType euclidean_distance(const Point& left, const Point& right); 23 | 24 | } // namespace morphio 25 | 26 | std::ostream& operator<<(std::ostream& os, const morphio::Point& point); 27 | std::ostream& operator<<(std::ostream& os, const morphio::Points& points); 28 | std::ostream& operator<<(std::ostream& os, const morphio::range& points); 29 | -------------------------------------------------------------------------------- /src/readers/morphologyASC.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #pragma once 7 | #include "morphio/warning_handling.h" 8 | #include 9 | 10 | namespace morphio { 11 | namespace readers { 12 | namespace asc { 13 | Property::Properties load(const std::string& path, 14 | const std::string& contents, 15 | unsigned int options, 16 | WarningHandler*); 17 | } // namespace asc 18 | } // namespace readers 19 | } // namespace morphio 20 | -------------------------------------------------------------------------------- /src/readers/morphologyHDF5.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #pragma once 7 | #include 8 | #include // std::string 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | namespace morphio { 16 | namespace readers { 17 | namespace h5 { 18 | Property::Properties load(const std::string& uri, WarningHandler*); 19 | Property::Properties load(const HighFive::Group& group, WarningHandler*); 20 | 21 | class MorphologyHDF5 22 | { 23 | public: 24 | explicit MorphologyHDF5(const HighFive::Group& group, const std::string& uri = "HDF5 GROUP"); 25 | virtual ~MorphologyHDF5() = default; 26 | Property::Properties load(WarningHandler*); 27 | 28 | private: 29 | void _checkVersion(); 30 | void _readMetadata(); 31 | void _readPoints(int); 32 | int _readSections(); 33 | void _readPerimeters(int); 34 | void _readMitochondria(); 35 | void _readEndoplasmicReticulum(); 36 | void _readDendriticSpinePostSynapticDensity(); 37 | 38 | template 39 | void _read(const std::string& group, 40 | const std::string& _dataset, 41 | unsigned int expectedDimension, 42 | T& data); 43 | 44 | HighFive::Group _group; 45 | Property::Properties _properties; 46 | std::string _uri; 47 | }; 48 | 49 | inline std::recursive_mutex& global_hdf5_mutex() { 50 | static std::recursive_mutex _mutex; 51 | return _mutex; 52 | } 53 | 54 | } // namespace h5 55 | } // namespace readers 56 | } // namespace morphio 57 | -------------------------------------------------------------------------------- /src/readers/morphologySWC.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace morphio { 13 | namespace readers { 14 | namespace swc { 15 | Property::Properties load(const std::string& path, 16 | const std::string& contents, 17 | unsigned int options, 18 | std::shared_ptr& warning_handler); 19 | } // namespace swc 20 | } // namespace readers 21 | } // namespace morphio 22 | -------------------------------------------------------------------------------- /src/readers/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "./utils.h" 2 | 3 | namespace morphio { 4 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 5 | #define freelocale _free_locale 6 | #define strtol_l _strtol_l 7 | 8 | #ifdef MORPHIO_USE_DOUBLE 9 | #define strto_float _strtod_l 10 | #else 11 | #define strto_float _strtof_l 12 | #endif 13 | 14 | #else // not WIN32 15 | 16 | #ifdef MORPHIO_USE_DOUBLE 17 | #define strto_float strtod_l 18 | #else 19 | #define strto_float strtof_l 20 | #endif 21 | 22 | #endif 23 | 24 | // Only create the `locale` to facilitate number handling once 25 | StringToNumber::StringToNumber() 26 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 27 | // On windows, use their locale handling for their runtime 28 | : locale(_create_locale(LC_ALL, "C")) { 29 | } 30 | #else 31 | // On other platforms, use the POSIX version 32 | : locale(newlocale(LC_NUMERIC_MASK, "POSIX", nullptr)) { 33 | } 34 | #endif 35 | 36 | StringToNumber::~StringToNumber() { 37 | freelocale(locale); 38 | } 39 | 40 | std::tuple StringToNumber::toInt(const std::string& s, size_t offset) const { 41 | const size_t base = 10; 42 | const char *pos = &s[offset]; 43 | const char *endpos = &s[s.size()]; 44 | int64_t ret = strtol_l(pos, const_cast(&endpos), base, locale); 45 | 46 | auto new_offset = static_cast(endpos - s.data()); 47 | 48 | if (ret == 0 && new_offset == 0) { 49 | throw std::invalid_argument("could not parse integer"); 50 | } 51 | 52 | return {ret, new_offset}; 53 | } 54 | 55 | std::tuple StringToNumber::toFloat(const std::string& s, size_t offset) const { 56 | const char *pos = &s[offset]; 57 | const char *endpos = &s[s.size()]; 58 | floatType ret = strto_float(pos, const_cast(&endpos), locale); 59 | 60 | auto new_offset = static_cast(endpos - s.data()); 61 | 62 | if (std::fabs(ret - 0) < morphio::epsilon && new_offset == 0) { 63 | throw std::invalid_argument("could not parse float"); 64 | } 65 | 66 | return {ret, new_offset}; 67 | } 68 | 69 | StringToNumber& getStringToNumber() { 70 | static StringToNumber stn; 71 | return stn; 72 | } 73 | 74 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 75 | #undef freelocale 76 | #undef strtol_l 77 | #endif 78 | 79 | #undef strto_float 80 | 81 | } // namespace morphio 82 | -------------------------------------------------------------------------------- /src/readers/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include // locale_t 3 | #include 4 | #include // std::tuple 5 | 6 | #include // floatType 7 | 8 | namespace morphio { 9 | 10 | struct StringToNumber { 11 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) 12 | _locale_t locale; 13 | #else 14 | locale_t locale; 15 | #endif 16 | 17 | StringToNumber(); 18 | ~StringToNumber(); 19 | 20 | std::tuple toInt(const std::string&s, size_t offset) const; 21 | std::tuple toFloat(const std::string&s, size_t offset) const; 22 | }; 23 | 24 | StringToNumber& getStringToNumber(); 25 | 26 | } // namespace morphio 27 | -------------------------------------------------------------------------------- /src/readers/vasculatureHDF5.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #pragma once 7 | 8 | #include // std::unique_ptr 9 | #include // std::string 10 | #include // std::vector 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | namespace morphio { 20 | namespace readers { 21 | namespace h5 { 22 | 23 | class VasculatureHDF5 24 | { 25 | public: 26 | explicit VasculatureHDF5(const std::string& uri) 27 | : _uri(uri) {} 28 | 29 | virtual ~VasculatureHDF5() = default; 30 | 31 | vasculature::property::Properties load(); 32 | 33 | private: 34 | void _readDatasets(); 35 | void _readPoints(); 36 | void _readSections(); 37 | void _readSectionTypes(); 38 | void _readConnectivity(); 39 | 40 | std::unique_ptr _file; 41 | 42 | std::unique_ptr _points; 43 | std::vector _pointsDims; 44 | 45 | std::unique_ptr _sections; 46 | std::vector _sectionsDims; 47 | 48 | std::unique_ptr _connectivity; 49 | std::vector _conDims; 50 | 51 | vasculature::property::Properties _properties; 52 | bool _write; 53 | std::string _uri; 54 | }; 55 | } // namespace h5 56 | } // namespace readers 57 | } // namespace morphio 58 | -------------------------------------------------------------------------------- /src/section.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include // any_of 6 | 7 | #include 8 | 9 | #include "point_utils.h" // operator<< 10 | 11 | namespace morphio { 12 | 13 | bool Section::isHeterogeneous(bool downstream) const { 14 | auto predicate = [&](const Section& s) { return type() != s.type(); }; 15 | if (downstream) { 16 | return std::any_of(breadth_begin(), breadth_end(), predicate); 17 | } 18 | return std::any_of(upstream_begin(), upstream_end(), predicate); 19 | } 20 | 21 | bool Section::hasSameShape(const Section& other) const noexcept { 22 | return (other.type() == type() && other.diameters() == diameters() && 23 | other.points() == points() && other.perimeters() == perimeters()); 24 | } 25 | 26 | } // namespace morphio 27 | 28 | std::ostream& operator<<(std::ostream& os, const morphio::Section& section) { 29 | const auto& points = section.points(); 30 | if (points.empty()) { 31 | os << "Section(id=" << section.id() << ", points=[])"; 32 | } else { 33 | os << "Section(id=" << section.id() << ", points=[(" << points[0] << "),..., (" 34 | << points[points.size() - 1] << ")])"; 35 | } 36 | return os; 37 | } 38 | -------------------------------------------------------------------------------- /src/shared_utils.hpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include // std::ostream 6 | #include 7 | #include 8 | 9 | #include "point_utils.h" 10 | 11 | 12 | namespace morphio { 13 | 14 | floatType _somaSurface(const SomaType type, 15 | const range& diameters, 16 | const range& points); 17 | 18 | template 19 | void _appendVector(std::vector& to, const std::vector& from, int offset) { 20 | to.insert(to.end(), from.begin() + offset, from.end()); 21 | } 22 | 23 | template 24 | std::vector copySpan(const std::vector& data, 25 | SectionRange range) { 26 | if (data.empty()) { 27 | return {}; 28 | } 29 | 30 | return {data.begin() + static_cast(range.first), 31 | data.begin() + static_cast(range.second)}; 32 | } 33 | 34 | /** 35 | * Is `path` a directory? 36 | * 37 | * Symlinks to directories are considered directories. 38 | */ 39 | bool is_directory(const std::string& path); 40 | 41 | /** 42 | * Is `path` a regular file? 43 | * 44 | * Symlinks to regular files are considered files. 45 | */ 46 | bool is_regular_file(const std::string& path); 47 | 48 | /** 49 | * Join `dirname` and `filename` into one path. 50 | * 51 | * This follows the Python `os.path.join` semantics, i.e., 52 | * - join_path("", "foo") == "foo" (not "/foo") 53 | * - join_path("/usr", "/home/foo") == "/home/foo" (not "/usr/home/foo") 54 | */ 55 | std::string join_path(const std::string& dirname, const std::string& filename); 56 | 57 | namespace property { 58 | 59 | template 60 | bool compare(const T& el1, const T& el2) { 61 | return el1 == el2; 62 | } 63 | } // namespace property 64 | 65 | namespace details { 66 | enum ThreePointSomaStatus { 67 | Conforms, 68 | ZeroColumnsAreTheSame, 69 | OneColumnIsTheSame, 70 | ThreeColumnsAreTheSame, 71 | NotRadiusOffset, 72 | }; 73 | 74 | ThreePointSomaStatus checkNeuroMorphoSoma(const std::array&, floatType); 75 | std::ostream& operator<<(std::ostream& os, ThreePointSomaStatus s); 76 | } // namespace details 77 | } // namespace morphio 78 | -------------------------------------------------------------------------------- /src/soma.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "point_utils.h" 11 | #include "shared_utils.hpp" 12 | 13 | namespace morphio { 14 | Soma::Soma(const std::shared_ptr& properties) 15 | : properties_(properties) {} 16 | 17 | Point Soma::center() const { 18 | return centerOfGravity(properties_->_somaLevel._points); 19 | } 20 | 21 | floatType Soma::volume() const { 22 | switch (properties_->_cellLevel._somaType) { 23 | case SOMA_NEUROMORPHO_THREE_POINT_CYLINDERS: { 24 | floatType radius = diameters()[0] / 2; 25 | return 4 * morphio::PI * radius * radius; 26 | } 27 | 28 | case SOMA_SINGLE_POINT: 29 | case SOMA_CYLINDERS: 30 | case SOMA_SIMPLE_CONTOUR: 31 | case SOMA_UNDEFINED: 32 | default: 33 | throw std::runtime_error("Volume is not supported"); 34 | } 35 | } 36 | 37 | floatType Soma::surface() const { 38 | return _somaSurface(type(), diameters(), points()); 39 | } 40 | 41 | floatType Soma::maxDistance() const { 42 | return maxDistanceToCenterOfGravity(properties_->_somaLevel._points); 43 | } 44 | 45 | } // namespace morphio 46 | -------------------------------------------------------------------------------- /src/vasc/properties.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../point_utils.h" 12 | #include "../shared_utils.hpp" 13 | 14 | namespace { 15 | bool compare_section_structure( 16 | const std::vector& vec1, 17 | const std::vector& vec2) { 18 | if (vec1.size() != vec2.size()) { 19 | return false; 20 | } 21 | 22 | for (size_t i = 1; i < vec1.size(); ++i) { 23 | if (vec1[i] - vec1[1] != vec2[i] - vec2[1]) { 24 | return false; 25 | } 26 | } 27 | return true; 28 | } 29 | 30 | 31 | } // namespace 32 | 33 | 34 | namespace morphio { 35 | namespace vasculature { 36 | namespace property { 37 | 38 | VascPointLevel::VascPointLevel(const std::vector& points, 39 | const std::vector& diameters) 40 | : _points(points) 41 | , _diameters(diameters) { 42 | if (_points.size() != _diameters.size()) { 43 | throw SectionBuilderError( 44 | "Point vector have size: " + std::to_string(_points.size()) + 45 | "while Diameter vector has size: " + std::to_string(_diameters.size())); 46 | } 47 | } 48 | 49 | VascPointLevel::VascPointLevel(const VascPointLevel& data) 50 | : VascPointLevel(data._points, data._diameters) {} 51 | 52 | VascPointLevel::VascPointLevel(const VascPointLevel& data, SectionRange range) { 53 | _points = copySpan(data._points, range); 54 | _diameters = copySpan(data._diameters, range); 55 | } 56 | 57 | bool VascSectionLevel::diff(const VascSectionLevel& other) const { 58 | return this == &other || 59 | (compare_section_structure(this->_sections, other._sections) && 60 | morphio::property::compare(this->_sectionTypes, other._sectionTypes) && 61 | morphio::property::compare(this->_predecessors, other._predecessors) && 62 | morphio::property::compare(this->_successors, other._successors)); 63 | } 64 | 65 | bool VascSectionLevel::operator==(const VascSectionLevel& other) const { 66 | return !diff(other); 67 | } 68 | 69 | bool VascSectionLevel::operator!=(const VascSectionLevel& other) const { 70 | return diff(other); 71 | } 72 | 73 | std::ostream& operator<<(std::ostream& os, const VascPointLevel& pointLevel) { 74 | os << "Point level properties:\n"; 75 | os << "Point diameter" 76 | << (pointLevel._diameters.size() == pointLevel._points.size() ? " Diameter\n" : "\n"); 77 | for (size_t i = 0; i < pointLevel._points.size(); ++i) { 78 | os << dumpPoint(pointLevel._points[i]) << ' ' << pointLevel._diameters[i] << '\n'; 79 | } 80 | return os; 81 | } 82 | 83 | std::ostream& operator<<(std::ostream& os, const Properties& properties) { 84 | return os << properties._pointLevel << '\n'; 85 | } 86 | } // namespace property 87 | } // namespace vasculature 88 | } // namespace morphio 89 | -------------------------------------------------------------------------------- /src/vasc/vasculature.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include // uint32_t 6 | #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) 7 | #define F_OK 0 8 | #include 9 | #else 10 | #include // access / F_OK 11 | #endif 12 | 13 | #include 14 | #include 15 | 16 | #include "../readers/morphologySWC.h" 17 | #include "../readers/vasculatureHDF5.h" 18 | 19 | namespace morphio { 20 | namespace vasculature { 21 | 22 | void buildConnectivity(std::shared_ptr properties); 23 | 24 | Vasculature::Vasculature(const std::string& source) { 25 | const size_t pos = source.find_last_of("."); 26 | if (pos == std::string::npos) { 27 | throw UnknownFileType("File has no extension"); 28 | } 29 | 30 | if (access(source.c_str(), F_OK) == -1) { 31 | throw RawDataError("File: " + source + " does not exist."); 32 | } 33 | 34 | std::string extension = source.substr(pos); 35 | 36 | property::Properties loader; 37 | if (extension == ".h5") { 38 | loader = readers::h5::VasculatureHDF5(source).load(); 39 | } else { 40 | throw UnknownFileType("File: " + source + " does not end with the .h5 extension"); 41 | } 42 | 43 | properties_ = std::make_shared(loader); 44 | 45 | buildConnectivity(properties_); 46 | } 47 | 48 | Section Vasculature::section(uint32_t id) const { 49 | return {id, properties_}; 50 | } 51 | 52 | std::vector
Vasculature::sections() const { 53 | std::vector
sections_; 54 | const auto& vasc_sections = properties_->get(); 55 | sections_.reserve(vasc_sections.size()); 56 | for (uint32_t i = 0; i < vasc_sections.size(); ++i) { 57 | sections_.emplace_back(i, properties_); 58 | } 59 | return sections_; 60 | } 61 | 62 | const std::vector Vasculature::sectionOffsets() const noexcept { 63 | // Vasculature section property is a single value representing the offset 64 | const auto& offsets = properties_->get(); 65 | 66 | const auto size = offsets.size(); 67 | std::vector indices(size + 1); 68 | 69 | std::copy(offsets.begin(), offsets.end(), indices.begin()); 70 | 71 | indices[size] = static_cast(this->points().size()); 72 | 73 | return indices; 74 | } 75 | 76 | const std::vector& 77 | Vasculature::sectionConnectivity() const noexcept { 78 | return properties_->get(); 79 | } 80 | 81 | graph_iterator Vasculature::begin() const { 82 | return graph_iterator(*this); 83 | } 84 | 85 | graph_iterator Vasculature::end() const { 86 | return graph_iterator(); 87 | } 88 | 89 | void buildConnectivity(std::shared_ptr properties) { 90 | const std::vector>& connectivity = 91 | properties->get(); 92 | auto& successors = properties->_sectionLevel._successors; 93 | auto& predecessors = properties->_sectionLevel._predecessors; 94 | 95 | for (const auto& connection : connectivity) { 96 | uint32_t first = connection[0]; 97 | uint32_t second = connection[1]; 98 | successors[first].push_back(second); 99 | predecessors[second].push_back(first); 100 | } 101 | } 102 | 103 | } // namespace vasculature 104 | } // namespace morphio 105 | -------------------------------------------------------------------------------- /src/version.cpp.in: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | namespace morphio 5 | { 6 | std::string getVersionString() { 7 | static const std::string version("@MORPHIO_VERSION_STRING@"); 8 | return version; 9 | } 10 | } // namespace morphio 11 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TESTS_SRC 2 | main.cpp 3 | test_collection.cpp 4 | test_enums.cpp 5 | test_immutable_morphology.cpp 6 | test_mitochondria.cpp 7 | test_morphology_readers.cpp 8 | test_mutable_morphology.cpp 9 | test_point_utils.cpp 10 | test_properties.cpp 11 | test_soma.cpp 12 | test_swc_reader.cpp 13 | test_utilities.cpp 14 | test_vasculature_morphology.cpp 15 | ) 16 | set(TESTS_LINK_LIBRAIRIES morphio_static HighFive Catch2::Catch2) 17 | 18 | if(APPLE) 19 | add_definitions("-DLIBCXX_INSTALL_FILESYSTEM_LIBRARY=YES") 20 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++") 21 | else() 22 | set(TESTS_LINK_LIBRAIRIES ${TESTS_LINK_LIBRAIRIES} PUBLIC stdc++fs) 23 | endif() 24 | 25 | add_executable(unittests ${TESTS_SRC}) 26 | 27 | # Using c++17 for the tests only. This "unlocks" an easy usage. 28 | set_target_properties(unittests 29 | PROPERTIES 30 | CXX_STANDARD 17 31 | CXX_STANDARD_REQUIRED YES 32 | CXX_EXTENSIONS NO 33 | ) 34 | 35 | target_compile_options(unittests PRIVATE 36 | $<$,$>: 37 | # don't warn about mixing floats and doubles in the tests, we since we test both for 38 | # morphio::floatType = {float, double}, we have to cast floating point number 39 | -Wno-implicit-float-conversion> 40 | ) 41 | 42 | if (MORPHIO_ENABLE_COVERAGE) 43 | include(CodeCoverage) 44 | SETUP_TARGET_FOR_COVERAGE_LCOV( 45 | NAME coverage 46 | EXECUTABLE ctest --output-on-failure 47 | DEPENDENCIES unittests 48 | EXCLUDE "/usr/*" "${PROJECT_SOURCE_DIR}/include/*" "${PROJECT_SOURCE_DIR}/3rdparty/*" 49 | ) 50 | endif() 51 | 52 | target_link_libraries(unittests 53 | PRIVATE 54 | ${TESTS_LINK_LIBRAIRIES} 55 | ) 56 | 57 | if (NOT EXTERNAL_CATCH2) 58 | catch_discover_tests( unittests 59 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 60 | ) 61 | endif() 62 | -------------------------------------------------------------------------------- /tests/data/annotations.asc: -------------------------------------------------------------------------------- 1 | ((Dendrite) 2 | (3 -4 0 2) 3 | (3 -6 0 2) 4 | (3 -8 0 2) 5 | (3 -10 0 2) 6 | ( 7 | (3 -10 0 2) 8 | (0 -10 0 2) 9 | (-3 -10 0 2) 10 | | ; <-- empty sibling but still works ! 11 | ) 12 | ) 13 | -------------------------------------------------------------------------------- /tests/data/astrocyte.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/astrocyte.h5 -------------------------------------------------------------------------------- /tests/data/complexe.swc: -------------------------------------------------------------------------------- 1 | # index type X Y Z radius parent 2 | 1 1 0.020000 0.020000 0.000000 0.124451 -1 3 | 2 1 0.068000 0.068000 0.000000 0.192333 1 4 | 3 1 0.116000 0.116000 0.000000 0.328098 2 5 | 4 1 0.164000 0.164000 0.000000 0.463862 3 6 | 5 1 0.212000 0.212000 0.000000 0.599627 4 7 | 6 1 0.260000 0.260000 0.000000 0.735391 5 8 | 7 1 0.308000 0.308000 0.000000 0.871156 6 9 | 8 1 0.356000 0.356000 0.000000 1.006920 7 10 | 9 1 0.404000 0.404000 0.000000 1.142685 8 11 | 10 1 0.452000 0.452000 0.000000 1.278449 9 12 | 11 1 0.500000 0.500000 0.000000 1.414214 10 13 | 12 1 0.548000 0.548000 0.000000 1.278449 11 14 | 13 1 0.596000 0.596000 0.000000 1.142685 12 15 | 14 1 0.644000 0.644000 0.000000 1.006920 13 16 | 15 1 0.692000 0.692000 0.000000 0.871156 14 17 | 16 1 0.740000 0.740000 0.000000 0.735391 15 18 | 17 1 0.788000 0.788000 0.000000 0.599627 16 19 | 18 1 0.836000 0.836000 0.000000 0.463862 17 20 | 19 1 0.884000 0.884000 0.000000 0.328098 18 21 | 20 1 0.932000 0.932000 0.000000 0.192333 19 22 | 21 1 0.980000 0.980000 0.000000 0.124451 20 23 | 22 2 0.000000 0.000000 0.000000 0.853513 1 24 | 23 2 0.000000 0.000000 0.100000 0.728556 22 25 | 24 2 -0.230907 -0.588320 0.257625 0.542229 23 26 | 25 2 -1.075483 -0.799626 0.770245 0.158341 24 27 | 26 2 -1.459043 -1.786882 0.831245 0.749711 25 28 | 27 2 -1.870406 -2.373398 1.725944 0.421039 26 29 | 28 2 -2.710822 -2.639591 2.066261 0.187787 27 30 | 29 2 -3.662137 -3.361521 2.590782 0.237023 28 31 | 30 2 -4.389185 -3.808853 3.265156 0.647296 29 32 | -------------------------------------------------------------------------------- /tests/data/disconnected_neurite.swc: -------------------------------------------------------------------------------- 1 | 1 1 0 0 0 1. -1 2 | 2 3 0 0 0 1. 1 3 | 3 3 0 5 0 1. 2 4 | 4 3 -5 5 0 1.5 3 5 | 5 3 6 5 0 1.5 3 6 | 6 2 0 0 0 1. 1 7 | 7 2 0 -4 0 1. 6 8 | 8 2 6 -4 0 2. 7 9 | 9 2 -5 -4 0 2. 7 10 | 10 3 -9 -8 0 2. -1 # <- this is connected to nothing 11 | -------------------------------------------------------------------------------- /tests/data/h5/empty.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/empty.h5 -------------------------------------------------------------------------------- /tests/data/h5/merged.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/merged.h5 -------------------------------------------------------------------------------- /tests/data/h5/non-valid.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/non-valid.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/Neuron-no-soma.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/Neuron-no-soma.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/Neuron.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/Neuron.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/endoplasmic-reticulum.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/endoplasmic-reticulum.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/glia.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/glia.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/glia_empty_perimeters.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/glia_empty_perimeters.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/glia_soma_only.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/glia_soma_only.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/glia_wrong_sized_perimeters.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/glia_wrong_sized_perimeters.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/h5v1.4.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/h5v1.4.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/incorrect_point_columns.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/incorrect_point_columns.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/incorrect_structure_columns.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/incorrect_structure_columns.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/make-dendritic-spine.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import h5py 3 | 4 | #from https://bbpteam.epfl.ch/documentation/projects/Morphology%20Documentation/latest/h5v1.html#dendritic-spine-example 5 | 6 | with h5py.File('simple-dendtric-spine.h5', 'w') as h5: 7 | h5.create_dataset('/points', 8 | data=np.array([[ 0., 5., 0., 0.1], # 0 \ 9 | [2.4, 9.1, 0., 0.2], # 1 | s0 10 | [0., 13.2, 0., 0.15], # 2 / 11 | [0., 13.2, 0., 0.2], # 3 \ s1 12 | [0., 15.9, 0., 2.4], # 4 / 13 | [0., 13.2, 0., 2.3], # 5 \ 14 | [2.4, 13.2, 0., 2.8], # 6 | s3 15 | [4.03, 13.2, 0., 2.4] # 7 / 16 | ], dtype=np.float32)) 17 | h5.create_dataset('/structure', 18 | data=np.array([[0, 2, -1], 19 | [3, 3, 0], 20 | [5, 2, 0]], np.int32)) 21 | 22 | h5.create_dataset('/organelles/postsynaptic_density/section_id', 23 | data=np.array([1, 2], dtype=np.uint32)) 24 | 25 | h5.create_dataset('/organelles/postsynaptic_density/segment_id', 26 | data=np.array([0, 1], dtype=np.uint32)) 27 | 28 | h5.create_dataset('/organelles/postsynaptic_density/offset', 29 | data=np.array([0.8525, 0.9], dtype=np.float32)) 30 | 31 | h5.create_group('metadata') 32 | 33 | h5['metadata'].attrs['version'] = np.array([1, 3], dtype=np.uint32) 34 | h5['metadata'].attrs['cell_family'] = np.array([2], dtype=np.uint32) 35 | 36 | -------------------------------------------------------------------------------- /tests/data/h5/v1/merged.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/merged.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/metadata_group_only.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/metadata_group_only.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/mitochondria.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/mitochondria.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/monodim.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/monodim.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/reversed_NRN_neurite_order.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/reversed_NRN_neurite_order.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/simple-broken-section-type.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/simple-broken-section-type.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/simple-dendritric-spine.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/simple-dendritric-spine.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/simple-negative-section-type.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/simple-negative-section-type.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/simple-single-point-soma.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/simple-single-point-soma.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/simple-two-point-soma.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/simple-two-point-soma.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/simple.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/simple.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/single-neurite.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/single-neurite.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/soma_after_dendrite.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/soma_after_dendrite.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/soma_no_neurites.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/soma_no_neurites.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/three-point-soma-two-offset.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/three-point-soma-two-offset.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/two_child_unmerged.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/two_child_unmerged.h5 -------------------------------------------------------------------------------- /tests/data/h5/v1/unknown_section_type_structure.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v1/unknown_section_type_structure.h5 -------------------------------------------------------------------------------- /tests/data/h5/v2/Neuron.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/v2/Neuron.h5 -------------------------------------------------------------------------------- /tests/data/h5/vasculature-broken-section-type.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/vasculature-broken-section-type.h5 -------------------------------------------------------------------------------- /tests/data/h5/vasculature1.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/vasculature1.h5 -------------------------------------------------------------------------------- /tests/data/h5/vasculature2.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/h5/vasculature2.h5 -------------------------------------------------------------------------------- /tests/data/invalid-incomplete.asc: -------------------------------------------------------------------------------- 1 | ( (Color White) ; [10,1] 2 | (Dendrite) 3 | ( -290.87 -113.09 -16.32 2.06) 4 | ( -290.87 -113.09 -16.32 2.06) 5 | ( 6 | ( -267.94 -128.61 -22.57 0.69) 7 | ( -204.90 -157.63 -42.45 0.69) 8 | (Cross ; [3,3] 9 | (Color Orange) 10 | (Name "Marker 3") 11 | ( -223.67 -157.92 -42.45 0.69) ; 1 12 | ( -222.76 -154.18 -39.90 0.69) ; 2 13 | ) ; End of markers 14 | Incomplete 15 | ( -206.90 -157.63 -42.45 0.69) 16 | | 17 | ( -269.77 -129.47 -22.57 0.92) ; R-2-2, 1 18 | ( -268.17 -130.62 -24.75 0.92) ; R-2-2, 2 19 | ( -266.79 -131.77 -26.13 0.92) ; R-2-2, 3 20 | Incomplete 21 | ) 22 | ) -------------------------------------------------------------------------------- /tests/data/iterators.asc: -------------------------------------------------------------------------------- 1 | ("CellBody" 2 | (Color Red) 3 | (CellBody) 4 | ( 0.5 0 0 0) 5 | ( 0.5 0.5 0 0) 6 | (-0.5 0 0 0) 7 | (-0.5 -0.5 0 0) 8 | ) 9 | 10 | ((Dendrite) 11 | (0 0 0 0) 12 | (1 0 0 0) 13 | ( 14 | (2 0 0 0) 15 | ( 16 | (3 0 0 0) 17 | | 18 | (4 0 0 0) 19 | ) 20 | | 21 | (5 0 0 0) 22 | ( 23 | (6 0 0 0) 24 | | 25 | (7 0 0 0) 26 | ) 27 | ) 28 | ) 29 | 30 | 31 | ((Axon) 32 | (0 0 0 0) 33 | (8 0 0 0) 34 | ( 35 | (9 0 0 0) 36 | | 37 | (10 0 0 0) 38 | ) 39 | ) 40 | -------------------------------------------------------------------------------- /tests/data/marker-with-string.asc: -------------------------------------------------------------------------------- 1 | ; The following annotation has been found in C280999A-I4.asc 2 | ; It is a top-level annotation with a quote inside 3 | ( (Color Red) 4 | ( -0.97 -141.17 84.77) 5 | "<--4 boutons on a PC soma" 6 | ) ; End of text 7 | 8 | ("CellBody" 9 | (Color Red) 10 | (CellBody) 11 | ( 0.001 0.001 0 0.01) 12 | ( -0.001 0.001 0 0.01) 13 | ( -0.001 -0.001 0 0.01) 14 | ( 0.001 -0.001 0 0.01) 15 | ) 16 | -------------------------------------------------------------------------------- /tests/data/markers.asc: -------------------------------------------------------------------------------- 1 | ; The file is created for C++ tests to increase coverage 2 | ( (Color White) ; [10,1] 3 | (Dendrite) 4 | ( -290.87 -113.09 -16.32 2.06) ; Root 5 | ( -290.87 -113.09 -16.32 2.06) ; R, 1 6 | ( 7 | ( -277.14 -119.13 -18.02 0.69) ; R-1, 1 8 | ( -275.54 -119.99 -16.67 0.69) ; R-1, 2 9 | (Cross ; [3,3] 10 | (Color Orange) 11 | (Name "Marker 3") 12 | ( -271.87 -121.14 -16.27 0.69) ; 1 13 | ( -269.34 -122.29 -15.48 0.69) ; 2 14 | ) ; End of markers 15 | Normal 16 | | 17 | ( -277.80 -120.28 -19.48 0.92) ; R-2, 1 18 | ( -276.65 -121.14 -20.20 0.92) ; R-2, 2 19 | (Cross ; [3,3] 20 | (Color Orange) 21 | (Name "Marker 3") 22 | ( -279.41 -119.99 -18.00 0.46) ; 1 23 | ( -272.98 -126.60 -21.22 0.92) ; 2 24 | ) ; End of markers 25 | ( 26 | ( -267.94 -128.61 -22.57 0.69) ; R-2-1, 1 27 | ( -204.90 -157.63 -42.45 0.69) ; R-2-1, 34 28 | (Cross ; [3,3] 29 | (Color Orange) 30 | (Name "Marker 3") 31 | ( -223.67 -157.92 -42.45 0.69) ; 1 32 | ( -222.76 -154.18 -39.90 0.69) ; 2 33 | ) ; End of markers 34 | Incomplete 35 | | 36 | ( -269.77 -129.47 -22.57 0.92) ; R-2-2, 1 37 | ( -268.17 -130.62 -24.75 0.92) ; R-2-2, 2 38 | ( -266.79 -131.77 -26.13 0.92) ; R-2-2, 3 39 | Incomplete 40 | ) ; End of split 41 | ) ; End of split 42 | ) -------------------------------------------------------------------------------- /tests/data/mono-type.asc: -------------------------------------------------------------------------------- 1 | ("CellBody" 2 | (Color Red) 3 | (CellBody) 4 | (0 0 0 2) 5 | (1 0 0 2) 6 | ) 7 | 8 | ((Axon) 9 | (0 0 0 2) 10 | (0 5 0 2) 11 | ) 12 | 13 | ((Dendrite) 14 | (0 0 0 2) 15 | (0 5 0 2) 16 | ) 17 | 18 | ((Dendrite) 19 | (1 0 0 2) 20 | (0 5 0 2) 21 | ) 22 | 23 | ((Apical) 24 | (1 0 0 2) 25 | (0 5 0 2) 26 | ) 27 | 28 | ((Apical) 29 | (0 0 0 2) 30 | (0 5 0 2) 31 | ) 32 | 33 | ((Dendrite) 34 | (2 0 0 2) 35 | (0 5 0 2) 36 | ) 37 | 38 | ((Dendrite) 39 | (3 0 0 2) 40 | (0 5 0 2) 41 | ) 42 | 43 | ((Axon) 44 | (1 0 0 2) 45 | (0 5 0 2) 46 | ) 47 | -------------------------------------------------------------------------------- /tests/data/multiple_point_section.asc: -------------------------------------------------------------------------------- 1 | ; Used in test_two_points_sections() 2 | 3 | ("CellBody" 4 | (Color Red) 5 | (CellBody) 6 | (1 0 0 0.1) 7 | (1 1 0 0.1) 8 | (-1 0 0 0.1) 9 | (-1 1 0 0.1) 10 | ) 11 | 12 | ((Dendrite) 13 | (0 0 0 2) 14 | (0 5 0 2) 15 | (10 50 0 2) 16 | ( 17 | (-5 5 0 3) 18 | (0 1 2 3) 19 | | 20 | (6 5 0 3) 21 | (0 4 5 6) 22 | ) 23 | ) 24 | 25 | 26 | ((Axon) 27 | (0 0 0 2) 28 | (0 -4 0 2) 29 | (5 5 5 5) 30 | (6 6 6 6) 31 | (7 7 7 7) 32 | ) 33 | -------------------------------------------------------------------------------- /tests/data/multiple_soma.swc: -------------------------------------------------------------------------------- 1 | # 2 soma, ids: 1, 10 2 | 1 1 0 0 0 1. -1 3 | 2 3 0 0 0 1. 1 4 | 3 3 0 5 0 1. 2 5 | 4 3 -5 5 0 1.5 3 6 | 5 3 6 5 0 1.5 3 7 | 6 2 0 0 0 1. 1 8 | 7 2 0 -4 0 1. 6 9 | 8 2 6 -4 0 2. 7 10 | 9 2 -5 -4 0 2. 7 11 | 10 1 0 0 0 1. -1 12 | -------------------------------------------------------------------------------- /tests/data/nested_single_children.asc: -------------------------------------------------------------------------------- 1 | ("CellBody" 2 | (CellBody) 3 | (1 0 0 0.1) 4 | (1 1 0 0.1) 5 | (-1 0 0 0.1) 6 | (-1 1 0 0.1) 7 | ) 8 | 9 | ( (Color Blue) 10 | (Axon) 11 | (0 0 0 8) 12 | (0 0 1 7) 13 | ( 14 | (0 0 2 6) 15 | ( 16 | (0 0 2 6) ; this duplicate should disapear in the merge 17 | (0 0 3 5) 18 | ( 19 | (0 0 4 4) 20 | ) 21 | ) 22 | ) 23 | ) 24 | -------------------------------------------------------------------------------- /tests/data/neurite_wrong_root_point.swc: -------------------------------------------------------------------------------- 1 | 1 1 0 0 0 5 -1 2 | 2 1 0 -5 0 5 1 3 | 3 1 0 +5 0 5 1 4 | 4 3 0 0 0 10 2 # <-- should have parent ID: 1 5 | 5 3 0 0 1 10 4 6 | 6 3 0 0 1 10 3 # <-- should have parent ID: 1 7 | 7 3 0 0 2 10 6 8 | -------------------------------------------------------------------------------- /tests/data/no_soma.swc: -------------------------------------------------------------------------------- 1 | 1 2 0 0 0 2.0 -1 2 | 2 2 0 -2 0 2.0 1 3 | 3 2 0 2 0 2.0 1 4 | -------------------------------------------------------------------------------- /tests/data/nrn-order-already-sorted.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlueBrain/MorphIO/7204ae6abdf3377188af9f778e60daf507250ca3/tests/data/nrn-order-already-sorted.h5 -------------------------------------------------------------------------------- /tests/data/pia.asc: -------------------------------------------------------------------------------- 1 | ; V3 text file written for MicroBrightField products. 2 | (ImageCoords) 3 | 4 | ("pia" 5 | (Closed) 6 | (MBFObjectType 5) 7 | (0 1 2 3) 8 | (3 4 5 4) 9 | (6 7 8 5) 10 | (9 10 11 6) 11 | ) 12 | 13 | ("layer1-2" 14 | (Color RGB (255, 251, 255)) 15 | (GUID "11594A5D0D7646B580E877CB40957E07") 16 | (MBFObjectType 5) 17 | (Resolution 1.846036) 18 | ( 983.07 455.36 -0.19 0.15) ; 2, 10 19 | ( 1192.31 420.35 -0.19 0.15) ; 2, 11 20 | ) ; End of contour 21 | 22 | ("CellBody" 23 | (Color Red) 24 | (CellBody) 25 | ( -3.69 14.30 2.81 0.22) ; 8, 1 26 | ( -3.97 12.63 2.69 0.22) ; 8, 2 27 | ( -4.02 11.32 2.44 0.22) ; 8, 3 28 | ( -3.85 9.84 2.19 0.22) ; 8, 4 29 | ( -3.76 8.09 2.13 0.22) ; 8, 5 30 | ) ; End of contour 31 | 32 | ( (Color Blue) 33 | (Axon) 34 | ( -2.87 -9.24 -5.06 1.47) ; Root 35 | ( -2.76 -10.41 -5.13 1.47) ; 1, R 36 | ( -2.03 -12.48 -5.13 1.25) ; 2 37 | ( -1.62 -13.30 -5.56 1.25) ; 3 38 | ) 39 | -------------------------------------------------------------------------------- /tests/data/reversed_NRN_neurite_order.swc: -------------------------------------------------------------------------------- 1 | # NRN simulator neurite order is: soma -> axon -> basal -> apical 2 | # In this file the order is reversed 3 | 1 1 0 0 0 1. -1 4 | 2 4 1 1 1 1. 1 # apical 5 | 3 4 2 1 1 1. 2 6 | 4 3 0 1 2 1. 1 # basal 7 | 5 3 0 1 3 1. 4 8 | 6 2 3 3 3 1. 1 # axon 9 | 7 2 3 3 4 1. 6 10 | -------------------------------------------------------------------------------- /tests/data/sections-block.asc: -------------------------------------------------------------------------------- 1 | ; Same file as simple.asc but with a (Sections) block 2 | 3 | ; V3 text file written for MicroBrightField products. 4 | (Sections S1 "576985993_0003" 3 100 0 5 | S2 "576985993_0013" 103 100 0 6 | S3 "576985993_0023" 203 100 0 7 | S4 "576985993_0033" 303 100 0 8 | S5 "576985993_0043" 403 100 0 9 | S6 "576985993_0053" 503 100 0 10 | S7 "576985993_0063" 603 100 0 11 | ) ; End of Sections 12 | 13 | ("CellBody" 14 | (Color Red) 15 | (CellBody) 16 | ( 0.001 0.001 0 0.01) 17 | ( -0.001 0.001 0 0.01) 18 | ( -0.001 -0.001 0 0.01) 19 | ( 0.001 -0.001 0 0.01) 20 | ) 21 | 22 | ((Dendrite) 23 | (0 0 0 2) 24 | (0 5 0 2) 25 | ( 26 | (-5 5 0 3) 27 | | 28 | (6 5 0 3) 29 | ) 30 | ) 31 | 32 | 33 | ((Axon) 34 | (0 0 0 2) 35 | (0 -4 0 2) 36 | ( 37 | (6 -4 0 4) 38 | | 39 | (-5 -4 0 4) 40 | ) 41 | ) 42 | -------------------------------------------------------------------------------- /tests/data/simple-all-types.swc: -------------------------------------------------------------------------------- 1 | # index, type, x, y, z, radius, parent 2 | 1 1 0. 0. 0. .1 -1 3 | 4 | 2 5 0. 0. 0. .5 1 5 | 3 5 4.06736643 9.13545458 0. .5 2 6 | 7 | 4 6 0. 0. 0. .6 1 8 | 5 6 7.43144825 6.69130606 0. .6 4 9 | 10 | 6 7 0. 0. 0. .7 1 11 | 7 7 9.51056516 3.09016994 0. .7 6 12 | 13 | 8 8 0. 0. 0. .8 1 14 | 9 8 9.94521895 -1.04528463 0. .8 8 15 | 16 | 10 9 0. 0. 0. .9 1 17 | 11 9 8.66025404 -5. 0. .9 10 18 | 19 | 12 10 0. 0. 0. 1.0 1 20 | 13 10 5.87785252 -8.09016994 0. 1.0 12 21 | 22 | 14 11 0. 0. 0. 1.1 1 23 | 15 11 2.07911691 -9.78147601 0. 1.1 14 24 | 25 | 16 12 0. 0. 0. 1.1 1 26 | 17 12 -2.07911691 -9.78147601 0. 1.2 16 27 | 28 | 18 13 0. 0. 0. 1.1 1 29 | 19 13 -5.87785252 -8.09016994 0. 1.3 18 30 | 31 | 20 14 0. 0. 0. 1.1 1 32 | 21 14 -8.66025404 -5. 0. 1.4 20 33 | 34 | 22 15 0. 0. 0. 1.1 1 35 | 23 15 -9.94521895 -1.04528463 0. 1.5 22 36 | 37 | 24 16 0. 0. 0. 1.1 1 38 | 25 16 -9.51056516 3.09016994 0. 1.6 24 39 | 40 | 26 17 0. 0. 0. 1.1 1 41 | 27 17 -7.43144825 6.69130606 0. 1.7 26 42 | 43 | 28 18 0. 0. 0. 1.1 1 44 | 29 18 -4.06736643 9.13545458 0. 1.8 28 45 | 46 | 30 19 0. 0. 0. 1.1 1 47 | 31 19 0. 10. 0. 1.9 30 48 | -------------------------------------------------------------------------------- /tests/data/simple-heterogeneous-neurite.swc: -------------------------------------------------------------------------------- 1 | # SWC structure: 2 | # 3 | # (0, 5) 4 | # (-5, 5)----- ------ (6, 5) <- types = 2 5 | # | 6 | # | 7 | # | 8 | # | Type = 3 9 | # | 10 | # o origin 11 | # | 12 | # | Type = 2 13 | # | 14 | # | 15 | #(-5, -4)----- ------ (6, -4) <- types = 3 16 | # (0, -4) 17 | # 18 | # all radii are 1, except for end points, which are 0 19 | # 20 | # This is the same file as simple.swc, but with changing types 21 | 22 | 23 | # index, type, x, y, z, radius, parent 24 | 1 1 0 0 0 1. -1 25 | 2 3 0 0 0 1. 1 26 | 3 3 0 5 0 1. 2 27 | 4 2 -5 5 0 1.5 3 28 | 5 2 6 5 0 1.5 3 29 | 6 2 0 0 0 1. 1 30 | 7 2 0 -4 0 1. 6 31 | 8 3 6 -4 0 2. 7 32 | 9 3 -5 -4 0 2. 7 33 | -------------------------------------------------------------------------------- /tests/data/simple-trailing-space.swc: -------------------------------------------------------------------------------- 1 | # note that this has a trailing spaces! 2 | 1 2 0 0 0 3.0 -1 3 | # ^ here 4 | 2 2 1 1 1 3.0 1 5 | 3 2 2 2 2 3.0 2 6 | -------------------------------------------------------------------------------- /tests/data/simple-windows-eol.swc: -------------------------------------------------------------------------------- 1 | # SWC structure: 2 | # index, type, x, y, z, radius, parent 3 | # 4 | # (0, 5) 5 | # (-5, 5)----- ------ (6, 5) 6 | # | 7 | # | 8 | # | 9 | # | Type = 3 10 | # | 11 | # o origin 12 | # | 13 | # | Type = 2 14 | # | 15 | # | 16 | #(-5, -4)----- ------ (6, -4) 17 | # (0, -4) 18 | # 19 | # all radii are 1, except for end points, which are 0 20 | # 21 | # This is the same file as simple.asc 22 | 23 | 24 | 1 1 0 0 0 1. -1 25 | 2 3 0 0 0 1. 1 26 | 3 3 0 5 0 1. 2 27 | 4 3 -5 5 0 1.5 3 28 | 5 3 6 5 0 1.5 3 29 | 6 2 0 0 0 1. 1 30 | 7 2 0 -4 0 1. 6 31 | 8 2 6 -4 0 2. 7 32 | 9 2 -5 -4 0 2.0000000000000000000000000000000000000000000000000000000000000 7 33 | # long value for radius is to make sure SWC parser accepts long values 34 | -------------------------------------------------------------------------------- /tests/data/simple-with-font.asc: -------------------------------------------------------------------------------- 1 | ; Same as simple.asc but with a (Font) block 2 | 3 | ("CellBody" 4 | (Color Red) 5 | (CellBody) 6 | ( 0.001 0.001 0 0.01) 7 | ( -0.001 0.001 0 0.01) 8 | ( -0.001 -0.001 0 0.01) 9 | ( 0.001 -0.001 0 0.01) 10 | ) 11 | 12 | 13 | ( (Color White) 14 | (Font "MS Sans Serif" 12) 15 | ( 7.79 -0.89 -4.31) 16 | "??" 17 | ) ; End of text 18 | 19 | 20 | ((Dendrite) 21 | (0 0 0 2) 22 | (0 5 0 2) 23 | ( 24 | (-5 5 0 3) 25 | | 26 | (6 5 0 3) 27 | ) 28 | ) 29 | 30 | 31 | ((Axon) 32 | (0 0 0 2) 33 | (0 -4 0 2) 34 | ( 35 | (6 -4 0 4) 36 | | 37 | (-5 -4 0 4) 38 | ) 39 | ) 40 | -------------------------------------------------------------------------------- /tests/data/simple-with-image-coord.asc: -------------------------------------------------------------------------------- 1 | ; Same as simple.asc but with a weird (ImageCoords) block 2 | 3 | (ImageCoords Filename 4 | "Z:\projects docs and shared files\AnalySIS\LNMC slices stained_10x\Rodrigo Perin\rp140212_ecord_3_10x_MinProjection.jpg" 5 | Merge 65535 65535 65535 0 6 | Coords 0.738551 0.739645 -560.248901 350.811127 13.104751 7 | ) ; End of ImageCoords 8 | 9 | ("CellBody" 10 | (Color Red) 11 | (CellBody) 12 | ( 0.001 0.001 0 0.01) 13 | ( -0.001 0.001 0 0.01) 14 | ( -0.001 -0.001 0 0.01) 15 | ( 0.001 -0.001 0 0.01) 16 | ) 17 | 18 | ((Dendrite) 19 | (0 0 0 2) 20 | (0 5 0 2) 21 | ( 22 | (-5 5 0 3) 23 | | 24 | (6 5 0 3) 25 | ) 26 | ) 27 | 28 | 29 | ((Axon) 30 | (0 0 0 2) 31 | (0 -4 0 2) 32 | ( 33 | (6 -4 0 4) 34 | | 35 | (-5 -4 0 4) 36 | ) 37 | ) 38 | -------------------------------------------------------------------------------- /tests/data/simple.asc: -------------------------------------------------------------------------------- 1 | ; This is the same morphology as simple.swc 2 | ; 3 | ; (0, 5) 4 | ; (-5, 5)----- ------ (6, 5) 5 | ; | 6 | ; | 7 | ; | 8 | ; | Type = 3 9 | ; | 10 | ; o origin 11 | ; | 12 | ; | Type = 2 13 | ; | 14 | ; | 15 | ;(-5, -4)----- ------ (6, -4) 16 | ; (0, -4) 17 | 18 | 19 | ("CellBody" 20 | (Color Red) 21 | (CellBody) 22 | ( 0.001 0.001 0 0.01) 23 | ( -0.001 0.001 0 0.01) 24 | ( -0.001 -0.001 0 0.01) 25 | ( 0.001 -0.001 0 0.01) 26 | ) 27 | 28 | ((Dendrite) 29 | (0 0 0 2) 30 | (0 5 0 2) 31 | ( 32 | (-5 5 0 3) 33 | | 34 | (6 5 0 3) 35 | ) 36 | ) 37 | 38 | 39 | ((Axon) 40 | (0 0 0 2) 41 | (0 -4 0 2) 42 | ( 43 | (6 -4 0 4) 44 | | 45 | (-5 -4 0 4) 46 | ) 47 | ) 48 | -------------------------------------------------------------------------------- /tests/data/simple.swc: -------------------------------------------------------------------------------- 1 | # SWC structure: 2 | # index, type, x, y, z, radius, parent 3 | # 4 | # (0, 5) 5 | # (-5, 5)----- ------ (6, 5) 6 | # | 7 | # | 8 | # | 9 | # | Type = 3 10 | # | 11 | # o origin 12 | # | 13 | # | Type = 2 14 | # | 15 | # | 16 | #(-5, -4)----- ------ (6, -4) 17 | # (0, -4) 18 | # 19 | # all radii are 1, except for end points, which are 0 20 | # 21 | # This is the same file as simple.asc 22 | 23 | 24 | 1 1 0 0 0 1. -1 25 | 2 3 0 0 0 1. 1 26 | 3 3 0 5 0 1. 2 27 | 4 3 -5 5 0 1.5 3 28 | 5 3 6 5 0 1.5 3 29 | 6 2 0 0 0 1. 1 30 | 7 2 0 -4 0 1. 6 31 | 8 2 6 -4 0 2. 7 32 | 9 2 -5 -4 0 2.0000000000000000000000000000000000000000000000000000000000000 7 33 | # long value for radius is to make sure SWC parser accepts long values 34 | -------------------------------------------------------------------------------- /tests/data/simple.unknown: -------------------------------------------------------------------------------- 1 | ; This is the same morphology as simple.swc 2 | ; 3 | ; (0, 5) 4 | ; (-5, 5)----- ------ (6, 5) 5 | ; | 6 | ; | 7 | ; | 8 | ; | Type = 3 9 | ; | 10 | ; o origin 11 | ; | 12 | ; | Type = 2 13 | ; | 14 | ; | 15 | ;(-5, -4)----- ------ (6, -4) 16 | ; (0, -4) 17 | 18 | 19 | ("CellBody" 20 | (Color Red) 21 | (CellBody) 22 | (0 0 0 2) 23 | ) 24 | 25 | ((Dendrite) 26 | (0 0 0 2) 27 | (0 5 0 2) 28 | ( 29 | (-5 5 0 3) 30 | | 31 | (6 5 0 3) 32 | ) 33 | ) 34 | 35 | 36 | ((Axon) 37 | (0 0 0 2) 38 | (0 -4 0 2) 39 | ( 40 | (6 -4 0 4) 41 | | 42 | (-5 -4 0 4) 43 | ) 44 | ) 45 | -------------------------------------------------------------------------------- /tests/data/simple2.asc: -------------------------------------------------------------------------------- 1 | ("CellBody" 2 | (Color Red) 3 | (CellBody) 4 | (0 0 0 2) 5 | ) 6 | 7 | ((Dendrite) 8 | (0 0 0 2) 9 | (0 5 0 2) 10 | ( 11 | (-5 5 0 3) 12 | (-6 5 0 3) 13 | ( 14 | (-7 5 0 3) 15 | | 16 | (-8 10 0 3) 17 | ) 18 | | 19 | (6 5 0 3) 20 | ) 21 | ) 22 | 23 | 24 | ((Axon) 25 | (0 0 0 2) 26 | (0 -4 0 2) 27 | ( 28 | (6 -4 0 4) 29 | | 30 | (-5 -4 0 4) 31 | ) 32 | ) 33 | -------------------------------------------------------------------------------- /tests/data/single_point_root.asc: -------------------------------------------------------------------------------- 1 | ((Dendrite) 2 | (3 -4 0 2) 3 | ( 4 | (3 -10 2 4) 5 | | 6 | (3 -10 0 2) 7 | ) 8 | ) 9 | -------------------------------------------------------------------------------- /tests/data/soma_cylinders.swc: -------------------------------------------------------------------------------- 1 | # A soma composed of three cylinders 2 | # Cylinders are along X and have a radius of 40 3 | 1 1 0 0 0 40 -1 4 | 2 1 1 0 0 40 1 5 | 3 1 2 0 0 40 2 6 | 4 1 3 0 0 40 3 7 | 5 2 0 0 0 40 2 8 | 6 2 0 0 0 40 5 9 | -------------------------------------------------------------------------------- /tests/data/soma_multiple_frustums.swc: -------------------------------------------------------------------------------- 1 | # A soma composed of three frustums 2 | # Soma surface (excluding endcaps) should be 4164.610254415956 3 | 1 1 0 0 0 40 -1 4 | 2 1 1 0 0 35 1 5 | 3 1 2 0 0 29 2 6 | 4 1 3 0 0 17 3 7 | -------------------------------------------------------------------------------- /tests/data/soma_single_frustum.swc: -------------------------------------------------------------------------------- 1 | # A soma composed of one frustum 2 | # Soma surface (excluding endcaps) should be 1201.428168331057 3 | 1 1 0 0 0 40 -1 4 | 2 1 1 0 0 35 1 5 | -------------------------------------------------------------------------------- /tests/data/soma_three_points_cylinder.swc: -------------------------------------------------------------------------------- 1 | # A three points soma (no dendrite) 2 | 1 1 0 0 0 9 -1 3 | 2 1 0 -9 0 9 1 4 | 3 1 0 9 0 9 1 -------------------------------------------------------------------------------- /tests/data/spine.asc: -------------------------------------------------------------------------------- 1 | ; V3 text file written for MicroBrightField products. 2 | (ImageCoords) 3 | 4 | ("Cell Body" 5 | (Color Red) 6 | (CellBody) 7 | ( 1 1 1 0.15) ; 1, 1 8 | ( 1 2 1 0.15) ; 1, 1 9 | ) ; End of contour 10 | 11 | 12 | ( (Color Magenta) 13 | (Dendrite) 14 | ( 3.22 -1.15 150.00 0.98) ; Root 15 | ( 5.84 -2.17 150.00 0.98) ; 1, R 16 | ( 9.34 -3.81 150.00 0.98) ; 2 17 | < (Class 4 "none") 18 | (Color MediumGray) 19 | (Generated 0) 20 | ( 9.57 -3.14 150.00 0.98)> ; Spine 21 | ( 9.99 -4.00 150.00 0.97) ; 3 22 | ( 11.38 -4.62 150.00 0.97) ; 4 23 | ( 12.55 -5.16 150.00 0.97) ; 5 24 | < (Class 4 "none") 25 | (Color MediumGray) 26 | (Generated 0) 27 | ( 12.97 -4.81 150.00 0.97)> ; Spine 28 | ( 13.75 -5.96 150.00 0.97) ; 6 29 | Normal 30 | ) ; End of tree 31 | -------------------------------------------------------------------------------- /tests/data/three_point_soma.swc: -------------------------------------------------------------------------------- 1 | # Neuron with NeuroMorpho 3 point soma. 2 | # In a three point soma. The first point bifurcates 3 | # into 2 other soma points. 4 | # This is the only valid bifurcating soma configuration. 5 | # # 6 | # SWC structure: 7 | # index, type, x, y, z, radius, parent 8 | 9 | 1 1 0 0 0 2.0 -1 10 | 2 1 0 -2 0 2.0 1 11 | 3 1 0 2 0 2.0 1 12 | # 1st neurite 13 | 4 2 0 0 4 0.1 1 14 | 5 2 0 0 5 0.1 4 15 | 6 2 0 0 6 0.1 5 16 | 7 2 0 0 7 0.1 6 17 | 8 2 0 0 8 0.1 7 18 | # 2nd neurite 19 | 9 2 1 0 3 0.5 1 20 | 10 2 2 0 3 0.5 9 21 | 11 2 3 0 3 0.5 10 22 | 12 2 4 0 3 0.5 11 23 | 13 2 5 0 3 0.5 12 24 | # 3rd neurite 25 | 14 3 0 1 6 0.5 1 26 | 15 3 0 2 6 0.5 14 27 | 16 3 0 3 6 0.5 15 28 | 17 3 0 4 6 0.5 16 29 | 18 3 0 5 6 0.5 17 30 | # 4th neurite 31 | 19 4 0 0 9 0.5 1 32 | 20 4 0 0 10 0.5 19 33 | 21 4 0 0 11 0.5 20 34 | 22 4 0 0 12 0.5 21 35 | 23 4 0 0 13 0.5 22 36 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | // Using catch2 for testing: https://github.com/catchorg/Catch2 6 | #define CATCH_CONFIG_MAIN // have Catch2 provide a main() 7 | #include 8 | -------------------------------------------------------------------------------- /tests/requirement_tests.txt: -------------------------------------------------------------------------------- 1 | h5py>=2.9.0 2 | pytest>=6.0 3 | numpy>=1.14.2 4 | -------------------------------------------------------------------------------- /tests/test_0_API.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | # SPDX-License-Identifier: Apache-2.0 3 | import morphio 4 | 5 | def test_doc_exists(): 6 | classes = [ 7 | morphio.EndoplasmicReticulum, 8 | morphio.MitoSection, 9 | morphio.Mitochondria, 10 | morphio.Morphology, 11 | morphio.Section, 12 | morphio.Soma, 13 | morphio.mut.EndoplasmicReticulum, 14 | morphio.mut.MitoSection, 15 | morphio.mut.Mitochondria, 16 | morphio.mut.Morphology, 17 | morphio.mut.Section, 18 | morphio.mut.Soma, 19 | ] 20 | 21 | # we want to makes sure we never forget to add imports in the morphio.__init__ 22 | # however, sometimes pybind adds new functions in that namespace, this is the 23 | # place to explicitly ignore them 24 | ignored_methods = { 25 | "_pybind11_conduit_v1_" 26 | } 27 | 28 | for cls in classes: 29 | public_methods = ( 30 | method for method in dir(cls) 31 | if not (method.startswith("__") or method in ignored_methods) 32 | ) 33 | for method in public_methods: 34 | assert getattr(cls, method).__doc__, \ 35 | 'Public method {} of class {} is not documented !'.format(method, cls) 36 | 37 | 38 | def test_mut_immut_have_same_methods(): 39 | '''Both modules morphio and morphio.mut should expose the same API''' 40 | def methods(cls): 41 | return set(method for method in dir(cls) if not method[:2] == '__') 42 | 43 | only_in_immut = { 44 | "section_types", 45 | "diameters", 46 | "perimeters", 47 | "points", 48 | "n_points", 49 | "section_offsets", 50 | "as_mutable", 51 | } 52 | only_in_mut = { 53 | "remove_unifurcations", 54 | "write", 55 | "append_root_section", 56 | "delete_section", 57 | "build_read_only", 58 | "as_immutable", 59 | } 60 | assert (methods(morphio.Morphology) - only_in_immut == 61 | methods(morphio.mut.Morphology) - only_in_mut) 62 | 63 | assert (methods(morphio.Section) - {'n_points'} == 64 | methods(morphio.mut.Section) - {'append_section'}) 65 | 66 | assert (methods(morphio.Soma) == 67 | methods(morphio.mut.Soma)) 68 | 69 | assert (methods(morphio.EndoplasmicReticulum) == 70 | methods(morphio.mut.EndoplasmicReticulum)) 71 | 72 | only_in_mut_mitochondria = { 73 | 'append_root_section', 74 | 'breadth_begin', 75 | 'breadth_end', 76 | 'children', 77 | 'depth_begin', 78 | 'is_root', 79 | 'parent', 80 | 'upstream_begin', 81 | } 82 | assert (methods(morphio.Mitochondria) == 83 | methods(morphio.mut.Mitochondria) - only_in_mut_mitochondria) 84 | -------------------------------------------------------------------------------- /tests/test_11_collection.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | # SPDX-License-Identifier: Apache-2.0 3 | from pathlib import Path 4 | 5 | import numpy as np 6 | import pytest 7 | 8 | import morphio 9 | 10 | 11 | DATA_DIR = Path(__file__).parent / "data" 12 | COLLECTION_PATHS = [DATA_DIR / "h5/v1/merged.h5", 13 | DATA_DIR / "h5/v1" 14 | ] 15 | 16 | 17 | def available_morphologies(): 18 | return [ 19 | "simple", 20 | "glia", 21 | "mitochondria", 22 | "endoplasmic-reticulum", 23 | "simple-dendritric-spine" 24 | ] 25 | 26 | 27 | def check_load_from_collection(collection): 28 | morphology_names = available_morphologies() 29 | 30 | for morph_name in morphology_names: 31 | print(morph_name) 32 | morph = collection.load(morph_name) 33 | assert isinstance(morph, morphio.Morphology) 34 | 35 | morph = collection.load(morph_name, mutable=False) 36 | assert isinstance(morph, morphio.Morphology) 37 | 38 | morph = collection.load(morph_name, mutable=True) 39 | assert isinstance(morph, morphio.mut.Morphology) 40 | 41 | @pytest.mark.parametrize("collection_path", COLLECTION_PATHS) 42 | def test_load_from_collection_with_context(collection_path): 43 | with morphio.Collection(collection_path) as collection: 44 | check_load_from_collection(collection) 45 | 46 | 47 | @pytest.mark.parametrize("collection_path", COLLECTION_PATHS) 48 | def test_load_from_collection_without_context(collection_path): 49 | collection = morphio.Collection(collection_path) 50 | 51 | check_load_from_collection(collection) 52 | 53 | collection.close() 54 | 55 | 56 | @pytest.mark.parametrize("collection_path", COLLECTION_PATHS) 57 | def test_container_unordered(collection_path): 58 | with morphio.Collection(collection_path) as collection: 59 | morphology_names = available_morphologies() 60 | morphology_names = morphology_names[1:] 61 | 62 | loop_indices = [] 63 | for k, morph in collection.load_unordered(morphology_names): 64 | loop_indices.append(k) 65 | 66 | np.testing.assert_array_equal( 67 | sorted(loop_indices), 68 | np.arange(len(morphology_names)) 69 | ) 70 | 71 | 72 | @pytest.mark.parametrize("collection_path", COLLECTION_PATHS) 73 | def test_container_unordered1(collection_path): 74 | with morphio.Collection(collection_path) as collection: 75 | morphology_names = available_morphologies() 76 | morphology_names = morphology_names[1:] 77 | 78 | loop_indices = collection.argsort(morphology_names) 79 | np.testing.assert_array_equal( 80 | sorted(loop_indices), 81 | np.arange(len(morphology_names)) 82 | ) 83 | 84 | def test_container_with_warning_handler(): 85 | with morphio.Collection(DATA_DIR) as collection: 86 | warning_handler = morphio.WarningHandlerCollector() 87 | collection.load('neurite_wrong_root_point', warning_handler=warning_handler) 88 | assert len(warning_handler.get_all()) == 2 89 | -------------------------------------------------------------------------------- /tests/test_3_h5.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | # SPDX-License-Identifier: Apache-2.0 3 | from itertools import chain, repeat 4 | from pathlib import Path 5 | 6 | import pytest 7 | from morphio import Morphology, RawDataError, SectionType, ostream_redirect 8 | from numpy.testing import assert_array_equal 9 | from utils import captured_output 10 | 11 | 12 | DATA_DIR = Path(__file__).parent / "data" 13 | H5_PATH = Path(DATA_DIR, 'h5') 14 | H5V1_PATH = Path(H5_PATH, 'v1') 15 | H5V2_PATH = Path(H5_PATH, 'v2') 16 | 17 | 18 | def test_v1(): 19 | n = Morphology(H5V1_PATH / 'simple.h5') 20 | assert len(n.root_sections) == 2 21 | assert n.root_sections[0].type == 3 22 | assert n.root_sections[1].type == 2 23 | assert n.version == ("h5", 1, 3) 24 | 25 | n = Morphology(H5V1_PATH / 'Neuron.h5') 26 | assert n.version == ("h5", 1, 0) 27 | 28 | assert len(n.sections) == 84 29 | assert len(n.soma.points) == 3 30 | assert len(list(n.iter())) == 84 31 | assert len(n.points) == 924 32 | 33 | section_types = list(s.type for s in n.iter()) 34 | assert len(section_types) == 84 35 | real_section_types = list(chain(repeat(SectionType.apical_dendrite, 21), 36 | repeat(SectionType.basal_dendrite, 42), 37 | repeat(SectionType.axon, 21))) 38 | 39 | assert section_types == real_section_types 40 | assert_array_equal(n.points[:7], 41 | [[0.0, 0.0, 0.0], 42 | [0.0, 0.0, 0.10000000149011612], 43 | [0.5529246926307678, -0.7534923553466797, 0.9035181403160095], 44 | [1.2052767276763916, -1.3861794471740723, 1.6835479736328125], 45 | [1.2670834064483643, -1.3914604187011719, 2.4186644554138184], 46 | [1.271288275718689, -2.3130500316619873, 3.192789077758789], 47 | [1.605881929397583, -2.6893420219421387, 3.992844343185425]]) 48 | 49 | 50 | def test_wrong_section_type(): 51 | with pytest.raises(RawDataError, match='Unsupported section type: 20'): 52 | Morphology(H5V1_PATH / 'simple-broken-section-type.h5') 53 | 54 | with pytest.raises(RawDataError, match='Unsupported section type: -2'): 55 | Morphology(H5V1_PATH / 'simple-negative-section-type.h5') 56 | 57 | 58 | def test_v2(): 59 | with pytest.raises(RawDataError, 60 | match='h5v2 is no longer supported, see: https://github.com/BlueBrain/MorphIO#H5v2'): 61 | Morphology(H5V2_PATH / 'Neuron.h5') 62 | 63 | 64 | def test_soma_no_neurite(): 65 | n = Morphology(H5V1_PATH / 'soma_no_neurites.h5') 66 | 67 | assert_array_equal(n.soma.points, 68 | [[ 0., 0., 0.], 69 | [ 1., 0., 0.], 70 | [ 0., 25., 0.]]) 71 | assert_array_equal(n.soma.diameters, 72 | [6, 6, 15]) 73 | 74 | assert len(n.root_sections) == 0 75 | 76 | 77 | def test_single_children(): 78 | with captured_output() as (_, _): 79 | with ostream_redirect(stdout=True, stderr=True): 80 | neuron = Morphology(H5V1_PATH / 'two_child_unmerged.h5') 81 | assert len(list(neuron.iter())) == 8 82 | -------------------------------------------------------------------------------- /tests/test_enums.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | TEST_CASE("enums") { 8 | SECTION("SOMA_SINGLE_POINT") { 9 | std::stringstream ss; 10 | ss << morphio::enums::SomaType::SOMA_SINGLE_POINT; 11 | CHECK(ss.str() == "SOMA_SINGLE_POINT"); 12 | } 13 | 14 | SECTION("SOMA_NEUROMORPHO_THREE_POINT_CYLINDERS") { 15 | std::stringstream ss; 16 | ss << morphio::enums::SomaType::SOMA_NEUROMORPHO_THREE_POINT_CYLINDERS; 17 | CHECK(ss.str() == "SOMA_NEUROMORPHO_THREE_POINT_CYLINDERS"); 18 | } 19 | 20 | SECTION("SOMA_CYLINDERS") { 21 | std::stringstream ss; 22 | ss << morphio::enums::SomaType::SOMA_CYLINDERS; 23 | CHECK(ss.str() == "SOMA_CYLINDERS"); 24 | } 25 | 26 | SECTION("SOMA_SIMPLE_CONTOUR") { 27 | std::stringstream ss; 28 | ss << morphio::enums::SomaType::SOMA_SIMPLE_CONTOUR; 29 | CHECK(ss.str() == "SOMA_SIMPLE_CONTOUR"); 30 | } 31 | 32 | SECTION("SOMA_UNDEFINED") { 33 | std::stringstream ss; 34 | ss << morphio::enums::SomaType::SOMA_UNDEFINED; 35 | CHECK(ss.str() == "SOMA_UNDEFINED"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/test_point_utils.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include "../src/point_utils.h" 6 | 7 | #include 8 | #include // std::stringstream 9 | 10 | 11 | TEST_CASE("morphio::Point") { 12 | using namespace morphio; 13 | Point p{10., 10., 10.}; 14 | 15 | std::vector points = {p, p, p}; 16 | 17 | CHECK(subtract(p, p) == morphio::Point{0, 0, 0}); 18 | REQUIRE_THAT(euclidean_distance(p, p), Catch::WithinAbs(0, 0.001)); 19 | CHECK(dumpPoint(p) == "10 10 10"); 20 | CHECK(dumpPoints(points) == "10 10 10\n10 10 10\n10 10 10\n"); 21 | 22 | { 23 | std::stringstream ss; 24 | ss << p; 25 | CHECK(ss.str() == "10 10 10"); 26 | } 27 | 28 | { 29 | std::stringstream ss; 30 | ss << points; 31 | CHECK(ss.str() == "10 10 10\n10 10 10\n10 10 10\n"); 32 | } 33 | 34 | { 35 | auto r = morphio::range(); 36 | std::stringstream ss; 37 | ss << r; 38 | CHECK(ss.str().empty()); 39 | 40 | ss.clear(); 41 | 42 | r = morphio::range(points).subspan(0, 2); 43 | ss << r; 44 | CHECK(ss.str() == "10 10 10\n10 10 10\n"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/test_soma.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | 14 | TEST_CASE("morphio::soma") { 15 | using namespace morphio::Property; 16 | 17 | SECTION("mismatch of points and diameters") { 18 | std::vector points; 19 | std::vector diameters{1, 1}; 20 | std::vector perimeters; 21 | 22 | CHECK_THROWS(PointLevel(points, diameters, perimeters)); 23 | } 24 | 25 | SECTION("Volumes") { 26 | const auto three_point = morphio::Morphology("data/three_point_soma.swc"); 27 | CHECK_THAT(three_point.soma().volume(), Catch::WithinAbs(50.26, 0.01)); 28 | 29 | const auto soma_cylinders = morphio::Morphology("data/soma_cylinders.swc"); 30 | CHECK_THROWS(soma_cylinders.soma().volume()); 31 | 32 | const auto soma_single_point = morphio::Morphology("data/soma_single_frustum.swc"); 33 | CHECK_THROWS(soma_single_point.soma().volume()); 34 | 35 | const auto soma_simple_contour = morphio::Morphology("data/simple.asc"); 36 | CHECK_THROWS(soma_simple_contour.soma().volume()); 37 | } 38 | 39 | SECTION("print SomaTypes") { 40 | using morphio::SomaType; 41 | std::stringstream ss; 42 | 43 | ss << SomaType::SOMA_UNDEFINED; 44 | CHECK(ss.str() == "SOMA_UNDEFINED"); 45 | 46 | ss.str(""); 47 | ss << SomaType::SOMA_SINGLE_POINT; 48 | CHECK(ss.str() == "SOMA_SINGLE_POINT"); 49 | 50 | ss.str(""); 51 | ss << SomaType::SOMA_NEUROMORPHO_THREE_POINT_CYLINDERS; 52 | CHECK(ss.str() == "SOMA_NEUROMORPHO_THREE_POINT_CYLINDERS"); 53 | 54 | ss.str(""); 55 | ss << SomaType::SOMA_CYLINDERS; 56 | CHECK(ss.str() == "SOMA_CYLINDERS"); 57 | 58 | ss.str(""); 59 | ss << SomaType::SOMA_SIMPLE_CONTOUR; 60 | CHECK(ss.str() == "SOMA_SIMPLE_CONTOUR"); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/test_vasculature_morphology.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | using Vasculature = morphio::vasculature::Vasculature; 13 | 14 | namespace { 15 | 16 | struct Files { 17 | std::string vasculature; 18 | 19 | Files() 20 | : vasculature("data/h5/vasculature1.h5") {} 21 | }; 22 | 23 | } // anonymous namespace 24 | 25 | 26 | TEST_CASE("vasculature_section_offsets", "[vasculature]") { 27 | Files files; 28 | morphio::vasculature::Vasculature morph(files.vasculature); 29 | 30 | const auto& sections = morph.sections(); 31 | size_t n_offsets = sections.size() + 1; 32 | 33 | std::vector expected_section_offsets; 34 | expected_section_offsets.reserve(n_offsets); 35 | 36 | uint32_t offset = 0; 37 | expected_section_offsets.push_back(offset); 38 | 39 | for (const auto& section : sections) { 40 | offset += static_cast(section.points().size()); 41 | expected_section_offsets.push_back(offset); 42 | } 43 | 44 | REQUIRE(morph.sectionOffsets() == expected_section_offsets); 45 | } 46 | 47 | 48 | TEST_CASE("vasculature_section_connectivity", "[vasculature]") { 49 | Files files; 50 | morphio::vasculature::Vasculature morph(files.vasculature); 51 | 52 | auto file = HighFive::File(files.vasculature, HighFive::File::ReadOnly); 53 | 54 | const auto dset = file.getDataSet("/connectivity"); 55 | const auto dims = dset.getSpace().getDimensions(); 56 | const size_t n_connections = dims[0]; 57 | 58 | const auto section_connectivity = morph.sectionConnectivity(); 59 | 60 | REQUIRE(section_connectivity.size() == n_connections); 61 | 62 | std::vector> expected_connectivity(n_connections); 63 | 64 | dset.read(expected_connectivity.front().data()); 65 | 66 | REQUIRE(section_connectivity == expected_connectivity); 67 | } 68 | -------------------------------------------------------------------------------- /tests/test_vector_utils.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | * 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | 7 | #include 8 | 9 | TEST_CASE("VectorTypes.Point", "[vector_types]") { 10 | using morphio::Point; 11 | const Point zero{0., 0., 0.}; 12 | 13 | SECTION("operator==") { 14 | CHECK(zero == zero); 15 | } 16 | SECTION("operator+") { 17 | // CHECK(zero == zero); 18 | } 19 | SECTION("operator-") {} 20 | SECTION("operator*") { 21 | // try pre and post versions 22 | } 23 | SECTION("operator/") {} 24 | 25 | SECTION("operator+=") {} 26 | SECTION("operator-=") {} 27 | SECTION("operator/=") {} 28 | } 29 | 30 | /* 31 | template 32 | Point centerOfGravity(const T& points); 33 | template 34 | floatType maxDistanceToCenterOfGravity(const T& points); 35 | 36 | REQUIRE_THAT(soma.surface(), Catch::WithinAbs(1017.87604, 0.001)); 37 | */ 38 | -------------------------------------------------------------------------------- /tests/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2023, EPFL/Blue Brain Project 2 | # SPDX-License-Identifier: Apache-2.0 3 | '''Module providing utility functions for the tests''' 4 | import re 5 | import sys 6 | from contextlib import contextmanager 7 | from functools import partial 8 | from io import StringIO 9 | 10 | import pytest 11 | from morphio import Morphology, set_ignored_warning, set_maximum_warnings 12 | 13 | 14 | @contextmanager 15 | def ignored_warning(warning): 16 | '''Context manager during which a warning is ignored''' 17 | try: 18 | set_ignored_warning(warning, True) 19 | yield 20 | finally: 21 | set_ignored_warning(warning, False) 22 | 23 | 24 | def strip_color_codes(string): 25 | '''Strip color codes from the input string''' 26 | ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]') 27 | return ansi_escape.sub('', string) 28 | 29 | 30 | def _assert_exception(content, exception, str1, str2, extension): 31 | '''with given content and check that the exception is raised''' 32 | with pytest.raises(exception) as obj: 33 | Morphology(content, extension=extension) 34 | assert obj.match(str1) 35 | assert obj.match(str2) 36 | 37 | 38 | assert_asc_exception = partial(_assert_exception, extension='asc') 39 | assert_swc_exception = partial(_assert_exception, extension='swc') 40 | 41 | 42 | @contextmanager 43 | def captured_output(): 44 | '''Capture the python streams 45 | 46 | To be used as: 47 | with captured_output() as (out, err): 48 | print('hello world') 49 | assert_equal(out.getvalue().strip(), 'hello world') 50 | ''' 51 | set_maximum_warnings(-1) 52 | new_out, new_err = StringIO(), StringIO() 53 | old_out, old_err = sys.stdout, sys.stderr 54 | try: 55 | sys.stdout, sys.stderr = new_out, new_err 56 | yield sys.stdout, sys.stderr 57 | finally: 58 | sys.stdout, sys.stderr = old_out, old_err 59 | --------------------------------------------------------------------------------