diff --git a/src/fvm_multicell.hpp b/src/fvm_multicell.hpp index e7bc12bb3bcb05242438c118249daca3a31527df..67324155ccb32157bec224d50638cf111bd3e265 100644 --- a/src/fvm_multicell.hpp +++ b/src/fvm_multicell.hpp @@ -28,9 +28,9 @@ namespace mc { namespace fvm { template <typename Value, typename Index> -class fvm_cell { +class fvm_multicell { public: - fvm_cell() = default; + fvm_multicell() = default; /// the real number type using value_type = Value; @@ -210,7 +210,7 @@ private: using mechanism_catalogue = nest::mc::mechanisms::catalogue<value_type, size_type>; // perform area and capacitance calculation on initialization - void compute_cv_area_capacitance( + void compute_cv_area_unnormalized_capacitance( std::pair<size_type, size_type> comps, const segment& seg, index_vector &parent); }; @@ -219,7 +219,7 @@ private: //////////////////////////////////////////////////////////////////////////////// template <typename T, typename I> -void fvm_cell<T, I>::compute_cv_area_capacitance( +void fvm_multicell<T, I>::compute_cv_area_unnormalized_capacitance( std::pair<size_type, size_type> comps, const segment& seg, index_vector &parent) @@ -283,10 +283,9 @@ void fvm_cell<T, I>::compute_cv_area_capacitance( } } - template <typename T, typename I> template <typename Cells, typename Detectors, typename Targets, typename Probes> -void fvm_cell<T, I>::initialize( +void fvm_multicell<T, I>::initialize( const Cells& cells, Detectors& detector_handles, Targets& target_handles, @@ -297,6 +296,12 @@ void fvm_cell<T, I>::initialize( using util::make_span; using util::size; + // count total detectors, targets and probes for validation of handle container sizes + size_type detectors_total = 0u; + size_type targets_total = 0u; + size_type probess_total = 0u; + + auto ncell = util::size(cells); auto cell_num_compartments = transform_view(cells, [](const cell& c) { return c.num_compartments(); }); @@ -304,122 +309,62 @@ void fvm_cell<T, I>::initialize( auto cell_comp_part = make_partition(cell_comp_bounds, cell_num_compartments); auto ncomp = cell_comp_part.bounds().second; - index_vector group_parent_index{cell_comp_part.bounds().second, 0}; + // initialize storage from total compartment count + cv_areas_ = vector_type{ncomp, T{0}}; + face_alpha_ = vector_type{ncomp, T{0}}; + cv_capacitance_ = vector_type{ncomp, T{0}}; + current_ = vector_type{ncomp, T{0}}; + voltage_ = vector_type{ncomp, T{0}}; + + index_vector group_parent_index{ncomp, 0}; + + for (size_type i = 0; i<ncell; ++i) { + const auto& c = cells[i]; + auto comps = cell_comp_part[i]; - auto comps = cell_comp_part.begin(); - for (const auto& c: cells) { auto parent_index = c.model().parent_index; - for (auto j: make_span(*comps)) { - group_parent_index[j] = parent_index[j-comps->first]+comps->first; + for (auto k: make_span(comps)) { + group_parent_index[k] = parent_index[k-comps.first]+comps.first; } auto seg_num_compartments = transform_view(c.segments(), [](const segment& s) { return s.num_compartments(); }); + auto nseg = seg_num_compartments.size(); std::vector<cell_lid_type> seg_comp_bounds; - auto seg_comp_part = make_partition(seg_comp_bounds, seg_num_compartments, comps->first); + auto seg_comp_part = make_partition(seg_comp_bounds, seg_num_compartments, comps.first); - auto seg_comps = seg_comp_part.begin(); - for (auto j=0; j<size(seg_comp_part); ++j) { - calculate_cv_area_capacitance( + for (size_type j = 0; j<nseg; ++j) { + compute_cv_area_unnormalized_capacitance(seg_comp_part[j], c.segment(j), group_parent_index); } - ++comps; - } - - + // normalize capacitance across cell + for (auto k: make_span(comps)) { + cv_capacitance_[k] /= cv_areas_[k]; + } + // add mechanisms to look up table for instantiation below + // TODO: move mech_map, syn_map insertions here etc. - const nest::mc::cell& cell = *(std::begin(cells)); - size_type ncomp = cell.num_compartments(); + detectors_total += c.detectors().size(); + targets_total += c.synapses().size(); + probess_total += c.probes.size(); + } - // confirm write-parameters have enough room to store handles - EXPECTS(util::size(detector_handles)==cell.detectors().size()); - EXPECTS(util::size(target_handles)==cell.synapses().size()); - EXPECTS(util::size(probe_handles)==cell.probes().size()); + // confirm write-parameters were appropriately sized + EXPECTS(util::size(detector_handles)==detectors_total); + EXPECTS(util::size(target_handles)==targets_total); + EXPECTS(util::size(probe_handles)==probes_total); - // initialize storage - cv_areas_ = vector_type{ncomp, T{0}}; - face_alpha_ = vector_type{ncomp, T{0}}; - cv_capacitance_ = vector_type{ncomp, T{0}}; - current_ = vector_type{ncomp, T{0}}; - voltage_ = vector_type{ncomp, T{0}}; + // initalize matrix + matrix_ = matrix_type(group_parent_index); using util::left; using util::right; - const auto graph = cell.model(); - matrix_ = matrix_type(graph.parent_index); - - auto parent_index = matrix_.p(); - segment_index_ = graph.segment_index; - - auto seg_idx = 0; - for(auto const& s : cell.segments()) { - if(auto soma = s->as_soma()) { - // assert the assumption that the soma is at 0 - if(seg_idx!=0) { - throw std::domain_error( - "FVM lowering encountered soma with non-zero index" - ); - } - auto area = math::area_sphere(soma->radius()); - cv_areas_[0] += area; - cv_capacitance_[0] += area * soma->mechanism("membrane").get("c_m").value; - } - else if(auto cable = s->as_cable()) { - // loop over each compartment in the cable - // each compartment has the face between two CVs at its centre - // the centers of the CVs are the end points of the compartment - // - // __________________________________ - // | ........ | .cvleft. | cv | - // | ........ L ........ C R - // |__________|__________|__________| - // - // The compartment has end points marked L and R (left and right). - // The left compartment is assumed to be closer to the soma - // (i.e. it follows the minimal degree ordering) - // The face is at the center, marked C. - // The full control volume to the left (marked with .) - auto c_m = cable->mechanism("membrane").get("c_m").value; - auto r_L = cable->mechanism("membrane").get("r_L").value; - for(auto c : cable->compartments()) { - auto i = segment_index_[seg_idx] + c.index; - auto j = parent_index[i]; - - auto radius_center = math::mean(c.radius); - auto area_face = math::area_circle( radius_center ); - face_alpha_[i] = area_face / (c_m * r_L * c.length); - - auto halflen = c.length/2; - - auto al = math::area_frustrum(halflen, left(c.radius), radius_center); - auto ar = math::area_frustrum(halflen, right(c.radius), radius_center); - cv_areas_[j] += al; - cv_areas_[i] += ar; - cv_capacitance_[j] += al * c_m; - cv_capacitance_[i] += ar * c_m; - } - } - else { - throw std::domain_error("FVM lowering encountered unsuported segment type"); - } - ++seg_idx; - } - - // normalize the capacitance by cv_area - for(auto i=0u; i<size(); ++i) { - cv_capacitance_[i] /= cv_areas_[i]; - } - - ///////////////////////////////////////////// - // create mechanisms - ///////////////////////////////////////////// - - // FIXME : candidate for a private member function + // create mechanisms // for each mechanism in the cell record the indexes of the segments that // contain the mechanism