Skip to content

Commit

Permalink
lmorpho (#1746)
Browse files Browse the repository at this point in the history
Add the lmorpho utility back to Arbor

The original utility was removed because it was a maintenance burden with no users.
Now users are requesting the feature, this PR adds the old code, and updates it
to work with the new morphology description API.
  • Loading branch information
schmitts authored Dec 3, 2021
1 parent c88b7be commit 397a66b
Show file tree
Hide file tree
Showing 8 changed files with 1,045 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -556,3 +556,4 @@ install(
cmake/FindUnwind.cmake
DESTINATION "${cmake_config_dir}")

add_subdirectory(lmorpho)
8 changes: 8 additions & 0 deletions lmorpho/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
add_executable(lmorpho lmorpho.cpp lsystem.cpp lsys_models.cpp)

target_link_libraries(lmorpho PRIVATE arbor arbor-sup ext-tinyopt arborio)

# TODO: resolve public headers
target_link_libraries(lmorpho PRIVATE arbor-private-headers)

install(TARGETS lmorpho RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
115 changes: 115 additions & 0 deletions lmorpho/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# `lmporho` — generate random neuron morphologies

`lmorpho` implements an L-system geometry generator for the purpose of
generating a series of artificial neuron morphologies as described by a set of
stasticial parameters.

## Method

The basic algorithm used is that of [Burke (1992)][burke1992], with extensions
for embedding in 3-d taken from [Ascoli (2001)][ascoli2001].

A dendritic tree is represented by a piece-wise linear embedding of a rooted
tree into R³×R⁺, describing the position in space and non-negative radius.
Morphologies are represented as a sequence of these trees together with a point
and radius describing a (spherical) soma.

The generation process for a tree successively grows the terminal points by
some length ΔL each step, changing its orientation each step according to a
random distribution. After growing, there is a radius-dependent probability
that it will bifurcate or terminate. Parameters describing these various
probability distributions constitute the L-system model.

The distributions used in [Ascoli (2001)][ascoli2001] can be constant (i.e. not
random), uniform over some interval, truncated normal, or a mixture
distribution of these. In the present version of the code, mixture
distributions are not supported.

## Output

Generated morphologies can be output either in
[SWC format](http://research.mssm.edu/cnic/swc.html), or as 'parent vectors',
which describe the topology of the associated tree.

Entry _i_ of the (zero-indexed) parent vector gives the index of the proximal
unbranched section to which it connects. Somata have a parent index of -1.

Morphology information can be written one each to separate files or
concatenated. If concatenated, the parent vector indices will be shifted as
required to maintain consistency.

## Models

Two L-system parameter sets are provided as 'built-in'; if neither model is
selected, a simple, non-biological default model is used.

As mixture distributions are not yet supported in `lmorpho`, these models are
simplified approximations to those in the literature as described below.

### Motor neuron model

The 'motoneuron' model corresponds to the adult cat spinal alpha-motoneuron
model described in [Ascoli (2001)][ascoli2001], based in turn on the model of
[Burke (1992)][burke1992].

The model parameters in Ascoli are not complete; missing parameters were taken
from the corresponding ArborVitae model parameters in the same paper, and
somatic diameters were taken from [Cullheim (1987)][cullheim1987].

### Purkinke neuron model

The 'purkinke' model corresponds to the guinea pig Purkinje cell model from
[Ascoli (2001)][ascoli2001], which was fit to data from [Rapp
(1994)][rapp1994]. Somatic diameters are a simple fit to the three measurements
in the original source.

Some required parameters are not recorded in [Ascoli (2001)][ascoli2001];
the correlation component `diam_child_a` and the `length_step` ΔL are
taken from the corresponding L-Neuron parameter description in the
[L-Neuron database](l-neuron-database). These should be verified by
fitting against the digitized morphologies as found in the database.

Produced neurons from this model do not look especially realistic.

### Other models

There is not yet support for loading in arbitrary parameter sets, or for
translating or approximating the parameters that can be found in the
[L-Neuron database][l-neuron-database]. Support for parameter estimation
from a population of discretized morphologies would be useful.

## References

1. Ascoli, G. A., Krichmar, J. L., Scorcioni, R., Nasuto, S. J., Senft, S. L.
and Krichmar, G. L. (2001). Computer generation and quantitative morphometric
analysis of virtual neurons. _Anatomy and Embryology_ _204_(4), 283–301.
[DOI: 10.1007/s004290100201][ascoli2001]

2. Burke, R. E., Marks, W. B. and Ulfhake, B. (1992). A parsimonious description
of motoneuron dendritic morphology using computer simulation.
_The Journal of Neuroscience_ _12_(6), 2403–2416. [online][burke1992]

3. Cullheim, S., Fleshman, J. W., Glenn, L. L., and Burke, R. E. (1987).
Membrane area and dendritic structure in type-identified triceps surae alpha
motoneurons. _The Journal of Comparitive Neurology_ _255_(1), 68–81.
[DOI: 10.1002/cne.902550106][cullheim1987]

4. Rapp, M., Segev, I. and Yaom, Y. (1994). Physiology, morphology and detailed
passive models of guinea-pig cerebellar Purkinje cells.
_The Journal of Physiology_, _474_, 101–118.
[DOI: 10.1113/jphysiol.1994.sp020006][rapp1994].


[ascoli2001]: http://dx.doi.org/10.1007/s004290100201
"Ascoli et al. (2001). Computer generation […] of virtual neurons."

[burke1992]: http://www.jneurosci.org/content/12/6/2403
"Burke et al. (1992). A parsimonious description of motoneuron dendritic morphology […]"

[cullheim1987]: http://dx.doi.org/10.1002/cne.902550106
"Cullheim et al. (1987). Membrane area and dendritic structure in […] alpha motoneurons."

[rapp1994]: http://dx.doi.org/10.1113/jphysiol.1994.sp020006
"Rapp et al. (1994). Physiology, morphology […] of guinea-pig cerebellar Purkinje cells."

[l-neuron-database]: http://krasnow1.gmu.edu/cn3/L-Neuron/database/index.html
121 changes: 121 additions & 0 deletions lmorpho/lmorpho.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include <algorithm>
#include <iostream>
#include <fstream>
#include <map>
#include <sstream>
#include <vector>

#include <tinyopt/tinyopt.h>

#include "lsystem.hpp"
#include "lsys_models.hpp"

#include <arbor/cable_cell.hpp>
#include <arborio/cableio.hpp>
#include <arborio/label_parse.hpp>

const char* usage_str =
"[OPTION]...\n"
"\n"
" -n, --count=N Number of morphologies to generate.\n"
" -m, --model=MODEL Use L-system MODEL for generation (see below).\n"
" --acc=FILE Output morphologies as ACC to FILE.\n"
" -h, --help Emit this message and exit.\n"
"\n"
"Generate artificial neuron morphologies based on L-system descriptions.\n"
"\n"
"If a FILE argument contains a '%', then one file will be written for\n"
"each generated morphology, with the '%' replaced by the index of the\n"
"morphology, starting from zero.\n"
"A FILE argument of '-' corresponds to standard output.\n"
"\n"
"Currently supported MODELs:\n"
" motoneuron Adult cat spinal alpha-motoneurons, based on models\n"
" and data in Burke 1992 and Ascoli 2001.\n"
" purkinje Guinea pig Purkinje cells, basd on models and data\n"
" from Rapp 1994 and Ascoli 2001.\n";

int main(int argc, char** argv) {
// options
int n_morph = 1;
std::optional<unsigned> rng_seed = 0;
lsys_param P;
bool help = false;
std::optional<std::string> acc_file;

std::pair<const char*, const lsys_param*> models[] = {
{"motoneuron", &alpha_motoneuron_lsys},
{"purkinje", &purkinje_lsys}
};


try {
for (auto arg = argv+1; *arg; ) {
bool ok = false;
ok |= (n_morph << to::parse<int>(arg, "--n", "--count")).has_value();
ok |= (rng_seed << to::parse<int>(arg, "--s", "--seed")).has_value();
ok |= (acc_file << to::parse<std::string>(arg, "-f", "--acc")).has_value();
const lsys_param* o;
if((o << to::parse<const lsys_param*>(arg, to::keywords(models), "-m", "--model")).has_value()) {
P = *o;
}
ok |= (help << to::parse(arg, "-h", "--help")).has_value();
if (!ok) throw to::option_error("unrecognized argument", *arg);
}

if (help) {
to::usage(argv[0], usage_str);
return 0;
}

std::minstd_rand g;
if (rng_seed) {
g.seed(rng_seed.value());
}

using namespace arborio::literals;

auto apical = apical_lsys;
auto basal = basal_lsys;

for (int i = 0; i < n_morph; ++i) {
const arb::segment_tree morph = generate_morphology(P.diam_soma, std::vector<lsys_param>{apical, basal}, g);

arb::label_dict labels;
labels.set("soma", "(tag 1)"_reg);
labels.set("basal", "(tag 3)"_reg);
labels.set("apical", "(tag 4)"_reg);
arb::decor decor;

arb::cable_cell cell(morph, labels, decor);

if(acc_file) {
std::string filename = acc_file.value();
const std::string toReplace("%");
auto pos = filename.find(toReplace);
if(pos != std::string::npos) {
filename.replace(pos, toReplace.length(), std::to_string(i));
}

if(filename == "-") {
arborio::write_component(std::cout, cell);
} else {
std::ofstream of(filename);
arborio::write_component(of, cell);
}

}
}

} catch (to::option_error& e) {
std::cerr << argv[0] << ": " << e.what() << "\n";
std::cerr << "Try '" << argv[0] << " --help' for more information.\n";
std::exit(2);
}
catch (std::exception& e) {
std::cerr << "caught exception: " << e.what() << "\n";
std::exit(1);
}

}

Loading

0 comments on commit 397a66b

Please sign in to comment.