NEURON
report_event.cpp
Go to the documentation of this file.
1 /*
2 # =============================================================================
3 # Copyright (c) 2016 - 2021 Blue Brain Project/EPFL
4 #
5 # See top-level LICENSE file for details.
6 # =============================================================================
7 */
8 
9 #include "report_event.hpp"
10 
11 #include <numeric>
12 
17 #ifdef ENABLE_SONATA_REPORTS
18 #include "bbp/sonata/reports.h"
19 #endif // ENABLE_SONATA_REPORTS
20 
21 namespace coreneuron {
22 
23 #ifdef ENABLE_SONATA_REPORTS
24 ReportEvent::ReportEvent(double dt,
25  double tstart,
26  const VarsToReport& filtered_gids,
27  const char* name,
28  double report_dt,
30  : dt(dt)
31  , tstart(tstart)
32  , report_path(name)
33  , report_dt(report_dt)
34  , report_type(type)
35  , vars_to_report(filtered_gids) {
36  nrn_assert(filtered_gids.size());
37  step = tstart / dt;
38  reporting_period = static_cast<int>(report_dt / dt);
39  gids_to_report.reserve(filtered_gids.size());
40  for (const auto& gid: filtered_gids) {
41  gids_to_report.push_back(gid.first);
42  }
43  std::sort(gids_to_report.begin(), gids_to_report.end());
44 }
45 
46 // Compute and store the weighted sum of currents for each segment,
47 // then compute the soma total as the sum of its segments' currents.
48 // This function assumes that nt->summation_report_handler_ and vars_to_report are properly
49 // populated.
50 
51 void ReportEvent::summation_alu(NrnThread* nt) {
52  auto& summation_report = nt->summation_report_handler_->summation_reports_[report_path];
53  const auto weighted_sum_accumulator = [](double acc, const auto& pair) {
54  // pair.first is a pointer to the current value,
55  // pair.second is the scaling factor
56  return acc + (*pair.first) * pair.second;
57  };
58 
59  // Calculate weighted sum of currents for each segment using std::accumulate
60  for (const auto& [segment_id, current_pairs]: summation_report.currents_) {
61  double sum = std::accumulate(current_pairs.begin(),
62  current_pairs.end(),
63  0.0,
64  weighted_sum_accumulator);
65 
66  summation_report.summation_[segment_id] = sum;
67  }
68 
69  // Calculate the soma total current by summing over its segments using std::accumulate
70  if (!summation_report.gid_segments_.empty()) {
71  const auto accumulator = [&summation_report](double acc, int segment_id) {
72  return acc + summation_report.summation_[segment_id];
73  };
74  for (const auto& [gid, segment_ids]: summation_report.gid_segments_) {
75  double sum_soma =
76  std::accumulate(segment_ids.begin(), segment_ids.end(), 0.0, accumulator);
77 
78  *(vars_to_report[gid].front().var_value) = sum_soma;
79  }
80  }
81 }
82 
83 /** @brief Compute Local Field Potentials (LFP) for each cell.
84  *
85  * For every segment of a cell, computes the total membrane current (imem + iclamp)
86  * and accumulates the weighted contribution to each electrode using precomputed
87  * transfer factors. Results are written into the report output buffers.
88  */
89 void ReportEvent::lfp_calc(NrnThread* nt) {
90  auto* mapinfo = static_cast<NrnThreadMappingInfo*>(nt->mapping);
91  double* fast_imem_rhs = nt->nrn_fast_imem->nrn_sav_rhs;
92  auto& summation_report = nt->summation_report_handler_->summation_reports_[report_path];
93  for (const auto& kv: vars_to_report) {
94  int gid = kv.first;
95  const auto& electrode_outputs = kv.second;
96  const auto& cell_mapping = mapinfo->get_cell_mapping(gid);
97  const auto n_electrodes = cell_mapping->num_electrodes();
98  const auto n_segments = cell_mapping->lfp_segment_ids.size();
99  std::vector<double> lfp_values(n_electrodes, 0.0);
100  for (size_t i = 0; i < n_segments; i++) {
101  const auto segment_id = cell_mapping->lfp_segment_ids[i];
102 
103  // compute imem + iclamp
104  const double imem = std::accumulate(summation_report.currents_[segment_id].begin(),
105  summation_report.currents_[segment_id].end(),
106  fast_imem_rhs[segment_id],
107  [](double sum, const auto& value) {
108  return sum + *value.first * value.second;
109  });
110 
111  // dot product with the factors
112  const double* factors = &cell_mapping->lfp_factors_flat[i * n_electrodes];
113  for (size_t e = 0; e < n_electrodes; e++) {
114  lfp_values[e] += imem * factors[e];
115  }
116  }
117 
118  // write LFP values to report output buffers
119  for (const auto& output: electrode_outputs) {
120  *(output.var_value) = lfp_values[output.id];
121  }
122  }
123 }
124 
125 /** on deliver, call ReportingLib and setup next event */
126 void ReportEvent::deliver(double t, NetCvode* nc, NrnThread* nt) {
127 /* libsonata is not thread safe */
128 #pragma omp critical
129  {
130  // Sum currents and calculate lfp only on reporting steps
131  if ((static_cast<int>(step) % reporting_period) == 0) {
132  if (report_type == ReportType::Summation) {
133  summation_alu(nt);
134  } else if (report_type == ReportType::LFP) {
135  lfp_calc(nt);
136  }
137  }
138  // each thread needs to know its own step
139 #ifdef ENABLE_SONATA_REPORTS
140  sonata_record_node_data(step,
141  gids_to_report.size(),
142  gids_to_report.data(),
143  report_path.data());
144 #endif
145  send(t + dt, nc, nt);
146  step++;
147  }
148 }
149 
150 bool ReportEvent::require_checkpoint() {
151  return false;
152 }
153 #endif
154 
155 } // Namespace coreneuron
#define i
Definition: md1redef.h:19
step
Definition: extdef.h:7
const char * name
Definition: init.cpp:16
THIS FILE IS AUTO GENERATED DONT MODIFY IT.
#define nrn_assert(x)
assert()-like macro, independent of NDEBUG status
Definition: nrn_assert.h:33
NrnMappingInfo mapinfo
mapping information
short type
Definition: cabvars.h:10
static uint32_t value
Definition: scoprand.cpp:25
size_t size()
number of section lists
CellMapping * get_cell_mapping(int gid)
get cell mapping information for given gid if exist otherwise return NULL.
Represent main neuron object computed by single thread.
Definition: multicore.h:58