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

Apply some polish to model construction. #2134

Merged
merged 7 commits into from
Jul 26, 2023
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
8 changes: 6 additions & 2 deletions doc/python/mechanisms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Cable cell mechanisms
If global parameters change, we are effectively defining a new type
of mechanism, so global parameter information is encoded in the
name.
Range parameters are set using a dictionary of name-value pairs.
Range parameters are set using a dictionary of name-value pairs or as kwargs.

.. code-block:: Python

Expand All @@ -46,7 +46,11 @@ Cable cell mechanisms
pas_2 = arbor.mechanism('pas/e=-45')

# A passive leaky channel with custom reversal potential (global), and custom conductance (range).
pas_3 = arbor.mechanism('pas/e=-45', {'g', 0.1})
pas_3a = arbor.mechanism('pas/e=-45', {'g', 0.1})

# A passive leaky channel with custom reversal potential (global), and custom conductance (range)
# written as keyword args.
pas_3b = arbor.mechanism('pas/e=-45', g=0.1)

# This is an equivalent to pas_3, using set method to specify range parameters.
pas_4 = arbor.mechanism('pas/e=-45')
Expand Down
21 changes: 19 additions & 2 deletions python/cells.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "pybind11/pytypes.h"
#include "schedule.hpp"
#include "strprintf.hpp"
#include "util.hpp"

