Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

resurrect lmorpho #1746

Merged
merged 4 commits into from
Dec 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -562,3 +562,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