Skip to content

Commit

Permalink
Fix LIF oversampling. (#2091)
Browse files Browse the repository at this point in the history
Fixes an issue where LIF sampling across multiple epochs causes
repetition of the same sampling event et ergo
multiple samples for the same time, viz
```
0 v0
0 v0
1 v1
0 v0
1 v1
2 v2
...
```
  • Loading branch information
thorstenhater authored Mar 7, 2023
1 parent 6d41317 commit a2b0ef8
Show file tree
Hide file tree
Showing 3 changed files with 867 additions and 411 deletions.
24 changes: 17 additions & 7 deletions arbor/lif_cell_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ lif_cell_group::lif_cell_group(const std::vector<cell_gid_type>& gids,
// set up cell state
cells_.push_back(cell);
last_time_updated_.push_back(0.0);
last_time_sampled_.push_back(-1.0);
// tell our caller about this cell's connections
cg_sources.add_cell();
cg_targets.add_cell();
Expand Down Expand Up @@ -107,7 +108,10 @@ lif_decay(const lif_cell& cell, double t0, double t1) {

// Advances a single cell (lid) with the exact solution (jumps can be arbitrary).
// Parameter dt is ignored, since we make jumps between two consecutive spikes.
void lif_cell_group::advance_cell(time_type tfinal, time_type dt, cell_gid_type lid, const event_lane_subrange& event_lanes) {
void lif_cell_group::advance_cell(time_type tfinal,
time_type dt,
cell_gid_type lid,
const event_lane_subrange& event_lanes) {
const auto gid = gids_[lid];
auto& cell = cells_[lid];
// time of last update.
Expand All @@ -123,11 +127,15 @@ void lif_cell_group::advance_cell(time_type tfinal, time_type dt, cell_gid_type
std::size_t n_values = 0;
std::vector<std::pair<time_type, sampler_association_handle>> samples;
if (!samplers_.empty()) {
auto tlast = last_time_sampled_[lid];
std::lock_guard<std::mutex> guard(sampler_mex_);
for (auto& [hdl, assoc]: samplers_) {
if (assoc.probeset_ids.empty()) continue; // No need to generate events
// Construct sampling times
const auto& times = util::make_range(assoc.sched.events(t, tfinal));
// No need to generate events
if (assoc.probeset_ids.empty()) continue;
// Construct sampling times, might give us the last time we sampled, so skip that.
auto times = util::make_range(assoc.sched.events(tlast, tfinal));
while (!times.empty() && times.front() == tlast) times.left++;
if (times.empty()) continue;
const auto n_times = times.size();
// Count up the samplers touching _our_ gid
int delta = 0;
Expand Down Expand Up @@ -219,21 +227,23 @@ void lif_cell_group::advance_cell(time_type tfinal, time_type dt, cell_gid_type
}
}
}
last_time_sampled_[lid] = time;
}
if (!(do_sample || do_event)) {
throw arbor_internal_error{"LIF cell group: Must select either sample or spike event; got neither."};
}
last_time_updated_[lid] = t;
}
arb_assert (sampled_voltages.size() == n_values);
arb_assert (sampled_voltages.size() <= n_values);
// Now we need to call all sampler callbacks with the data we have collected
{
std::lock_guard<std::mutex> guard(sampler_mex_);
for (const auto& [k, vs]: sampled) {
for (auto& [k, vs]: sampled) {
const auto& fun = samplers_[k].sampler;
for (const auto& [id, us]: vs) {
for (auto& [id, us]: vs) {
auto meta = get_probe_metadata(id)[0];
fun(meta, us.size(), us.data());
us.clear();
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions arbor/lif_cell_group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class ARB_ARBOR_API lif_cell_group: public cell_group {

// Time when the cell was last updated.
std::vector<time_type> last_time_updated_;
// Time when the cell was last sampled.
std::vector<time_type> last_time_sampled_;
// Time when the cell can _next_ be updated;
std::vector<time_type> next_time_updatable_;

Expand Down
Loading

0 comments on commit a2b0ef8

Please sign in to comment.