namespace pyarb {

Expand Down Expand Up @@ -472,6 +473,8 @@ void register_cells(pybind11::module& m) {
.def(pybind11::init([](arb::mechanism_desc mech) {return arb::density(mech);}))
.def(pybind11::init([](const std::string& name, const std::unordered_map<std::string, double>& params) {return arb::density(name, params);}))
.def(pybind11::init([](arb::mechanism_desc mech, const std::unordered_map<std::string, double>& params) {return arb::density(mech, params);}))
.def(pybind11::init([](const std::string& name, pybind11::kwargs parms) {return arb::density(name, util::dict_to_map<double>(parms));}))
.def(pybind11::init([](arb::mechanism_desc mech, pybind11::kwargs params) {return arb::density(mech, util::dict_to_map<double>(params));}))
.def_readonly("mech", &arb::density::mech, "The underlying mechanism.")
.def("__repr__", [](const arb::density& d){return "<arbor.density " + mechanism_desc_str(d.mech) + ">";})
.def("__str__", [](const arb::density& d){return "<arbor.density " + mechanism_desc_str(d.mech) + ">";});
Expand All @@ -482,6 +485,8 @@ void register_cells(pybind11::module& m) {
.def(pybind11::init([](arb::mechanism_desc mech) {return arb::voltage_process(mech);}))
.def(pybind11::init([](const std::string& name, const std::unordered_map<std::string, double>& params) {return arb::voltage_process(name, params);}))
.def(pybind11::init([](arb::mechanism_desc mech, const std::unordered_map<std::string, double>& params) {return arb::voltage_process(mech, params);}))
.def(pybind11::init([](arb::mechanism_desc mech, pybind11::kwargs params) {return arb::voltage_process(mech, util::dict_to_map<double>(params));}))
.def(pybind11::init([](const std::string& name, pybind11::kwargs parms) {return arb::voltage_process(name, util::dict_to_map<double>(parms));}))
.def_readonly("mech", &arb::voltage_process::mech, "The underlying mechanism.")
.def("__repr__", [](const arb::voltage_process& d){return "<arbor.voltage_process " + mechanism_desc_str(d.mech) + ">";})
.def("__str__", [](const arb::voltage_process& d){return "<arbor.voltage_process " + mechanism_desc_str(d.mech) + ">";});
Expand All @@ -496,8 +501,16 @@ void register_cells(pybind11::module& m) {
.def(pybind11::init(
[](arb::density dens, const std::unordered_map<std::string, std::string>& scales) {
auto s = arb::scaled_mechanism<arb::density>(std::move(dens));
for (const auto& it: scales) {
s.scale(it.first, arborio::parse_iexpr_expression(it.second).unwrap());
for (const auto& [k, v]: scales) {
s.scale(k, arborio::parse_iexpr_expression(v).unwrap());
}
return s;
}))
.def(pybind11::init(
[](arb::density dens, pybind11::kwargs scales) {
auto s = arb::scaled_mechanism<arb::density>(std::move(dens));
for (const auto& [k, v]: util::dict_to_map<std::string>(scales)) {
s.scale(k, arborio::parse_iexpr_expression(v).unwrap());
}
return s;
}))
Expand Down Expand Up @@ -526,6 +539,8 @@ void register_cells(pybind11::module& m) {
.def(pybind11::init([](arb::mechanism_desc mech) {return arb::synapse(mech);}))
.def(pybind11::init([](const std::string& name, const std::unordered_map<std::string, double>& params) {return arb::synapse(name, params);}))
.def(pybind11::init([](arb::mechanism_desc mech, const std::unordered_map<std::string, double>& params) {return arb::synapse(mech, params);}))
.def(pybind11::init([](const std::string& name, pybind11::kwargs parms) {return arb::synapse(name, util::dict_to_map<double>(parms));}))
.def(pybind11::init([](arb::mechanism_desc mech, pybind11::kwargs params) {return arb::synapse(mech, util::dict_to_map<double>(params));}))
.def_readonly("mech", &arb::synapse::mech, "The underlying mechanism.")
.def("__repr__", [](const arb::synapse& s){return "<arbor.synapse " + mechanism_desc_str(s.mech) + ">";})
.def("__str__", [](const arb::synapse& s){return "<arbor.synapse " + mechanism_desc_str(s.mech) + ">";});
Expand All @@ -537,7 +552,9 @@ void register_cells(pybind11::module& m) {
.def(pybind11::init([](const std::string& name) {return arb::junction(name);}))
.def(pybind11::init([](arb::mechanism_desc mech) {return arb::junction(mech);}))
.def(pybind11::init([](const std::string& name, const std::unordered_map<std::string, double>& params) {return arb::junction(name, params);}))
.def(pybind11::init([](const std::string& name, pybind11::kwargs parms) {return arb::junction(name, util::dict_to_map<double>(parms));}))
.def(pybind11::init([](arb::mechanism_desc mech, const std::unordered_map<std::string, double>& params) {return arb::junction(mech, params);}))
.def(pybind11::init([](arb::mechanism_desc mech, pybind11::kwargs params) {return arb::junction(mech, util::dict_to_map<double>(params));}))
.def_readonly("mech", &arb::junction::mech, "The underlying mechanism.")
.def("__repr__", [](const arb::junction& j){return "<arbor.junction " + mechanism_desc_str(j.mech) + ">";})
.def("__str__", [](const arb::junction& j){return "<arbor.junction " + mechanism_desc_str(j.mech) + ">";});
Expand Down
2 changes: 1 addition & 1 deletion python/example/diffusion.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def event_generators(self, gid):

dec = A.decor()
dec.set_ion("na", int_con=0.0, diff=0.005)
dec.place("(location 0 0.5)", A.synapse("inject/x=na", {"alpha": 200.0}), "Zap")
dec.place("(location 0 0.5)", A.synapse("inject/x=na", alpha=200.0), "Zap")
dec.paint("(all)", A.density("decay/x=na"))
dec.discretization(A.cv_policy("(max-extent 5)"))

Expand Down
4 changes: 2 additions & 2 deletions python/example/network_two_cells_gap_junctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ def cell_description(self, gid):
.set_property(cm=self.cm)
.set_property(rL=self.rL)
# add a gap junction mechanism at the "gj_site" location and label that specific mechanism on that location "gj_label"
.place('"gj_site"', arbor.junction("gj", {"g": self.gj_g}), "gj_label")
.paint('"cell"', arbor.density(f"pas/e={self.Vms[gid]}", {"g": self.g}))
.place('"gj_site"', arbor.junction("gj", g=self.gj_g), "gj_label")
.paint('"cell"', arbor.density(f"pas/e={self.Vms[gid]}", g=self.g))
)

if self.cv_policy_max_extent is not None:
Expand Down
2 changes: 1 addition & 1 deletion python/example/probe_lfpykit.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def make_cable_cell(morphology, clamp_location):
)
# set passive mechanism all over
# passive mech w. leak reversal potential (mV)
.paint("(all)", arbor.density("pas/e=-65", {"g": 0.0001}))
.paint("(all)", arbor.density("pas/e=-65", g=0.0001))
)

# set number of CVs per branch
Expand Down
2 changes: 1 addition & 1 deletion python/example/single_cell_cable.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def cell_description(self, gid):
decor = (
arbor.decor()
.set_property(Vm=self.Vm, cm=self.cm, rL=self.rL)
.paint('"cable"', arbor.density(f"pas/e={self.Vm}", {"g": self.g}))
.paint('"cable"', arbor.density(f"pas/e={self.Vm}", g=self.g))
.place(
'"start"',
arbor.iclamp(
Expand Down
2 changes: 1 addition & 1 deletion python/example/single_cell_detailed.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
# Paint density mechanisms.
decor.paint('"all"', density("pas"))
decor.paint('"custom"', density("hh"))
decor.paint('"dend"', density("Ih", {"gbar": 0.001}))
decor.paint('"dend"', density("Ih", gbar=0.001))
# Place stimuli and detectors.
decor.place('"root"', arbor.iclamp(10, 1, current=2), "iclamp0")
decor.place('"root"', arbor.iclamp(30, 1, current=2), "iclamp1")
Expand Down
2 changes: 1 addition & 1 deletion python/example/single_cell_detailed_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
# Paint density mechanisms.
.paint('"all"', density("pas"))
.paint('"custom"', density("hh"))
.paint('"dend"', density("Ih", {"gbar": 0.001}))
.paint('"dend"', density("Ih", gbar=0.001))
# Place stimuli and detectors.
.place('"root"', arbor.iclamp(10, 1, current=2), "iclamp0")
.place('"root"', arbor.iclamp(30, 1, current=2), "iclamp1")
Expand Down
2 changes: 1 addition & 1 deletion python/example/single_cell_stdp.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def cell_description(self, gid):
.place('"center"', arbor.synapse("expsyn"), "synapse")
.place(
'"center"',
arbor.synapse("expsyn_stdp", {"max_weight": 1.0}),
arbor.synapse("expsyn_stdp", max_weight=1.0),
"stpd_synapse",
)
)
Expand Down
18 changes: 18 additions & 0 deletions python/mechanism.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,24 @@ void register_mechanisms(pybind11::module& m) {
"(as defined in NMODL) is used.\n\n"
"Example overriding a global parameter:\n"
" m = arbor.mechanism('nernst/R=8.3145,F=96485')")
// allow construction of a description with parameters provided in kwargs:
// mech = arbor.mechanism('mech_name', param1=1.2, param2=3.14)
.def(pybind11::init(
[](const char* name, pybind11::kwargs kws) {
arb::mechanism_desc md(name);
auto params = util::dict_to_map<double>(kws);
for (const auto& [k, v]: params) md.set(k, v);
return md;
}),
"name"_a, "The name of the mechanism",
"Example usage setting parameters:\n"
" m = arbor.mechanism('expsyn', tau=1.4})\n"
"will create parameters for the 'expsyn' mechanism, with the provided value\n"
"for 'tau' overrides the default. If a parameter is not set, the default\n"
"(as defined in NMODL) is used.\n\n"
"Example overriding a global parameter:\n"
" m = arbor.mechanism('nernst/R=8.3145,F=96485')")

.def("set",
[](arb::mechanism_desc& md, std::string name, double value) {
md.set(name, value);
Expand Down
2 changes: 1 addition & 1 deletion python/pyarb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ void register_profiler(pybind11::module& m);
void register_recipe(pybind11::module& m);
void register_schedules(pybind11::module& m);
void register_simulation(pybind11::module& m, pyarb_global_ptr);
void register_single_cell(pybind11::module& m);
void register_arborenv(pybind11::module& m);
void register_single_cell(pybind11::module& m);

#ifdef ARB_MPI_ENABLED
void register_mpi(pybind11::module& m);
Expand Down
16 changes: 15 additions & 1 deletion python/single_cell_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "event_generator.hpp"
#include "error.hpp"
#include "strprintf.hpp"
#include "proxy.hpp"

using arb::util::any_cast;

Expand Down Expand Up @@ -236,8 +237,21 @@ void register_single_cell(pybind11::module& m) {

pybind11::class_<single_cell_model> model(m, "single_cell_model",
"Wrapper for simplified description, and execution, of single cell models.");

model
.def(pybind11::init([](const arb::segment_tree& m,
const arb::decor& d,
const label_dict_proxy& l) -> single_cell_model {
return single_cell_model(arb::cable_cell({m}, d, l.dict));
}),
"tree"_a, "decor"_a, "labels"_a=arb::decor{},
"Build single cell model from cable cell components")
.def(pybind11::init([](const arb::morphology& m,
const arb::decor& d,
const label_dict_proxy& l) -> single_cell_model {
return single_cell_model(arb::cable_cell(m, d, l.dict));
}),
"morph"_a, "decor"_a, "labels"_a=arb::decor{},
"Build single cell model from cable cell components")
.def(pybind11::init<arb::cable_cell>(),
"cell"_a, "Initialise a single cell model for a cable cell.")
.def("run",
Expand Down
12 changes: 12 additions & 0 deletions python/util.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <fstream>
#include <string>

#include <pybind11/pybind11.h>

Expand Down Expand Up @@ -46,5 +47,16 @@ std::string read_file_or_buffer(py::object fn) {
}
}

template<typename T>
std::unordered_map<std::string, T> dict_to_map(pybind11::dict d) {
std::unordered_map<std::string, T> result;
for (const auto& [k, v]: d) {
std::string key = k.template cast<std::string>();
T val = v.template cast<T>();
result[key] = val;
}
return result;
}

}
}