NEURON
report_handler.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_handler.hpp"
13 
14 namespace coreneuron {
15 
16 template <typename T>
17 std::vector<T> intersection_gids(const NrnThread& nt, std::vector<T>& target_gids) {
18  std::vector<int> thread_gids;
19  for (int i = 0; i < nt.ncell; i++) {
20  thread_gids.push_back(nt.presyns[i].gid_);
21  }
22  std::vector<T> intersection;
23 
24  std::sort(thread_gids.begin(), thread_gids.end());
25  std::sort(target_gids.begin(), target_gids.end());
26 
27  std::set_intersection(thread_gids.begin(),
28  thread_gids.end(),
29  target_gids.begin(),
30  target_gids.end(),
31  back_inserter(intersection));
32 
33  return intersection;
34 }
35 
37  double dt,
38  double tstop,
39  double delay) {
40 #ifdef ENABLE_SONATA_REPORTS
41  if (report_config.start < t) {
42  report_config.start = t;
43  }
44  report_config.stop = std::min(report_config.stop, tstop);
45 
46  for (const auto& mech: report_config.mech_names) {
47  report_config.mech_ids.emplace_back(nrn_get_mechtype(mech.data()));
48  }
49  if (report_config.type == SynapseReport && report_config.mech_ids.empty()) {
50  std::cerr << "[ERROR] mechanism to report: " << report_config.mech_names[0]
51  << " is not mapped in this simulation, cannot report on it \n";
52  nrn_abort(1);
53  }
54  for (int ith = 0; ith < nrn_nthread; ++ith) {
55  NrnThread& nt = nrn_threads[ith];
56  double* report_variable = nt._actual_v;
57  if (!nt.ncell) {
58  continue;
59  }
60  auto* mapinfo = static_cast<NrnThreadMappingInfo*>(nt.mapping);
61  const std::vector<int>& nodes_to_gid = map_gids(nt);
62  const std::vector<int> gids_to_report = intersection_gids(nt, report_config.target);
63  VarsToReport vars_to_report;
64  bool is_soma_target;
65  switch (report_config.type) {
66  case IMembraneReport:
67  report_variable = nt.nrn_fast_imem->nrn_sav_rhs;
68  case SectionReport:
69  vars_to_report = get_section_vars_to_report(nt,
70  gids_to_report,
71  report_variable,
72  report_config.section_type,
73  report_config.section_all_compartments);
74  is_soma_target = report_config.section_type == SectionType::Soma ||
75  report_config.section_type == SectionType::Cell;
76  register_section_report(nt, report_config, vars_to_report, is_soma_target);
77  break;
78  case SummationReport:
79  vars_to_report =
80  get_summation_vars_to_report(nt, gids_to_report, report_config, nodes_to_gid);
81  register_custom_report(nt, report_config, vars_to_report);
82  break;
83  case LFPReport:
84  mapinfo->prepare_lfp();
85  vars_to_report = get_lfp_vars_to_report(
86  nt, gids_to_report, report_config, mapinfo->_lfp.data(), nodes_to_gid);
87  is_soma_target = report_config.section_type == SectionType::Soma ||
88  report_config.section_type == SectionType::Cell;
89  register_section_report(nt, report_config, vars_to_report, is_soma_target);
90  break;
91  default:
92  vars_to_report =
93  get_synapse_vars_to_report(nt, gids_to_report, report_config, nodes_to_gid);
94  register_custom_report(nt, report_config, vars_to_report);
95  }
96  if (!vars_to_report.empty()) {
97  auto report_event = std::make_unique<ReportEvent>(dt,
98  t,
99  vars_to_report,
100  report_config.output_path.data(),
101  report_config.report_dt,
102  report_config.type);
103  report_event->send(t, net_cvode_instance, &nt);
104  m_report_events.push_back(std::move(report_event));
105  }
106  }
107 #else
108  if (nrnmpi_myid == 0) {
109  std::cerr << "[WARNING] : Reporting is disabled. Please recompile with libsonata.\n";
110  }
111 #endif
112 }
113 
114 #ifdef ENABLE_SONATA_REPORTS
115 void ReportHandler::register_section_report(const NrnThread& nt,
116  const ReportConfiguration& config,
117  const VarsToReport& vars_to_report,
118  bool is_soma_target) {
119  if (nrnmpi_myid == 0) {
120  std::cerr << "[WARNING] : Format '" << config.format << "' in report '"
121  << config.output_path << "' not supported.\n";
122  }
123 }
124 void ReportHandler::register_custom_report(const NrnThread& nt,
125  const ReportConfiguration& config,
126  const VarsToReport& vars_to_report) {
127  if (nrnmpi_myid == 0) {
128  std::cerr << "[WARNING] : Format '" << config.format << "' in report '"
129  << config.output_path << "' not supported.\n";
130  }
131 }
132 
133 std::string getSectionTypeStr(SectionType type) {
134  switch (type) {
135  case All:
136  return "All";
137  case Cell:
138  case Soma:
139  return "soma";
140  case Axon:
141  return "axon";
142  case Dendrite:
143  return "dend";
144  case Apical:
145  return "apic";
146  default:
147  std::cerr << "SectionType not handled in getSectionTypeStr" << std::endl;
148  nrn_abort(1);
149  }
150 }
151 
152 void register_sections_to_report(const SecMapping* sections,
153  std::vector<VarWithMapping>& to_report,
154  double* report_variable,
155  bool all_compartments) {
156  for (const auto& section: sections->secmap) {
157  // compartment_id
158  int section_id = section.first;
159  const auto& segment_ids = section.second;
160 
161  // get all compartment values (otherwise, just middle point)
162  if (all_compartments) {
163  for (const auto& segment_id: segment_ids) {
164  // corresponding voltage in coreneuron voltage array
165  double* variable = report_variable + segment_id;
166  to_report.emplace_back(VarWithMapping(section_id, variable));
167  }
168  } else {
169  nrn_assert(segment_ids.size() % 2);
170  // corresponding voltage in coreneuron voltage array
171  const auto segment_id = segment_ids[segment_ids.size() / 2];
172  double* variable = report_variable + segment_id;
173  to_report.emplace_back(VarWithMapping(section_id, variable));
174  }
175  }
176 }
177 
178 VarsToReport ReportHandler::get_section_vars_to_report(const NrnThread& nt,
179  const std::vector<int>& gids_to_report,
180  double* report_variable,
181  SectionType section_type,
182  bool all_compartments) const {
183  VarsToReport vars_to_report;
184  const auto& section_type_str = getSectionTypeStr(section_type);
185  const auto* mapinfo = static_cast<NrnThreadMappingInfo*>(nt.mapping);
186  if (!mapinfo) {
187  std::cerr << "[COMPARTMENTS] Error : mapping information is missing for a Cell group "
188  << nt.ncell << '\n';
189  nrn_abort(1);
190  }
191 
192  for (const auto& gid: gids_to_report) {
193  const auto& cell_mapping = mapinfo->get_cell_mapping(gid);
194  if (cell_mapping == nullptr) {
195  std::cerr
196  << "[COMPARTMENTS] Error : Compartment mapping information is missing for gid "
197  << gid << '\n';
198  nrn_abort(1);
199  }
200  std::vector<VarWithMapping> to_report;
201  to_report.reserve(cell_mapping->size());
202 
203  if (section_type_str == "All") {
204  const auto& section_mapping = cell_mapping->secmapvec;
205  for (const auto& sections: section_mapping) {
206  register_sections_to_report(sections, to_report, report_variable, all_compartments);
207  }
208  } else {
209  /** get section list mapping for the type, if available */
210  if (cell_mapping->get_seclist_section_count(section_type_str) > 0) {
211  const auto& sections = cell_mapping->get_seclist_mapping(section_type_str);
212  register_sections_to_report(sections, to_report, report_variable, all_compartments);
213  }
214  }
215  vars_to_report[gid] = to_report;
216  }
217  return vars_to_report;
218 }
219 
220 VarsToReport ReportHandler::get_summation_vars_to_report(
221  const NrnThread& nt,
222  const std::vector<int>& gids_to_report,
223  const ReportConfiguration& report,
224  const std::vector<int>& nodes_to_gids) const {
225  VarsToReport vars_to_report;
226  const auto* mapinfo = static_cast<NrnThreadMappingInfo*>(nt.mapping);
227  auto& summation_report = nt.summation_report_handler_->summation_reports_[report.output_path];
228  if (!mapinfo) {
229  std::cerr << "[COMPARTMENTS] Error : mapping information is missing for a Cell group "
230  << nt.ncell << '\n';
231  nrn_abort(1);
232  }
233 
234  for (const auto& gid: gids_to_report) {
235  bool has_imembrane = false;
236  // In case we need convertion of units
237  int scale = 1;
238  for (auto i = 0; i < report.mech_ids.size(); ++i) {
239  auto mech_id = report.mech_ids[i];
240  auto var_name = report.var_names[i];
241  auto mech_name = report.mech_names[i];
242  if (mech_name != "i_membrane") {
243  // need special handling for Clamp processes to flip the current value
244  if (mech_name == "IClamp" || mech_name == "SEClamp") {
245  scale = -1;
246  }
247  Memb_list* ml = nt._ml_list[mech_id];
248  if (!ml) {
249  continue;
250  }
251 
252  for (int j = 0; j < ml->nodecount; j++) {
253  auto segment_id = ml->nodeindices[j];
254  if ((nodes_to_gids[ml->nodeindices[j]] == gid)) {
255  double* var_value =
256  get_var_location_from_var_name(mech_id, var_name.data(), ml, j);
257  summation_report.currents_[segment_id].push_back(
258  std::make_pair(var_value, scale));
259  }
260  }
261  } else {
262  has_imembrane = true;
263  }
264  }
265  const auto& cell_mapping = mapinfo->get_cell_mapping(gid);
266  if (cell_mapping == nullptr) {
267  std::cerr << "[SUMMATION] Error : Compartment mapping information is missing for gid "
268  << gid << '\n';
269  nrn_abort(1);
270  }
271  std::vector<VarWithMapping> to_report;
272  to_report.reserve(cell_mapping->size());
273  summation_report.summation_.resize(nt.end);
274  double* report_variable = summation_report.summation_.data();
275  const auto& section_type_str = getSectionTypeStr(report.section_type);
276  if (report.section_type != SectionType::All) {
277  if (cell_mapping->get_seclist_section_count(section_type_str) > 0) {
278  const auto& sections = cell_mapping->get_seclist_mapping(section_type_str);
279  register_sections_to_report(sections,
280  to_report,
281  report_variable,
282  report.section_all_compartments);
283  }
284  }
285  const auto& section_mapping = cell_mapping->secmapvec;
286  for (const auto& sections: section_mapping) {
287  for (auto& section: sections->secmap) {
288  // compartment_id
289  int section_id = section.first;
290  auto& segment_ids = section.second;
291  for (const auto& segment_id: segment_ids) {
292  // corresponding voltage in coreneuron voltage array
293  if (has_imembrane) {
294  summation_report.currents_[segment_id].push_back(
295  std::make_pair(nt.nrn_fast_imem->nrn_sav_rhs + segment_id, 1));
296  }
297  if (report.section_type == SectionType::All) {
298  double* variable = report_variable + segment_id;
299  to_report.emplace_back(VarWithMapping(section_id, variable));
300  } else if (report.section_type == SectionType::Cell ||
301  report.section_type == SectionType::Soma) {
302  summation_report.gid_segments_[gid].push_back(segment_id);
303  }
304  }
305  }
306  }
307  vars_to_report[gid] = to_report;
308  }
309  return vars_to_report;
310 }
311 
312 VarsToReport ReportHandler::get_synapse_vars_to_report(
313  const NrnThread& nt,
314  const std::vector<int>& gids_to_report,
315  const ReportConfiguration& report,
316  const std::vector<int>& nodes_to_gids) const {
317  VarsToReport vars_to_report;
318  for (const auto& gid: gids_to_report) {
319  // There can only be 1 mechanism
320  nrn_assert(report.mech_ids.size() == 1);
321  auto mech_id = report.mech_ids[0];
322  auto var_name = report.var_names[0];
323  Memb_list* ml = nt._ml_list[mech_id];
324  if (!ml) {
325  continue;
326  }
327  std::vector<VarWithMapping> to_report;
328  to_report.reserve(ml->nodecount);
329 
330  for (int j = 0; j < ml->nodecount; j++) {
331  double* is_selected =
333  bool report_variable = false;
334 
335  /// if there is no variable in mod file then report on every compartment
336  /// otherwise check the flag set in mod file
337  if (is_selected == nullptr) {
338  report_variable = true;
339  } else {
340  report_variable = *is_selected != 0.;
341  }
342  if ((nodes_to_gids[ml->nodeindices[j]] == gid) && report_variable) {
343  double* var_value = get_var_location_from_var_name(mech_id, var_name.data(), ml, j);
344  double* synapse_id =
346  nrn_assert(synapse_id && var_value);
347  to_report.emplace_back(static_cast<int>(*synapse_id), var_value);
348  }
349  }
350  if (!to_report.empty()) {
351  vars_to_report[gid] = to_report;
352  }
353  }
354  return vars_to_report;
355 }
356 
357 VarsToReport ReportHandler::get_lfp_vars_to_report(const NrnThread& nt,
358  const std::vector<int>& gids_to_report,
359  ReportConfiguration& report,
360  double* report_variable,
361  const std::vector<int>& nodes_to_gids) const {
362  const auto* mapinfo = static_cast<NrnThreadMappingInfo*>(nt.mapping);
363  if (!mapinfo) {
364  std::cerr << "[LFP] Error : mapping information is missing for a Cell group " << nt.ncell
365  << '\n';
366  nrn_abort(1);
367  }
368  auto& summation_report = nt.summation_report_handler_->summation_reports_[report.output_path];
369  VarsToReport vars_to_report;
370  std::size_t offset_lfp = 0;
371  for (const auto& gid: gids_to_report) {
372  const auto& cell_mapping = mapinfo->get_cell_mapping(gid);
373  if (cell_mapping == nullptr) {
374  std::cerr << "[LFP] Error : Compartment mapping information is missing for gid " << gid
375  << '\n';
376  nrn_abort(1);
377  }
378  std::vector<VarWithMapping> to_report;
379  int num_electrodes = cell_mapping->num_electrodes();
380  for (int electrode_id = 0; electrode_id < num_electrodes; electrode_id++) {
381  to_report.emplace_back(VarWithMapping(electrode_id, report_variable + offset_lfp));
382  offset_lfp++;
383  }
384  if (!to_report.empty()) {
385  vars_to_report[gid] = to_report;
386  }
387  }
388  return vars_to_report;
389 }
390 
391 // map GIDs of every compartment, it consist in a backward sweep then forward sweep algorithm
392 std::vector<int> ReportHandler::map_gids(const NrnThread& nt) const {
393  std::vector<int> nodes_gid(nt.end, -1);
394  // backward sweep: from presyn compartment propagate back GID to parent
395  for (int i = 0; i < nt.n_presyn; i++) {
396  const int gid = nt.presyns[i].gid_;
397  const int thvar_index = nt.presyns[i].thvar_index_;
398  // only for non artificial cells
399  if (thvar_index >= 0) {
400  // setting all roots gids of the presyns nodes,
401  // index 0 have parent set to 0, so we must stop at j > 0
402  // also 0 is the parent of all, so it is an error to attribute a GID to it.
403  nodes_gid[thvar_index] = gid;
404  for (int j = thvar_index; j > 0; j = nt._v_parent_index[j]) {
405  nodes_gid[nt._v_parent_index[j]] = gid;
406  }
407  }
408  }
409  // forward sweep: setting all compartements nodes to the GID of its root
410  // already sets on above loop. This is working only because compartments are stored in order
411  // parents follow by childrens
412  for (int i = nt.ncell + 1; i < nt.end; i++) {
413  nodes_gid[i] = nodes_gid[nt._v_parent_index[i]];
414  }
415  return nodes_gid;
416 }
417 #endif
418 
419 } // Namespace coreneuron
virtual void create_report(ReportConfiguration &config, double dt, double tstop, double delay)
#define i
Definition: md1redef.h:19
void move(Item *q1, Item *q2, Item *q3)
Definition: list.cpp:200
THIS FILE IS AUTO GENERATED DONT MODIFY IT.
NrnThread * nrn_threads
Definition: multicore.cpp:56
void nrn_abort(int errcode)
Definition: utils.cpp:13
int nrn_nthread
Definition: multicore.cpp:55
@ IMembraneReport
Definition: nrnreport.hpp:77
@ SummationReport
Definition: nrnreport.hpp:79
double * get_var_location_from_var_name(int mech_id, const char *variable_name, Memb_list *ml, int node_index)
std::vector< T > intersection_gids(const NrnThread &nt, std::vector< T > &target_gids)
int nrn_get_mechtype(const char *name)
Get mechanism type by the mechanism name.
Definition: mk_mech.cpp:145
NetCvode * net_cvode_instance
Definition: netcvode.cpp:35
#define nrn_assert(x)
assert()-like macro, independent of NDEBUG status
Definition: nrn_assert.h:33
NrnMappingInfo mapinfo
mapping information
size_t j
short type
Definition: cabvars.h:10
#define SELECTED_VAR_MOD_NAME
Definition: nrnreport.hpp:49
#define SYNAPSE_ID_MOD_NAME
name of the variable in mod file used for setting synapse id
Definition: nrnreport.hpp:52
A view into a set of mechanism instances.
Definition: nrnoc_ml.h:34
int nodecount
Definition: nrnoc_ml.h:78
int * nodeindices
Definition: nrnoc_ml.h:74
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
int * _v_parent_index
Definition: multicore.h:89
int ncell
Definition: multicore.h:64
int end
Definition: multicore.h:65
Memb_list ** _ml_list
Definition: multicore.h:63
Section to segment mapping.
NrnFastImem * nrn_fast_imem
Definition: multicore.hpp:124
Compartment mapping information for NrnThread.
std::vector< std::string > mech_names
Definition: nrnreport.hpp:90
std::vector< int > mech_ids
Definition: nrnreport.hpp:92