diff --git a/arbor/cable_cell.cpp b/arbor/cable_cell.cpp index 21dd4e5392..b956b2db9c 100644 --- a/arbor/cable_cell.cpp +++ b/arbor/cable_cell.cpp @@ -91,7 +91,7 @@ struct cable_cell_impl { dictionary(labels), decorations(decorations) { - init(decorations); + init(); } cable_cell_impl(): cable_cell_impl({},{},{}) {} @@ -100,7 +100,7 @@ struct cable_cell_impl { cable_cell_impl(cable_cell_impl&& other) = default; - void init(const decor&); + void init(); template mlocation_map& get_location_map(const T&) { @@ -116,13 +116,13 @@ struct cable_cell_impl { } template - void place(const locset& ls, const Item& item, const hash_type& label) { + void place(const mlocation_list& locs, const Item& item, const hash_type& label) { auto& mm = get_location_map(item); cell_lid_type& lid = placed_count.get(); cell_lid_type first = lid; - for (auto l: thingify(ls, provider)) { - placed p{l, lid++, item}; + for (const auto& loc: locs) { + placed p{loc, lid++, item}; mm.push_back(p); } auto range = lid_range(first, lid); @@ -160,42 +160,36 @@ struct cable_cell_impl { return region_map.get()[init.ion]; } - void paint(const region& reg, const density& prop) { - this->paint(reg, scaled_mechanism(prop)); + void paint(const mextent& cables, const std::string& str, const density& prop) { + this->paint(cables, str, scaled_mechanism(prop)); } - void paint(const region& reg, const scaled_mechanism& prop) { + void paint(const mextent& cables, const std::string& str, const scaled_mechanism& prop) { std::unordered_map im; - for (const auto& [fst, snd]: prop.scale_expr) { - im.insert_or_assign(fst, thingify(snd, provider)); + for (const auto& [label, iex]: prop.scale_expr) { + im.insert_or_assign(label, thingify(iex, provider)); } auto& mm = get_region_map(prop.t_mech); - const auto& cables = thingify(reg, provider); - for (const auto& c: cables) { + for (const auto& cable: cables) { // Skip zero-length cables in extent: - if (c.prox_pos == c.dist_pos) continue; - - if (!mm.insert(c, {prop.t_mech, im})) { - std::stringstream rg; rg << reg; + if (cable.prox_pos == cable.dist_pos) continue; + if (!mm.insert(cable, {prop.t_mech, im})) { throw cable_cell_error(util::pprintf("Setting mechanism '{}' on region '{}' overpaints at cable {}", - prop.t_mech.mech.name(), rg.str(), c)); + prop.t_mech.mech.name(), str, cable)); } } } template - void paint(const region& reg, const TaggedMech& prop) { - mextent cables = thingify(reg, provider); + void paint(const mextent& cables, const std::string& str, const TaggedMech& prop) { auto& mm = get_region_map(prop); - - for (auto c: cables) { + for (const auto& cable: cables) { // Skip zero-length cables in extent: - if (c.prox_pos==c.dist_pos) continue; - - if (!mm.insert(c, prop)) { - std::stringstream rg; rg << reg; - throw cable_cell_error(util::pprintf("Setting property '{}' on region '{}' overpaints at '{}'", show(prop), rg.str(), c)); + if (cable.prox_pos == cable.dist_pos) continue; + if (!mm.insert(cable, prop)) { + throw cable_cell_error(util::pprintf("Setting property '{}' on region '{}' overpaints at cable {}", + show(prop), str, cable)); } } } @@ -214,16 +208,27 @@ impl_ptr make_impl(cable_cell_impl* c) { return impl_ptr(c, [](cable_cell_impl* p){delete p;}); } -void cable_cell_impl::init(const decor& d) { - for (const auto& p: d.paintings()) { - auto& where = p.first; - std::visit([this, &where] (auto&& what) {this->paint(where, what);}, p.second); +void cable_cell_impl::init() { + // Try to cache with a lookback of one since most models paint/place one + // region/locset in direct succession. We also key on the stringy view of + // expressions since in general equality is undecidable. + std::string last_label = ""; + mextent last_region; + mlocation_list last_locset; + for (const auto& [where, what]: decorations.paintings()) { + if (auto region = util::to_string(where); last_label != region) { + last_label = std::move(region); + last_region = thingify(where, provider); + } + std::visit([this, &last_region, &last_label] (auto&& what) { this->paint(last_region, last_label, what); }, what); } - for (const auto& p: d.placements()) { - auto& where = std::get<0>(p); - auto& label = std::get<2>(p); - std::visit([this, &where, &label] (auto&& what) {return this->place(where, what, label); }, - std::get<1>(p)); + for (const auto& [where, what, label]: decorations.placements()) { + if (auto locset = util::to_string(where); last_label != locset) { + last_label = std::move(locset); + last_locset = thingify(where, provider); + } + std::visit([this, &last_locset, &label=label] (auto&& what) { return this->place(last_locset, what, label); }, + what); } } diff --git a/example/busyring/ring.cpp b/example/busyring/ring.cpp index 1d53fceb38..0516bdfc9b 100644 --- a/example/busyring/ring.cpp +++ b/example/busyring/ring.cpp @@ -398,9 +398,6 @@ arb::cable_cell complex_cell(arb::cell_gid_type gid, const cell_parameters& para decor.paint(soma, arb::axial_resistivity{133.577*U::Ohm*U::cm}); decor.paint(soma, arb::membrane_capacitance{4.21567e-2*U::F/U::m2}); - decor.paint(dend, arb::axial_resistivity{68.355*U::Ohm*U::cm}); - decor.paint(dend, arb::membrane_capacitance{2.11248e-2*U::F/U::m2}); - decor.paint(soma, arb::density("pas/e=-76.4024", {{"g", 0.000119174}})); decor.paint(soma, arb::density("NaV", {{"gbar", 0.0499779}})); decor.paint(soma, arb::density("SK", {{"gbar", 0.000733676}})); @@ -410,18 +407,19 @@ arb::cable_cell complex_cell(arb::cell_gid_type gid, const cell_parameters& para decor.paint(soma, arb::density("CaDynamics", {{"gamma", 0.0177038}, {"decay", 42.2507}})); decor.paint(soma, arb::density("Ih", {{"gbar", 1.07608e-07}})); + decor.paint(dend, arb::axial_resistivity{68.355*U::Ohm*U::cm}); + decor.paint(dend, arb::membrane_capacitance{2.11248e-2*U::F/U::m2}); + decor.paint(dend, arb::density("pas/e=-88.2554", {{"g", 9.57001e-05}})); decor.paint(dend, arb::density("NaV", {{"gbar", 0.0472215}})); decor.paint(dend, arb::density("Kv3_1", {{"gbar", 0.186859}})); decor.paint(dend, arb::density("Im_v2", {{"gbar", 0.00132163}})); decor.paint(dend, arb::density("Ih", {{"gbar", 9.18815e-06}})); + decor.place(cntr, arb::threshold_detector{-20.0*U::mV}, "d"); decor.place(cntr, arb::synapse("expsyn"), "p"); - if (params.synapses>1) { - decor.place(syns, arb::synapse("expsyn"), "s"); - } - decor.place(cntr, arb::threshold_detector{-20.0*U::mV}, "d"); + if (params.synapses>1) decor.place(syns, arb::synapse("expsyn"), "s"); decor.set_default(arb::cv_policy_every_segment());