Skip to content

Commit

Permalink
Check that mechanisms have the right kind (#1633)
Browse files Browse the repository at this point in the history
- Expose `arb_mechanism_kind` to `mechanism_info`.
- While building mechanism data in `fvm_build_mechanism_data`, check that synapses, painted region dynamics and reversal potential methods have the expected `arb_mechanism_kind`. 
- Add unit test.
  • Loading branch information
noraabiakar authored Aug 27, 2021
1 parent 88fa33d commit 37dd7de
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 4 deletions.
19 changes: 15 additions & 4 deletions arbor/fvm_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -858,14 +858,17 @@ fvm_mechanism_data fvm_build_mechanism_data(const cable_cell_global_properties&
const std::string& name = entry.first;
mechanism_info info = catalogue[name];

std::vector<double> param_dflt;
fvm_mechanism_config config;
config.kind = arb_mechanism_kind_density;
if (info.kind != arb_mechanism_kind_density) {
throw cable_cell_error("expected density mechanism, got " +name +" which has " +arb_mechsnism_kind_str(info.kind));
}
config.kind = info.kind;

std::vector<std::string> param_names;
assign(param_names, util::keys(info.parameters));
sort(param_names);

std::vector<double> param_dflt;
std::size_t n_param = param_names.size();
param_dflt.reserve(n_param);
config.param_values.reserve(n_param);
Expand Down Expand Up @@ -963,6 +966,10 @@ fvm_mechanism_data fvm_build_mechanism_data(const cable_cell_global_properties&
const std::string& name = entry.first;
mechanism_info info = catalogue[name];

if (info.kind != arb_mechanism_kind_point) {
throw cable_cell_error("expected point mechanism, got " +name +" which has " +arb_mechsnism_kind_str(info.kind));
}

post_events |= info.post_events;
std::size_t n_param = info.parameters.size();
std::size_t n_inst = entry.second.size();
Expand Down Expand Up @@ -1044,7 +1051,7 @@ fvm_mechanism_data fvm_build_mechanism_data(const cable_cell_global_properties&
bool coalesce = catalogue[name].linear && gprop.coalesce_synapses;

fvm_mechanism_config config;
config.kind = arb_mechanism_kind_point;
config.kind = info.kind;
for (auto& kv: info.parameters) {
config.param_values.emplace_back(kv.first, std::vector<value_type>{});
if (!coalesce) {
Expand Down Expand Up @@ -1210,6 +1217,10 @@ fvm_mechanism_data fvm_build_mechanism_data(const cable_cell_global_properties&
{
const mechanism_desc& revpot = *maybe_revpot;
mechanism_info info = catalogue[revpot.name()];
if (info.kind != arb_mechanism_kind_reversal_potential) {
throw cable_cell_error("expected reversal potential mechanism for ion " +ion +", got "+ revpot.name() +" which has " +arb_mechsnism_kind_str(info.kind));
}

verify_mechanism(info, revpot);
revpot_specified.insert(ion);

Expand Down Expand Up @@ -1248,7 +1259,7 @@ fvm_mechanism_data fvm_build_mechanism_data(const cable_cell_global_properties&
}
else {
fvm_mechanism_config config;
config.kind = arb_mechanism_kind_reversal_potential;
config.kind = info.kind;
config.cv = M.ions[ion].cv;
config.norm_area.assign(config.cv.size(), 1.);

Expand Down
9 changes: 9 additions & 0 deletions arbor/include/arbor/mechanism_abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ typedef uint32_t arb_backend_kind;
#define arb_backend_kind_cpu 1
#define arb_backend_kind_gpu 2

inline const char* arb_mechsnism_kind_str(const arb_mechanism_kind& mech) {
switch (mech) {
case arb_mechanism_kind_density: return "density mechanism kind";
case arb_mechanism_kind_point: return "point mechanism kind";
case arb_mechanism_kind_reversal_potential: return "reversal potential mechanism kind";
default: return "unknown mechanism kind";
}
}

// Ion state variables; view into shared_state
typedef struct arb_ion_state {
arb_value_type* current_density;
Expand Down
3 changes: 3 additions & 0 deletions arbor/include/arbor/mechinfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ struct mechanism_info {
mechanism_info(const arb_mechanism_type&);
mechanism_info() = default;

// Mechanism kind
arb_mechanism_kind kind;

// Global fields have one value common to an instance of a mechanism, are
// constant in time and set at instantiation.
std::unordered_map<std::string, mechanism_field_spec> globals;
Expand Down
1 change: 1 addition & 0 deletions arbor/mechinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace arb {
mechanism_info::mechanism_info(const arb_mechanism_type& m) {
kind = m.kind;
post_events = m.has_post_events;
linear = m.is_linear;
fingerprint = m.fingerprint;
Expand Down
10 changes: 10 additions & 0 deletions doc/python/mechanisms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ mechanism that is to be painted or placed on the cable cell.
print(mech.parameters['tau'].default)
# 2.0
.. py:attribute:: kind
:type: string

String representation of the kind of the mechanism: density, point or reversal potential.

.. py:attribute:: globals
:type: dict[str, mechanism_field]

Expand All @@ -163,6 +168,11 @@ mechanism that is to be painted or placed on the cable cell.

True if a synapse mechanism has linear current contributions so that multiple instances on the same :term:`control volume` can be coalesced.

.. py:attribute:: post_events
:type: bool

True if a synapse mechanism has a `POST_EVENT` procedure defined.


.. py:class:: ion_dependency
Expand Down
6 changes: 6 additions & 0 deletions python/mechanism.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ void register_mechanisms(pybind11::module& m) {
"Ion dependencies.")
.def_readonly("linear", &arb::mechanism_info::linear,
"True if a synapse mechanism has linear current contributions so that multiple instances on the same compartment can be coalesced.")
.def_readonly("post_events", &arb::mechanism_info::post_events,
"True if a synapse mechanism has a `POST_EVENT` procedure defined.")
.def_property_readonly("kind",
[](const arb::mechanism_info& info) {
return arb_mechsnism_kind_str(info.kind);
}, "String representation of the kind of the mechanism.")
.def("__repr__",
[](const arb::mechanism_info& inf) {
return util::pprintf("(arbor.mechanism_info)"); })
Expand Down
25 changes: 25 additions & 0 deletions test/unit/test_fvm_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,31 @@ namespace {
}
} // namespace

template<typename P>
void check_compatible_mechanism_failure(cable_cell_global_properties gprop, P painter) {
auto system = two_cell_system();

painter(system);

auto cells = system.cells();
check_two_cell_system(cells);
fvm_cv_discretization D = fvm_cv_discretize(cells, gprop.default_parameters);

EXPECT_THROW(fvm_build_mechanism_data(gprop, cells, D), arb::cable_cell_error);
}

TEST(fvm_layout, compatible_mechanisms) {
cable_cell_global_properties gprop;
gprop.default_parameters = neuron_parameter_defaults;

check_compatible_mechanism_failure(gprop, [](auto& sys) {sys.descriptions[0].decorations.place(sys.builders[0].location({1, 0.4}), "hh", "syn0"); });
check_compatible_mechanism_failure(gprop, [](auto& sys) {sys.descriptions[1].decorations.paint(sys.builders[1].cable(mcable{0}), "expsyn"); });
check_compatible_mechanism_failure(gprop, [](auto& sys) {sys.descriptions[0].decorations.set_default(ion_reversal_potential_method{"na", "expsyn"}); });

gprop.default_parameters.reversal_potential_method["na"] = "pas";
check_compatible_mechanism_failure(gprop, [](auto& sys) {});
}

TEST(fvm_layout, mech_index) {
auto system = two_cell_system();
auto& descriptions = system.descriptions;
Expand Down

0 comments on commit 37dd7de

Please sign in to comment.