diff --git a/arbor/arbexcept.cpp b/arbor/arbexcept.cpp index 520883fe6d..00f0d8632a 100644 --- a/arbor/arbexcept.cpp +++ b/arbor/arbexcept.cpp @@ -44,9 +44,9 @@ zero_thread_requested_error::zero_thread_requested_error(unsigned nbt): nbt(nbt) {} -bad_probe_id::bad_probe_id(cell_member_type probe_id): - arbor_exception(pprintf("bad probe id {}", probe_id)), - probe_id(probe_id) +bad_probeset_id::bad_probeset_id(cell_member_type probeset_id): + arbor_exception(pprintf("bad probe id {}", probeset_id)), + probeset_id(probeset_id) {} gj_unsupported_lid_selection_policy::gj_unsupported_lid_selection_policy(cell_gid_type gid, cell_tag_type label): diff --git a/arbor/benchmark_cell_group.cpp b/arbor/benchmark_cell_group.cpp index 8abe81c2ba..1819edefed 100644 --- a/arbor/benchmark_cell_group.cpp +++ b/arbor/benchmark_cell_group.cpp @@ -95,7 +95,7 @@ void benchmark_cell_group::clear_spikes() { } void benchmark_cell_group::add_sampler(sampler_association_handle h, - cell_member_predicate probe_ids, + cell_member_predicate probeset_ids, schedule sched, sampler_function fn, sampling_policy policy) {} diff --git a/arbor/benchmark_cell_group.hpp b/arbor/benchmark_cell_group.hpp index ea64cbcedd..c106836a16 100644 --- a/arbor/benchmark_cell_group.hpp +++ b/arbor/benchmark_cell_group.hpp @@ -28,7 +28,7 @@ class benchmark_cell_group: public cell_group { void clear_spikes() override; - void add_sampler(sampler_association_handle h, cell_member_predicate probe_ids, schedule sched, sampler_function fn, sampling_policy policy) override; + void add_sampler(sampler_association_handle h, cell_member_predicate probeset_ids, schedule sched, sampler_function fn, sampling_policy policy) override; void remove_sampler(sampler_association_handle h) override {} diff --git a/arbor/fvm_lowered_cell.hpp b/arbor/fvm_lowered_cell.hpp index a3bff57d86..0316907b59 100644 --- a/arbor/fvm_lowered_cell.hpp +++ b/arbor/fvm_lowered_cell.hpp @@ -188,9 +188,9 @@ struct probe_association_map { return data.size(); } - // Return range of fvm_probe_data values associated with probe_id. - auto data_on(cell_member_type probe_id) const { - return util::transform_view(util::make_range(data.equal_range(probe_id)), util::second); + // Return range of fvm_probe_data values associated with probeset_id. + auto data_on(cell_member_type probeset_id) const { + return util::transform_view(util::make_range(data.equal_range(probeset_id)), util::second); } }; diff --git a/arbor/fvm_lowered_cell_impl.hpp b/arbor/fvm_lowered_cell_impl.hpp index 8621ef7eec..accfcb1564 100644 --- a/arbor/fvm_lowered_cell_impl.hpp +++ b/arbor/fvm_lowered_cell_impl.hpp @@ -632,11 +632,11 @@ fvm_initialization_data fvm_lowered_cell_impl::initialize( D, mech_data, fvm_info.target_handles, mechptr_by_name); if (!probe_data.empty()) { - cell_member_type probe_id{gid, i}; - fvm_info.probe_map.tag[probe_id] = pi.tag; + cell_member_type probeset_id{gid, i}; + fvm_info.probe_map.tag[probeset_id] = pi.tag; for (auto& data: probe_data) { - fvm_info.probe_map.data.insert({probe_id, std::move(data)}); + fvm_info.probe_map.data.insert({probeset_id, std::move(data)}); } } } diff --git a/arbor/include/arbor/arbexcept.hpp b/arbor/include/arbor/arbexcept.hpp index 1a5679a1f0..4acfb6a7bb 100644 --- a/arbor/include/arbor/arbexcept.hpp +++ b/arbor/include/arbor/arbexcept.hpp @@ -67,9 +67,9 @@ struct ARB_SYMBOL_VISIBLE bad_global_property: arbor_exception { cell_kind kind; }; -struct ARB_SYMBOL_VISIBLE bad_probe_id: arbor_exception { - explicit bad_probe_id(cell_member_type id); - cell_member_type probe_id; +struct ARB_SYMBOL_VISIBLE bad_probeset_id: arbor_exception { + explicit bad_probeset_id(cell_member_type id); + cell_member_type probeset_id; }; struct ARB_SYMBOL_VISIBLE gj_kind_mismatch: arbor_exception { diff --git a/arbor/include/arbor/simulation.hpp b/arbor/include/arbor/simulation.hpp index c2dd5311ec..205c8f940f 100644 --- a/arbor/include/arbor/simulation.hpp +++ b/arbor/include/arbor/simulation.hpp @@ -41,7 +41,7 @@ class ARB_ARBOR_API simulation { // Note: sampler functions may be invoked from a different thread than that // which called the `run` method. - sampler_association_handle add_sampler(cell_member_predicate probe_ids, + sampler_association_handle add_sampler(cell_member_predicate probeset_ids, schedule sched, sampler_function f, sampling_policy policy = sampling_policy::lax); void remove_sampler(sampler_association_handle); @@ -50,7 +50,7 @@ class ARB_ARBOR_API simulation { // Return probe metadata, one entry per probe associated with supplied probe id, // or an empty vector if no local match for probe id. - std::vector get_probe_metadata(cell_member_type probe_id) const; + std::vector get_probe_metadata(cell_member_type probeset_id) const; std::size_t num_spikes() const; diff --git a/arbor/lif_cell_group.cpp b/arbor/lif_cell_group.cpp index e7d24e955d..0fa71789ec 100644 --- a/arbor/lif_cell_group.cpp +++ b/arbor/lif_cell_group.cpp @@ -59,7 +59,7 @@ void lif_cell_group::clear_spikes() { } // TODO: implement sampler -void lif_cell_group::add_sampler(sampler_association_handle h, cell_member_predicate probe_ids, +void lif_cell_group::add_sampler(sampler_association_handle h, cell_member_predicate probeset_ids, schedule sched, sampler_function fn, sampling_policy policy) {} void lif_cell_group::remove_sampler(sampler_association_handle h) {} void lif_cell_group::remove_all_samplers() {} diff --git a/arbor/mc_cell_group.cpp b/arbor/mc_cell_group.cpp index 4507afae38..0510c60f9b 100644 --- a/arbor/mc_cell_group.cpp +++ b/arbor/mc_cell_group.cpp @@ -94,7 +94,7 @@ void mc_cell_group::set_binning_policy(binning_kind policy, time_type bin_interv struct sampler_call_info { sampler_function sampler; - cell_member_type probe_id; + cell_member_type probeset_id; probe_tag tag; unsigned index; const fvm_probe_data* pdata_ptr; @@ -151,7 +151,7 @@ void run_samples( sample_records.push_back(sample_record{time_type(raw_times[i]), &raw_samples[i]}); } - sc.sampler({sc.probe_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); + sc.sampler({sc.probeset_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); } void run_samples( @@ -181,7 +181,7 @@ void run_samples( sample_records.push_back(sample_record{time_type(raw_times[offset]), &ctmp[j]}); } - sc.sampler({sc.probe_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); + sc.sampler({sc.probeset_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); } void run_samples( @@ -211,7 +211,7 @@ void run_samples( sample_records.push_back(sample_record{time_type(raw_times[offset]), &csample_ranges[j]}); } - sc.sampler({sc.probe_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); + sc.sampler({sc.probeset_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); } void run_samples( @@ -254,7 +254,7 @@ void run_samples( sample_records.push_back(sample_record{time_type(raw_times[offset]), &csample_ranges[j]}); } - sc.sampler({sc.probe_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); + sc.sampler({sc.probeset_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); } void run_samples( @@ -301,7 +301,7 @@ void run_samples( sample_records.push_back(sample_record{time_type(raw_times[offset]), &csample_ranges[j]}); } - sc.sampler({sc.probe_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); + sc.sampler({sc.probeset_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); } void run_samples( @@ -375,7 +375,7 @@ void run_samples( sample_records.push_back(sample_record{time_type(raw_times[offset]), &csample_ranges[j]}); } - sc.sampler({sc.probe_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); + sc.sampler({sc.probeset_id, sc.tag, sc.index, p.get_metadata_ptr()}, n_sample, sample_records.data()); } // Generic run_samples dispatches on probe info variant type. @@ -476,7 +476,7 @@ void mc_cell_group::advance(epoch ep, time_type dt, const event_lane_subrange& e sample_size_type n_times = sample_times.size(); max_samples_per_call = std::max(max_samples_per_call, n_times); - for (cell_member_type pid: sa.probe_ids) { + for (cell_member_type pid: sa.probeset_ids) { auto cell_index = gid_index_map_.at(pid.gid); probe_tag tag = probe_map_.tag.at(pid); @@ -555,13 +555,13 @@ void mc_cell_group::advance(epoch ep, time_type dt, const event_lane_subrange& e } } -void mc_cell_group::add_sampler(sampler_association_handle h, cell_member_predicate probe_ids, +void mc_cell_group::add_sampler(sampler_association_handle h, cell_member_predicate probeset_ids, schedule sched, sampler_function fn, sampling_policy policy) { std::lock_guard guard(sampler_mex_); std::vector probeset = - util::assign_from(util::filter(util::keys(probe_map_.tag), probe_ids)); + util::assign_from(util::filter(util::keys(probe_map_.tag), probeset_ids)); if (!probeset.empty()) { auto result = sampler_map_.insert({h, sampler_association{std::move(sched), std::move(fn), std::move(probeset), policy}}); @@ -579,21 +579,21 @@ void mc_cell_group::remove_all_samplers() { sampler_map_.clear(); } -std::vector mc_cell_group::get_probe_metadata(cell_member_type probe_id) const { +std::vector mc_cell_group::get_probe_metadata(cell_member_type probeset_id) const { // Probe associations are fixed after construction, so we do not need to grab the mutex. - std::optional maybe_tag = util::value_by_key(probe_map_.tag, probe_id); + std::optional maybe_tag = util::value_by_key(probe_map_.tag, probeset_id); if (!maybe_tag) { return {}; } - auto data = probe_map_.data_on(probe_id); + auto data = probe_map_.data_on(probeset_id); std::vector result; result.reserve(data.size()); unsigned index = 0; for (const fvm_probe_data& item: data) { - result.push_back(probe_metadata{probe_id, *maybe_tag, index++, item.get_metadata_ptr()}); + result.push_back(probe_metadata{probeset_id, *maybe_tag, index++, item.get_metadata_ptr()}); } return result; diff --git a/arbor/mc_cell_group.hpp b/arbor/mc_cell_group.hpp index 3640c8cf24..1379dae2bd 100644 --- a/arbor/mc_cell_group.hpp +++ b/arbor/mc_cell_group.hpp @@ -52,14 +52,14 @@ class ARB_ARBOR_API mc_cell_group: public cell_group { spikes_.clear(); } - void add_sampler(sampler_association_handle h, cell_member_predicate probe_ids, + void add_sampler(sampler_association_handle h, cell_member_predicate probeset_ids, schedule sched, sampler_function fn, sampling_policy policy) override; void remove_sampler(sampler_association_handle h) override; void remove_all_samplers() override; - std::vector get_probe_metadata(cell_member_type probe_id) const override; + std::vector get_probe_metadata(cell_member_type probeset_id) const override; private: // List of the gids of the cells in the group. diff --git a/arbor/sampler_map.hpp b/arbor/sampler_map.hpp index 495a676d4b..e1781ee7ab 100644 --- a/arbor/sampler_map.hpp +++ b/arbor/sampler_map.hpp @@ -18,7 +18,7 @@ namespace arb { struct sampler_association { schedule sched; sampler_function sampler; - std::vector probe_ids; + std::vector probeset_ids; sampling_policy policy; }; diff --git a/arbor/simulation.cpp b/arbor/simulation.cpp index f604e19bc5..562db16266 100644 --- a/arbor/simulation.cpp +++ b/arbor/simulation.cpp @@ -96,7 +96,7 @@ class simulation_state { time_type run(time_type tfinal, time_type dt); - sampler_association_handle add_sampler(cell_member_predicate probe_ids, + sampler_association_handle add_sampler(cell_member_predicate probeset_ids, schedule sched, sampler_function f, sampling_policy policy = sampling_policy::lax); void remove_sampler(sampler_association_handle); @@ -449,7 +449,7 @@ time_type simulation_state::run(time_type tfinal, time_type dt) { } sampler_association_handle simulation_state::add_sampler( - cell_member_predicate probe_ids, + cell_member_predicate probeset_ids, schedule sched, sampler_function f, sampling_policy policy) @@ -457,7 +457,7 @@ sampler_association_handle simulation_state::add_sampler( sampler_association_handle h = sassoc_handles_.acquire(); foreach_group( - [&](cell_group_ptr& group) { group->add_sampler(h, probe_ids, sched, f, policy); }); + [&](cell_group_ptr& group) { group->add_sampler(h, probeset_ids, sched, f, policy); }); return h; } @@ -476,9 +476,9 @@ void simulation_state::remove_all_samplers() { sassoc_handles_.clear(); } -std::vector simulation_state::get_probe_metadata(cell_member_type probe_id) const { - if (auto linfo = util::value_by_key(gid_to_local_, probe_id.gid)) { - return cell_groups_.at(linfo->group_index)->get_probe_metadata(probe_id); +std::vector simulation_state::get_probe_metadata(cell_member_type probeset_id) const { + if (auto linfo = util::value_by_key(gid_to_local_, probeset_id.gid)) { + return cell_groups_.at(linfo->group_index)->get_probe_metadata(probeset_id); } else { return {}; @@ -528,12 +528,12 @@ time_type simulation::run(time_type tfinal, time_type dt) { } sampler_association_handle simulation::add_sampler( - cell_member_predicate probe_ids, + cell_member_predicate probeset_ids, schedule sched, sampler_function f, sampling_policy policy) { - return impl_->add_sampler(std::move(probe_ids), std::move(sched), std::move(f), policy); + return impl_->add_sampler(std::move(probeset_ids), std::move(sched), std::move(f), policy); } void simulation::remove_sampler(sampler_association_handle h) { @@ -544,8 +544,8 @@ void simulation::remove_all_samplers() { impl_->remove_all_samplers(); } -std::vector simulation::get_probe_metadata(cell_member_type probe_id) const { - return impl_->get_probe_metadata(probe_id); +std::vector simulation::get_probe_metadata(cell_member_type probeset_id) const { + return impl_->get_probe_metadata(probeset_id); } std::size_t simulation::num_spikes() const { diff --git a/arbor/spike_source_cell_group.hpp b/arbor/spike_source_cell_group.hpp index 4a54237e6c..aefe4a0d50 100644 --- a/arbor/spike_source_cell_group.hpp +++ b/arbor/spike_source_cell_group.hpp @@ -31,7 +31,7 @@ class ARB_ARBOR_API spike_source_cell_group: public cell_group { void clear_spikes() override; - void add_sampler(sampler_association_handle h, cell_member_predicate probe_ids, schedule sched, sampler_function fn, sampling_policy policy) override; + void add_sampler(sampler_association_handle h, cell_member_predicate probeset_ids, schedule sched, sampler_function fn, sampling_policy policy) override; void remove_sampler(sampler_association_handle h) override {} diff --git a/doc/concepts/probe_sample.rst b/doc/concepts/probe_sample.rst index 2dd2632556..6ea48b0d53 100644 --- a/doc/concepts/probe_sample.rst +++ b/doc/concepts/probe_sample.rst @@ -3,8 +3,61 @@ Cable cell probing and sampling =============================== -.. TODO:: - WIP! +Definitions +*********** + +.. glossary:: + + probe + A measurement that can be performed on a cell. Each cell kind will have its own sorts of probe. + Cable cells (:py:attr:`arbor.cable_probe`) allow the monitoring of membrane voltage, total membrane + current, mechanism state, and a number of other quantities, measured either over the whole cell, + or at specific sites (see :ref:`pycablecell-probesample`). + + vector probe + Certain probes work over a :term:`region` rather than a :term:`locset`. This means that, depending + settings such as :term:`cv policy`, data is sampled as a function of distance, yielding multiple data points. + Such probes are distinguished from regular probes as "vector probes". + + probeset + A set of probes. Probes are placed on locsets, and therefore may describe more than one probe. + + probeset address + Probesets are located at a probeset address, and the collection of probeset addresses for a given cell is + provided by the :py:class:`recipe` object. One address may correspond to more than one probe: + as an example, a request for membrane voltage on a cable cell at sites specified by a locset + expression will generate one probe for each site in that locset expression. + + See :ref:`pycablecell-probesample` for a list of objects that return a probeset address. + + probeset id + A designator for a probeset as specified by a recipe. The *probeset id* is a + :py:class:`cell_member` referring to a specific cell by gid, and the index into the list of + probeset addresses returned by the recipe for that gid. + + metadata + Each probe has associated metadata describing, for example, the location on a cell where the + measurement is being taken, or other such identifying information. Metadata for the probes + associated with a :term:`probeset id` can be retrieved from the simulation object, and is also provided + along with any recorded samples. + + sampler + sample_recorder + A sampler is something that receives :term:`probeset` data. It amounts to setting a particular probeset to a + particular measuring schedule, and then having a :term:`handle` with which to access the recorded probeset data later on. + + sample + A record of data corresponding to the value at a specific *probe* at a specific time. + + handle + A handle for reaching sampling data associated to a sampler, which is associated to a probeset. + Setting a sampler (through :py:func:`simulation.sample`) returns handles. Sampled data can be retrieved + by passing the handle associated to a sampler (associated to a probeset) to :py:func:`simulation.samples`. + + schedule + An object representing a series of monotonically increasing points in time, used for determining + sample times (see :ref:`pyrecipe`). + API --- diff --git a/doc/cpp/probe_sample.rst b/doc/cpp/probe_sample.rst index 76e16bfac2..cb7b08cfbb 100644 --- a/doc/cpp/probe_sample.rst +++ b/doc/cpp/probe_sample.rst @@ -8,11 +8,10 @@ Cable cell probing and sampling Cable cell probes ----------------- -Various properties of a a cable cell can be sampled via one of the cable cell -specific probe address described below. They fall into two classes: scalar +Various properties of a cable cell can be sampled. They fall into two classes: scalar probes are associated with a single real value, such as a membrane voltage or mechanism state value at a particular location; vector probes return -multiple values corresponding to a quantity sampled over a whole cell. +multiple values corresponding to a quantity sampled at a set of points on the cell. The sample data associated with a cable cell probe will either be a ``double`` for scalar probes, or a ``cable_sample_range`` describing a half-open range @@ -56,7 +55,7 @@ Mechanism state queries however will throw a ``cable_cell_error`` exception at simulation initialization if the requested state variable does not exist on the mechanism. -Cable cell probe addresses that are described by a ``locset`` may generate more +Cable cell probeset addresses that are described by a ``locset`` may generate more than one concrete probe: there will be one per location in the locset that is satisfiable. Sampler callback functions can distinguish between different probes with the same address and id by examining their index and/or @@ -277,7 +276,7 @@ If the mechanism is not defined at a particular site, that site is ignored. * Sample value: ``double``. State variable value. -* Metadata: ``mlocation``. Location as given in the probe address. +* Metadata: ``mlocation``. Location as given in the probeset address. .. code:: @@ -387,16 +386,17 @@ as a way of passing additional metadata about a probe to any sampler that polls it, with a view to samplers that handle multiple probes, possibly with different value types. -Probe addresses are decoupled from the cell descriptions themselves — +Probeset addresses are decoupled from the cell descriptions themselves — this allows a recipe implementation to construct probes independently of the cells themselves. It is the responsibility of a cell group implementation -to parse the probe address objects wrapped in the ``any address`` field. +to parse the probeset address objects wrapped in the ``any address`` field, +thus the order of probes returned is important. The _k_th element of the vector returned by ``get_probes(gid)`` is identified with a probe-id: ``cell_member_type{gid, k}``. -One probe address may describe more than one concrete probe, depending -upon the interpretation of the probe address by the cell group. In this +One probeset address may describe more than one concrete probe, depending +upon the interpretation of the probeset address by the cell group. In this instance, each of the concrete probes will be associated with the same probe-id. Samplers can distinguish between different probes with the same id by their probe index (see below). @@ -413,9 +413,9 @@ will be passed to a sampler function or function object: .. code-block:: cpp struct probe_metadata { - cell_member_type id; // probe id + cell_member_type id; // probeset id probe_tag tag; // probe tag associated with id - unsigned index; // index of probe source within those supplied by probe id + unsigned index; // index of probe source within those supplied by probeset id util::any_ptr meta; // probe-specific metadata }; @@ -425,7 +425,7 @@ will be passed to a sampler function or function object: where the parameters are respectively the probe metadata, the number of samples, and finally a pointer to the sequence of sample records. -The ``probe_id``, identifies the probe by its probe-id (see above). +The ``probeset_id``, identifies the probe by its probe-id (see above). The ``probe_tag`` in the metadata is the key given in the ``probe_info`` returned by the recipe. @@ -433,8 +433,8 @@ returned by the recipe. The ``index`` identifies which of the possibly multiple probes associated with the probe-id is the source of the samples. -The ``any_ptr`` value iin the metadata points to const probe-specific metadata; -the type of the metadata will depend upon the probe address specified in the +The ``any_ptr`` value in the metadata points to const probe-specific metadata; +the type of the metadata will depend upon the probeset address specified in the ``probe_info`` provided by the recipe. One ``sample_record`` struct contains one sample of the probe data at a @@ -452,12 +452,12 @@ given simulation time point: The ``data`` field points to the sample data, wrapped in ``any_ptr`` for type-checked access. The exact representation will depend on the nature of the object that is being probed, but it should depend only on the cell type and -probe address. +probeset address. The data pointed to by ``data``, and the sample records themselves, are only guaranteed to be valid for the duration of the call to the sampler function. A simple sampler implementation for ``double`` data, assuming -one probe per probe id, might be as follows: +one probe per probeset id, might be as follows: .. container:: example-code @@ -499,7 +499,7 @@ Polling rates, policies and sampler functions are set through the using cell_member_predicate = std::function; sampler_association_handle simulation::add_sampler( - cell_member_predicate probe_ids, + cell_member_predicate probeset_ids, schedule sched, sampler_function fn, sampling_policy policy = sampling_policy::lax); @@ -511,7 +511,7 @@ Polling rates, policies and sampler functions are set through the Multiple samplers can then be associated with the same probe locations. The handle returned is only used for managing the lifetime of the association. The ``cell_member_predicate`` parameter defines the -set of probe ids in terms of a membership test. +set of probeset ids in terms of a membership test. Two helper functions are provided for making ``cell_member_predicate`` objects: @@ -519,10 +519,10 @@ Two helper functions are provided for making ``cell_member_predicate`` objects: .. code-block:: cpp - // Match all probe ids. + // Match all probeset ids. cell_member_predicate all_probes = [](cell_member_type pid) { return true; }; - // Match just one probe id. + // Match just one probeset id. cell_member_predicate one_probe(cell_member_type pid) { return [pid](cell_member_type x) { return pid==x; }; } @@ -538,21 +538,21 @@ implemented in the future, but cell groups are in general not required to support any policy other than ``lax``. The simulation object will pass on the sampler setting request to the cell -group that owns the given probe id. The ``cell_group`` interface will be +group that owns the given probeset id. The ``cell_group`` interface will be correspondingly extended: .. container:: api-code .. code-block:: cpp - void cell_group::add_sampler(sampler_association_handle h, cell_member_predicate probe_ids, sample_schedule sched, sampler_function fn, sampling_policy policy); + void cell_group::add_sampler(sampler_association_handle h, cell_member_predicate probeset_ids, sample_schedule sched, sampler_function fn, sampling_policy policy); void cell_group::remove_sampler(sampler_association_handle); void cell_group::remove_all_samplers(); Cell groups will invoke the corresponding sampler function directly, and -may aggregate multiple samples with the same probe id in one call to the +may aggregate multiple samples with the same probeset id in one call to the sampler. Calls to the sampler are synchronous, in the sense that processing of the cell group state does not proceed while the sampler function is being executed, but the times of the samples given to the diff --git a/doc/cpp/simulation.rst b/doc/cpp/simulation.rst index 929ed27689..9332e20056 100644 --- a/doc/cpp/simulation.rst +++ b/doc/cpp/simulation.rst @@ -105,7 +105,7 @@ Class documentation **I/O:** .. cpp:function:: sampler_association_handle add_sampler(\ - cell_member_predicate probe_ids,\ + cell_member_predicate probeset_ids,\ schedule sched,\ sampler_function f,\ sampling_policy policy = sampling_policy::lax) diff --git a/doc/python/cell.rst b/doc/python/cell.rst index 6ea77ad989..b932bc823a 100644 --- a/doc/python/cell.rst +++ b/doc/python/cell.rst @@ -97,6 +97,7 @@ The types defined below are used as identifiers for cells and members of cell-lo # Create the global label referring to the group of items labeled "syn0" # on cell 5 global_label = arbor.cell_global_label(5, local_label) + .. class:: cell_member .. function:: cell_member(gid, index) @@ -109,9 +110,8 @@ The types defined below are used as identifiers for cells and members of cell-lo * be associated with a unique cell, identified by the member :attr:`gid`; * identify an item within a cell-local collection by the member :attr:`index`. - An example is uniquely identifying a probe description in the model. - Each probe description has a cell (with :attr:`gid`), and an :attr:`index` into - the set of probe descriptions on the cell. + An example is uniquely identifying a probeset on the model: + ``arbor.cell_member(12, 3)`` can be used to identify the probeset with :attr:`index` 3 on the cell with :attr:`gid` 12. Lexicographically ordered by :attr:`gid`, then :attr:`index`. diff --git a/doc/python/probe_sample-diag.dia b/doc/python/probe_sample-diag.dia new file mode 100644 index 0000000000..4274a7ebd3 Binary files /dev/null and b/doc/python/probe_sample-diag.dia differ diff --git a/doc/python/probe_sample-diag.svg b/doc/python/probe_sample-diag.svg new file mode 100644 index 0000000000..d6d9108fe4 --- /dev/null +++ b/doc/python/probe_sample-diag.svg @@ -0,0 +1,160 @@ + + + + + + + + probeset + + + + + + + + + + + + + + + + + + + + + + + + handle + + + + + + probe 1 + + + + + + probe 2 + + + + + + probe ... + + + + + + + + + + + + + + + + + + meta (str) + + + + + + data (ndarray) + + + + + + + + + + + + + + [0]: time, value + + + + + + [1]: time, value + + + + + + [...]: time, value + + + + + + + + + + + + + + + + + + + + + location expression for probe 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/python/probe_sample.rst b/doc/python/probe_sample.rst index 41374bd15b..3ac24a0ccd 100644 --- a/doc/python/probe_sample.rst +++ b/doc/python/probe_sample.rst @@ -5,23 +5,144 @@ Cable cell probing and sampling .. module:: arbor -Cable cell probe addresses are defined analogously to their counterparts in -the C++ API (see :ref:`cablecell-probes` for details). Sample data recorded -by the Arbor simulation object is returned in the form of a NumPy array, -with the first column holding sample times, and subsequent columns holding -the corresponding scalar- or vector-valued sample. - -Location expressions will be realised as zero or more specific sites on -a cell; probe addresses defined over location expressions will describe zero, +.. figure:: probe_sample-diag.svg + :width: 800 + :align: center + + A schematic view of how :term:`handles ` let you access sampled data measured at a :term:`probeset`. + A probeset is a probe placed on a locset (which may describe more than one point). + When setting a probe on a locset a :term:`sampler` is created. + When this sampler is set to sampling (at a certain schedule), a handle is returned. + This figure demonstrates how sampling data can be accessed through the handle associated to the probeset. + See below for a possible result for ``data``. + +.. code-block:: python + + print(data) # The probe data printed, as found in single_cell_recipe.py + [[ 0.00000000e+00 -4.00000000e+01] + [ 1.00000000e-01 -5.40211646e+01] + [ 2.00000000e-01 -6.19670534e+01] + ... + [ 2.99000000e+01 -6.44564354e+01]] + +Sample data recorded by the Arbor simulation object is returned in the form +of a NumPy array, with the first column holding sample times, and subsequent +columns holding the corresponding scalar- or vector-valued sample. + +Probesets are defined over a location expression and will describe zero, one, or more probes, one per site. They are evaluated in the context of the cell on which the probe is attached. +:term:`Vector probes ` are a kind of probes that samples over a region, rather than a :term:`locset`. +This means that they may output more than a single data point per timestamp. The layout of the outputs as returned +by :func:`~arbor.simulation.samples` is slightly different, but contains the same sort of information as regular +:term:`probesets `. + +.. figure:: probe_sample_vector-diag.svg + :width: 800 + :align: center + + The structure of the data returned is slightly different when a :term:`vector probe` is sampled. + The same kind of information is included however. Instead of returning a list per :term:`probe` in a :term:`probeset`, + the data and metadata now have an extra dimension to cover for the multitude of subregions. + + Each of the functions described below generates an opaque :class:`probe` object for use in the recipe :py:func:`recipe.probes` method. More information on probes, probe metadata, and sampling can be found in the documentation for the class :class:`simulation`. +.. note:: + + Cable cell probesets are defined analogously to their counterparts in + the C++ API (see :ref:`cablecell-probes` for details). Some details + like `probe_tag` are not exposed in Python, as having Python probe callbacks + has proven to be too slow. + +Example +------- + + +.. code-block:: python + + import arbor + + tree = arbor.segment_tree() + p = tree.append(arbor.mnpos, arbor.mpoint(-3, 0, 0, 3), arbor.mpoint(3, 0, 0, 3), tag=1) + tree.append(p, arbor.mpoint(3, 0, 0, 3), arbor.mpoint(-3, 0, 0, 3), tag=2) + tree.append(p, arbor.mpoint(3, 0, 0, 3), arbor.mpoint(-3, 0, 0, 3), tag=2) + + decor = ( + arbor.decor() + .set_property(Vm=-40) + .paint('"soma"', arbor.density("hh")) + .place('"midpoint"', arbor.iclamp(10, 2, 0.8), "iclamp")) + + cell = arbor.cable_cell(tree, labels, decor) + + class single_recipe(arbor.recipe): + def __init__(self): + arbor.recipe.__init__(self) + + def num_cells(self): + return 1 + + def cell_kind(self, gid): + return arbor.cell_kind.cable + + def cell_description(self, gid): + return cell + + def probes(self, gid): + return [arbor.cable_probe_membrane_voltage('(location 0 0.5)'), + arbor.cable_probe_membrane_voltage_cell(), + arbor.cable_probe_membrane_voltage('(join (location 0 0) (location 0 1))'), + ] + + # (4.6) Override the global_properties method + def global_properties(self, kind): + return arbor.neuron_cable_properties() + + recipe = single_recipe() + sim = arbor.simulation(recipe) + handles = [sim.sample((0, n), arbor.regular_schedule(0.1)) + for n in range(3) ] + sim.run(tfinal=1) + + for hd in handles: + print("Handle", hd) + for d, m in sim.samples(hd): + print(" * Meta:", m) + print(" * Payload:", d.shape) + +This script, has a single (scalar) probe, a single vector probe, and a probeset involving two scalar probes. +The script is complete and can be run with Arbor installed, and will output: + +.. code-block:: + + Handle 0 + * Meta: (location 0 0.5) + * Payload: (10, 2) + Handle 1 + * Meta: [(cable 0 0 1), (cable 0 1 1), (cable 1 0 0), (cable 2 0 0), (cable 1 0 1), (cable 2 0 1)] + * Payload: (10, 7) + Handle 2 + * Meta: (location 0 0) + * Payload: (10, 2) + * Meta: (location 0 1) + * Payload: (10, 2) + + +API +--- + +.. class:: probe + + An opaque object that is the Python representation of :cpp:class:`probe_info`. + + See below for ways to create probes. + Membrane voltage .. py:function:: cable_probe_membrane_voltage(where) @@ -37,6 +158,8 @@ Membrane voltage Metadata: the list of corresponding :class:`cable` objects. + Kind: :term:`vector probe`. + Axial current .. py:function:: cable_probe_axial_current(where) @@ -60,6 +183,8 @@ Ionic current Metadata: the list of corresponding :class:`cable` objects. + Kind: :term:`vector probe`. + Total ionic current .. py:function:: cable_probe_total_ion_current_density(where) @@ -75,6 +200,8 @@ Total ionic current Metadata: the list of corresponding :class:`cable` objects. + Kind: :term:`vector probe`. + Total transmembrane current .. py:function:: cable_probe_total_current_cell() @@ -83,6 +210,8 @@ Total transmembrane current Metadata: the list of corresponding :class:`cable` objects. + Kind: :term:`vector probe`. + Total stimulus current .. py:function:: cable_probe_stimulus_current_cell() @@ -90,6 +219,8 @@ Total stimulus current Metadata: the list of corresponding :class:`cable` objects. + Kind: :term:`vector probe`. + Density mechanism state variable .. py:function:: cable_probe_density_state(where, mechanism, state) @@ -105,6 +236,8 @@ Density mechanism state variable Metadata: the list of corresponding :class:`cable` objects. + Kind: :term:`vector probe`. + Point process state variable .. py:function:: cable_probe_point_state(target, mechanism, state) @@ -128,6 +261,8 @@ Point process state variable Metadata: a list of :class:`cable_point_probe_info` values, one for each matching target. + Kind: :term:`vector probe`. + Ionic internal concentration .. py:function:: cable_probe_ion_int_concentration(where, ion) @@ -143,6 +278,8 @@ Ionic internal concentration Metadata: the list of corresponding :class:`cable` objects. + Kind: :term:`vector probe`. + Ionic external concentration .. py:function:: cable_probe_ion_ext_concentration(where, ion) @@ -158,3 +295,5 @@ Ionic external concentration Metadata: the list of corresponding :class:`cable` objects. + Kind: :term:`vector probe`. + diff --git a/doc/python/probe_sample_vector-diag.dia b/doc/python/probe_sample_vector-diag.dia new file mode 100644 index 0000000000..aa0c3b47dc Binary files /dev/null and b/doc/python/probe_sample_vector-diag.dia differ diff --git a/doc/python/probe_sample_vector-diag.svg b/doc/python/probe_sample_vector-diag.svg new file mode 100644 index 0000000000..9e81bca85e --- /dev/null +++ b/doc/python/probe_sample_vector-diag.svg @@ -0,0 +1,175 @@ + + + + + + + + probeset + + + + + + + + + + + + + + + + + + + + + + + + handle + + + + + + probes + + + + + + + + + + meta (list) + + + + + + data (ndarray) + + + + + + + + + + + + + + [0]: time, value probe 1, value probe 2, ... + + + + + + [1]: time, value probe 1, value probe 2, ... + + + + + + [...]: time, value probe 1, value probe 2, .. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [0]: region expression probe 1 + + + + + + [1]: region expression probe 2 + + + + + + [...]: region expression probe ... + + + + + + + + + + + + diff --git a/doc/python/recipe.rst b/doc/python/recipe.rst index d50ed3fdcb..f3a4c5a11b 100644 --- a/doc/python/recipe.rst +++ b/doc/python/recipe.rst @@ -88,10 +88,10 @@ Recipe .. function:: probes(gid) - Returns a list specifying the probe addresses describing probes on the cell ``gid``. - Each address in the list is an opaque object of type :class:`probe` produced by - cell kind-specific probe address functions. Each probe address in the list - has a corresponding probe id of type :class:`cell_member`: an id ``(gid, i)`` + Returns a list specifying the probesets describing probes on the cell ``gid``. + Each element in the list is an opaque object of type :class:`probe` produced by + cell kind-specific probeset functions. Each probeset in the list + has a corresponding probeset id of type :class:`cell_member`: an id ``(gid, i)`` refers to the probes described by the ith entry in the list returned by ``get_probes(gid)``. By default returns an empty list. diff --git a/doc/python/simulation.rst b/doc/python/simulation.rst index 7d8b785107..943291e38a 100644 --- a/doc/python/simulation.rst +++ b/doc/python/simulation.rst @@ -114,25 +114,25 @@ over the local and distributed hardware resources (see :ref:`pydomdec`). Then, t **Sampling probes:** - .. function:: sample(probe_id, schedule, policy) + .. function:: sample(probeset_id, schedule, policy) - Set up a sampling schedule for the probes associated with the supplied probe_id of type :py:class:`cell_member`. + Set up a sampling schedule for the probes associated with the supplied probeset_id of type :py:class:`cell_member`. The schedule is any schedule object, as might be used with an event generator — see :ref:`pyrecipe` for details. The policy is of type :py:class:`sampling_policy`. It can be omitted, in which case the sampling will accord with the ``sampling_policy.lax`` policy. - The method returns a handle which can be used in turn to retrieve the sampled data from the simulator or to + The method returns a :term:`handle` which can be used in turn to retrieve the sampled data from the simulator or to remove the corresponding sampling process. - .. function:: probe_metadata(probe_id) + .. function:: probe_metadata(probeset_id) - Retrieve probe metadata for the probes associated with the given probe_id of type :py:class:`cell_member`. + Retrieve probe metadata for the probes associated with the given probeset_id of type :py:class:`cell_member`. The result will be a list, with one entry per probe; the specifics of each metadata entry will depend upon the kind of probe in question. .. function:: remove_sampler(handle) - Disable the sampling process referenced by the argument ``handle`` and remove any associated recorded data. + Disable the sampling process referenced by the argument :term:`handle` and remove any associated recorded data. .. function:: remove_all_samplers() @@ -140,25 +140,28 @@ over the local and distributed hardware resources (see :ref:`pydomdec`). Then, t .. function:: samples(handle) - Retrieve a list of sample data associated with the given ``handle``. - There will be one entry in the list per probe associated with the :term:`probe id` used when the sampling was set up. - For example, if a probe was placed on a locset describing three positions, the returned list will contain three elements. + Retrieve a list of sample data associated with the given :term:`handle`. + There will be one entry in the list per probe associated with the :term:`probeset id` used when the sampling was set up. + Each entry is a pair ``(samples, meta)`` where ``meta`` is the probe metadata as would be returned by + ``probe_metadata(probeset_id)``, and ``samples`` contains the recorded values. + + For example, if a probe was placed on a locset describing three positions, ``samples(handle)`` will + return a list of length `3`. In each element, each corresponding to a location in the locset, + you'll find a tuple containing ``metadata`` and ``data``, where ``metadata`` will be a string describing the location, + and ``data`` will (usually) be a ``numpy.ndarray``. An empty list will be returned if no output was recorded for the cell. For simulations that are distributed using MPI, handles associated with non-local cells will return an empty list. It is the responsibility of the caller to gather results over the ranks. - Each entry is a pair ``(samples, meta)`` where ``meta`` is the probe metadata as would be returned by - ``probe_metadata(probe_id)``, and ``samples`` contains the recorded values. - - The format of the recorded values will depend upon the specifics of the probe, though generally it will + The format of the recorded values (``data``) will depend upon the specifics of the probe, though generally it will be a NumPy array, with the first column corresponding to sample time and subsequent columns holding the value or values that were sampled from that probe at that time. .. function:: progress_banner() - Print a progress bar during simulation, with elapsed miliseconds and percentage of simulation completed. + Print a progress bar during simulation, with elapsed milliseconds and percentage of simulation completed. **Types:** @@ -263,44 +266,6 @@ Spikes recorded during a simulation are returned as a NumPy structured datatype Recording samples ----------------- -Definitions -*********** - -.. glossary:: - - probe - A measurement that can be performed on a cell. Each cell kind will have its own sorts of probe; - Cable cells (:py:attr:`arbor.cable_probe`) allow the monitoring of membrane voltage, total membrane - current, mechanism state, and a number of other quantities, measured either over the whole cell, - or at specific sites (see :ref:`pycablecell-probesample`). - - Probes are described by probe addresses, and the collection of probe addresses for a given cell is - provided by the :py:class:`recipe` object. One address may correspond to more than one probe: - as an example, a request for membrane voltage on a cable cell at sites specified by a location - expression will generate one probe for each site in that location expression. - - probe id - A designator for one or more probes as specified by a recipe. The *probe id* is a - :py:class:`cell_member` referring to a specific cell by gid, and the index into the list of - probe addresses returned by the recipe for that gid. - - metadata - Each probe has associated metadata describing, for example, the location on a cell where the - measurement is being taken, or other such identifying information. Metadata for the probes - associated with a :term:`probe id` can be retrieved from the simulation object, and is also provided - along with any recorded samples. - - sampler - A sampler is something that receives probe data. It amounts to setting a particular :term:`probe` to a - particular measuring schedule, and then having a handle with which to access the recorded probe data later on. - - sample - A record of data corresponding to the value at a specific *probe* at a specific time. - - schedule - An object representing a series of monotonically increasing points in time, used for determining - sample times (see :ref:`pyrecipe`). - Procedure ********* @@ -309,23 +274,23 @@ There are three parts to the process of recording cell data over a simulation. 1. Describing what to measure. The recipe object must provide a method :py:func:`recipe.probes` that returns a list of - probe addresses for the cell with a given ``gid``. The kth element of the list corresponds - to the :term:`probe id` ``(gid, k)``. + probeset addresses for the cell with a given ``gid``. The kth element of the list corresponds + to the :term:`probeset id` ``(gid, k)``. - Each probe address is an opaque object describing what to measure and where, and each cell kind + Each probeset address is an opaque object describing what to measure and where, and each cell kind will have its own set of functions for generating valid address specifications. Possible cable cell probes are described in the cable cell documentation: :ref:`pycablecell-probesample`. 2. Instructing the simulator to record data. Recording is set up with the method :py:func:`simulation.sample` - as described above. It returns a handle that is used to retrieve the recorded data after + as described above. It returns a :term:`handle` that is used to retrieve the recorded data after simulation. 3. Retrieve recorded data. - The method :py:func:`simulation.samples` takes a handle and returns the recorded data as a list, - with one entry for each probe associated with the :term:`probe id` that was used in step 2 above. Each + The method :py:func:`simulation.samples` takes a :term:`handle` and returns the recorded data as a list, + with one entry for each probe associated with the :term:`probeset id` that was used in step 2 above. Each entry will be a tuple ``(data, meta)`` where ``meta`` is the metadata associated with the probe, and ``data`` contains all the data sampled on that probe over the course of the simulation. @@ -350,7 +315,7 @@ Example sim = arbor.simulation(recipe, decomp, context) - # Sample probe id (0, 0) (first probe id on cell 0) every 0.1 ms with exact sample timing: + # Sample probeset id (0, 0) (first probeset id on cell 0) every 0.1 ms with exact sample timing: handle = sim.sample((0, 0), arbor.regular_schedule(0.1), arbor.sampling_policy.exact) diff --git a/doc/tutorial/network_ring.rst b/doc/tutorial/network_ring.rst index 43c5d5a3af..e7170c1252 100644 --- a/doc/tutorial/network_ring.rst +++ b/doc/tutorial/network_ring.rst @@ -131,9 +131,9 @@ This means the timestamps of the generated events will be kept in memory. Be def In addition to having the timestamps of spikes, we want to extract the voltage as a function of time. Step **(14)** sets the probes (step **10**) to measure at a certain schedule. This is sometimes described as -attaching a :term:`sampler` to a :term:`probe`. :py:func:`arbor.simulation.sample` expects a :term:`probe id` and the -desired schedule (here: a recording frequency of 10 kHz, or a ``dt`` of 0.1 ms). Note that the probe id is a separate index from those of -:term:`connection` endpoints; probe ids correspond to the index of the list produced by +attaching a :term:`sampler` to a :term:`probe`. :py:func:`arbor.simulation.sample` expects a :term:`probeset id` and the +desired schedule (here: a recording frequency of 10 kHz, or a ``dt`` of 0.1 ms). Note that the probeset id is a separate index from those of +:term:`connection` endpoints; probeset ids correspond to the index of the list produced by :py:func:`arbor.recipe.probes` on cell ``gid``. :py:func:`arbor.simulation.sample` returns a handle to the :term:`samples ` that will be recorded. We store diff --git a/example/dryrun/dryrun.cpp b/example/dryrun/dryrun.cpp index 6f38d96823..2e00e204a1 100644 --- a/example/dryrun/dryrun.cpp +++ b/example/dryrun/dryrun.cpp @@ -178,13 +178,13 @@ int main(int argc, char** argv) { arb::simulation sim(recipe, ctx); // The id of the only probe on the cell: the cell_member type points to (cell 0, probe 0) - auto probe_id = cell_member_type{0, 0}; + auto probeset_id = cell_member_type{0, 0}; // The schedule for sampling is 10 samples every 1 ms. auto sched = arb::regular_schedule(1); // This is where the voltage samples will be stored as (time, value) pairs arb::trace_vector voltage; - // Now attach the sampler at probe_id, with sampling schedule sched, writing to voltage - sim.add_sampler(arb::one_probe(probe_id), sched, arb::make_simple_sampler(voltage)); + // Now attach the sampler at probeset_id, with sampling schedule sched, writing to voltage + sim.add_sampler(arb::one_probe(probeset_id), sched, arb::make_simple_sampler(voltage)); // Set up recording of spikes to a vector on the root process. std::vector recorded_spikes; diff --git a/example/gap_junctions/gap_junctions.cpp b/example/gap_junctions/gap_junctions.cpp index 2887cb50c8..5d5d8c128c 100644 --- a/example/gap_junctions/gap_junctions.cpp +++ b/example/gap_junctions/gap_junctions.cpp @@ -180,7 +180,7 @@ int main(int argc, char** argv) { // This is where the voltage samples will be stored as (time, value) pairs std::vector> voltage_traces(decomp.num_local_cells()); - // Now attach the sampler at probe_id, with sampling schedule sched, writing to voltage + // Now attach the sampler at probeset_id, with sampling schedule sched, writing to voltage unsigned j=0; for (auto g : decomp.groups()) { for (auto i : g.gids) { diff --git a/example/generators/generators.cpp b/example/generators/generators.cpp index 44c5f9c4fd..c0b32d37a5 100644 --- a/example/generators/generators.cpp +++ b/example/generators/generators.cpp @@ -137,13 +137,13 @@ int main() { // Set up the probe that will measure voltage in the cell. // The id of the only probe on the cell: the cell_member type points to (cell 0, probe 0) - auto probe_id = cell_member_type{0, 0}; + auto probeset_id = cell_member_type{0, 0}; // The schedule for sampling is 10 samples every 1 ms. auto sched = arb::regular_schedule(0.1); // This is where the voltage samples will be stored as (time, value) pairs arb::trace_vector voltage; - // Now attach the sampler at probe_id, with sampling schedule sched, writing to voltage - sim.add_sampler(arb::one_probe(probe_id), sched, arb::make_simple_sampler(voltage)); + // Now attach the sampler at probeset_id, with sampling schedule sched, writing to voltage + sim.add_sampler(arb::one_probe(probeset_id), sched, arb::make_simple_sampler(voltage)); // Run the simulation for 100 ms, with time steps of 0.01 ms. sim.run(100, 0.01); diff --git a/example/generators/readme.md b/example/generators/readme.md index 843d566473..fc73a3a49b 100644 --- a/example/generators/readme.md +++ b/example/generators/readme.md @@ -165,19 +165,19 @@ We must attach a sampler to this probe to get sample values. The sampling interface is rich, and can be extended in many ways. For our simple use case there are three bits of information that need to be provided when creating a sampler -1. The `probe_id` that identifies the probe (generated in the recipe). +1. The `probeset_id` that identifies the probe (generated in the recipe). 2. The schedule to use for sampling (in our case 10 samples every ms). 3. The location where we want to save the samples for outputing later. ```C++ // The id of the only probe (cell 0, probe 0) - auto probe_id = cell_member_type{0, 0}; + auto probeset_id = cell_member_type{0, 0}; // The schedule for sampling is 10 samples every 1 ms. auto sched = arb::regular_schedule(0.1); // Where the voltage samples will be stored as (time, value) pairs arb::trace_data voltage; // Now attach the sampler: - sim.add_sampler(arb::one_probe(probe_id), sched, arb::make_simple_sampler(voltage)); + sim.add_sampler(arb::one_probe(probeset_id), sched, arb::make_simple_sampler(voltage)); ``` When the simulation is run, the `simple_sampler` that we attached to the probe will store the sample values as (time, voltage) pairs in the `voltage` vector. diff --git a/example/ring/ring.cpp b/example/ring/ring.cpp index fa47d3f215..72c4889e56 100644 --- a/example/ring/ring.cpp +++ b/example/ring/ring.cpp @@ -168,13 +168,13 @@ int main(int argc, char** argv) { // Set up the probe that will measure voltage in the cell. // The id of the only probe on the cell: the cell_member type points to (cell 0, probe 0) - auto probe_id = cell_member_type{0, 0}; + auto probeset_id = cell_member_type{0, 0}; // The schedule for sampling is 10 samples every 1 ms. auto sched = arb::regular_schedule(1); // This is where the voltage samples will be stored as (time, value) pairs arb::trace_vector voltage; - // Now attach the sampler at probe_id, with sampling schedule sched, writing to voltage - sim.add_sampler(arb::one_probe(probe_id), sched, arb::make_simple_sampler(voltage)); + // Now attach the sampler at probeset_id, with sampling schedule sched, writing to voltage + sim.add_sampler(arb::one_probe(probeset_id), sched, arb::make_simple_sampler(voltage)); // Set up recording of spikes to a vector on the root process. std::vector recorded_spikes; diff --git a/python/example/probe_lfpykit.py b/python/example/probe_lfpykit.py index 10e769345a..8519b933f7 100644 --- a/python/example/probe_lfpykit.py +++ b/python/example/probe_lfpykit.py @@ -25,9 +25,9 @@ def __init__(self, cell): self.the_cell = cell - self.vprobe_id = (0, 0) - self.iprobe_id = (0, 1) - self.cprobe_id = (0, 2) + self.vprobeset_id = (0, 0) + self.iprobeset_id = (0, 1) + self.cprobeset_id = (0, 2) self.the_props = arbor.neuron_cable_properties() @@ -125,9 +125,9 @@ def make_cable_cell(morphology, clamp_location): # set up sampling on probes with sampling every 1 ms schedule = arbor.regular_schedule(1.0) -v_handle = sim.sample(recipe.vprobe_id, schedule, arbor.sampling_policy.exact) -i_handle = sim.sample(recipe.iprobe_id, schedule, arbor.sampling_policy.exact) -c_handle = sim.sample(recipe.cprobe_id, schedule, arbor.sampling_policy.exact) +v_handle = sim.sample(recipe.vprobeset_id, schedule, arbor.sampling_policy.exact) +i_handle = sim.sample(recipe.iprobeset_id, schedule, arbor.sampling_policy.exact) +c_handle = sim.sample(recipe.cprobeset_id, schedule, arbor.sampling_policy.exact) # run simulation for 500 ms of simulated activity and collect results. sim.run(tfinal=500) diff --git a/python/example/single_cell_detailed_recipe.py b/python/example/single_cell_detailed_recipe.py index e13f8a85b3..4443b9f3ac 100644 --- a/python/example/single_cell_detailed_recipe.py +++ b/python/example/single_cell_detailed_recipe.py @@ -119,8 +119,8 @@ def global_properties(self, gid): # Instruct the simulation to record the spikes and sample the probe sim.record(arbor.spike_recording.all) -probe_id = arbor.cell_member(0, 0) -handle = sim.sample(probe_id, arbor.regular_schedule(0.02)) +probeset_id = arbor.cell_member(0, 0) +handle = sim.sample(probeset_id, arbor.regular_schedule(0.02)) # (7) Run the simulation sim.run(tfinal=100, dt=0.025) diff --git a/python/example/single_cell_recipe.py b/python/example/single_cell_recipe.py index 6e12fd546d..315d0a088c 100644 --- a/python/example/single_cell_recipe.py +++ b/python/example/single_cell_recipe.py @@ -71,7 +71,7 @@ def global_properties(self, kind): sim = arbor.simulation(recipe) # (7) Create and run simulation and set up 10 kHz (every 0.1 ms) sampling on the probe. -# The probe is located on cell 0, and is the 0th probe on that cell, thus has probe_id (0, 0). +# The probe is located on cell 0, and is the 0th probe on that cell, thus has probeset_id (0, 0). sim.record(arbor.spike_recording.all) handle = sim.sample((0, 0), arbor.regular_schedule(0.1)) diff --git a/python/simulation.cpp b/python/simulation.cpp index 90689f843d..647522d0b3 100644 --- a/python/simulation.cpp +++ b/python/simulation.cpp @@ -126,18 +126,18 @@ class simulation_shim { return py::array_t(py::ssize_t(spike_record_.size()), spike_record_.data()); } - py::list get_probe_metadata(arb::cell_member_type probe_id) const { + py::list get_probe_metadata(arb::cell_member_type probeset_id) const { py::list result; - for (auto&& pm: sim_->get_probe_metadata(probe_id)) { + for (auto&& pm: sim_->get_probe_metadata(probeset_id)) { result.append(global_ptr_->probe_meta_converters.convert(pm.meta)); } return result; } - arb::sampler_association_handle sample(arb::cell_member_type probe_id, const pyarb::schedule_shim_base& sched, arb::sampling_policy policy) { + arb::sampler_association_handle sample(arb::cell_member_type probeset_id, const pyarb::schedule_shim_base& sched, arb::sampling_policy policy) { std::shared_ptr recorders{new sample_recorder_vec}; - for (const arb::probe_metadata& pm: sim_->get_probe_metadata(probe_id)) { + for (const arb::probe_metadata& pm: sim_->get_probe_metadata(probeset_id)) { recorders->push_back(global_ptr_->recorder_factories.make_recorder(pm.meta)); } @@ -145,7 +145,7 @@ class simulation_shim { // is kept in sampler_map_; the two copies share the same recorder data. sampler_callback cb{std::move(recorders)}; - auto sah = sim_->add_sampler(arb::one_probe(probe_id), sched.schedule(), cb, policy); + auto sah = sim_->add_sampler(arb::one_probe(probeset_id), sched.schedule(), cb, policy); sampler_map_.insert({sah, cb}); return sah; @@ -234,11 +234,11 @@ void register_simulation(pybind11::module& m, pyarb_global_ptr global_ptr) { "Retrieve recorded spikes as numpy array.") .def("probe_metadata", &simulation_shim::get_probe_metadata, "Retrieve metadata associated with given probe id.", - "probe_id"_a) + "probeset_id"_a) .def("sample", &simulation_shim::sample, - "Record data from probes with given probe_id according to supplied schedule.\n" + "Record data from probes with given probeset_id according to supplied schedule.\n" "Returns handle for retrieving data or removing the sampling.", - "probe_id"_a, "schedule"_a, "policy"_a = arb::sampling_policy::lax) + "probeset_id"_a, "schedule"_a, "policy"_a = arb::sampling_policy::lax) .def("samples", &simulation_shim::samples, "Retrieve sample data as a list, one element per probe associated with the query.", "handle"_a) diff --git a/test/unit/test_probe.cpp b/test/unit/test_probe.cpp index ca541823fa..7cf962832f 100644 --- a/test/unit/test_probe.cpp +++ b/test/unit/test_probe.cpp @@ -755,12 +755,12 @@ void run_partial_density_probe_test(const context& ctx) { cell_lid_type probe_lid = 0; for (auto tp: test_probes) { for (cell_gid_type gid: {0, 1}) { - cell_member_type probe_id{gid, probe_lid}; + cell_member_type probeset_id{gid, probe_lid}; if (std::isnan(tp.expected[gid])) { - EXPECT_EQ(0u, probe_map.data.count(probe_id)); + EXPECT_EQ(0u, probe_map.data.count(probeset_id)); } else { - probe_handle h = get_probe_raw_handle(probe_id); + probe_handle h = get_probe_raw_handle(probeset_id); EXPECT_DOUBLE_EQ(tp.expected[gid], deref(h)); } }