10 #include <unordered_set>
18 #ifdef ENABLE_SONATA_REPORTS
20 void ReportHandler::register_section_report(
const NrnThread& nt,
21 const ReportConfiguration& config,
22 const VarsToReport& vars_to_report,
23 bool is_soma_target) {
25 std::cerr <<
"[WARNING] : Format '" << config.format <<
"' in report '"
26 << config.output_path <<
"' not supported.\n";
29 void ReportHandler::register_custom_report(
const NrnThread& nt,
30 const ReportConfiguration& config,
31 const VarsToReport& vars_to_report) {
33 std::cerr <<
"[WARNING] : Format '" << config.format <<
"' in report '"
34 << config.output_path <<
"' not supported.\n";
45 static void fill_segment_id_2_node_id(
Memb_list* ml,
46 std::unordered_map<int, int>& segment_id_2_node_id) {
50 if (!segment_id_2_node_id.empty()) {
56 auto result = segment_id_2_node_id.insert({segment_id,
j});
58 std::cerr <<
"Found duplicate in nodeindices: " << segment_id <<
" index: " <<
j
60 std::cerr <<
"The nodeindices (size: " << ml->
nodecount <<
") are:\n[";
65 std::cerr <<
"Probably you asked for a compartment report for a synapse variable and "
66 "there are many synapses attached to the soma.\nThis is not allowed since "
67 "compartment reports require 1 and only 1 variable on every segment.\n";
80 static void fill_segment_id_2_node_id(
82 std::unordered_map<
int, std::vector<int>>& segment_id_2_node_id) {
86 if (!segment_id_2_node_id.empty()) {
92 segment_id_2_node_id[segment_id].push_back(
j);
105 static double* get_one_var(
const NrnThread& nt,
107 const std::string& var_name,
108 const std::string& mech_name,
109 const int segment_id,
110 std::unordered_map<int, int> segment_id_2_node_id,
112 if (mech_name ==
"i_membrane") {
113 return nt.nrn_fast_imem->nrn_sav_rhs + segment_id;
115 if (mech_name ==
"v") {
116 return nt._actual_v + segment_id;
120 std::cerr <<
"Mechanism (" << mech_id <<
", " << var_name <<
", " << mech_name
122 std::cerr <<
"Negative mech_id\n";
129 std::cerr <<
"Mechanism (" << mech_id <<
", " << var_name <<
", " << mech_name
131 std::cerr <<
"NULL Memb_list\n";
136 fill_segment_id_2_node_id(ml, segment_id_2_node_id);
138 const auto it = segment_id_2_node_id.find(segment_id);
141 if (it == segment_id_2_node_id.end()) {
142 std::cerr <<
"Mechanism (" << mech_id <<
", " << var_name <<
", " << mech_name
143 <<
") not found at gid: " << gid <<
" segment: " << segment_id << std::endl;
144 std::cerr <<
"The nodeindices (size: " << ml->
nodecount <<
") are:\n[";
152 const int node_id = it->second;
156 if (ans ==
nullptr) {
158 <<
"get_var_location_from_var_name failed to retrieve a valid pointer for mechanism ("
159 << mech_id <<
", " << var_name <<
", " << mech_name <<
") at gid: " << gid
160 <<
" segment: " << segment_id << std::endl;
175 static std::vector<double*> get_vars(
178 const std::string& var_name,
179 const std::string& mech_name,
180 const int segment_id,
181 std::unordered_map<
int, std::vector<int>>& segment_id_2_node_ids) {
182 if (mech_name ==
"i_membrane") {
183 return {nt.nrn_fast_imem->nrn_sav_rhs + segment_id};
185 if (mech_name ==
"v") {
186 return {nt._actual_v + segment_id};
200 fill_segment_id_2_node_id(ml, segment_id_2_node_ids);
202 const auto it = segment_id_2_node_ids.find(segment_id);
205 if (it == segment_id_2_node_ids.end()) {
209 const std::vector<int>& node_ids = it->second;
211 std::vector<double*> ans;
212 for (
auto node_id: node_ids) {
227 static double get_scaling_factor(
const std::string& mech_name,
230 const int segment_id) {
232 if (mech_name ==
"IClamp" || mech_name ==
"SEClamp") {
237 return (*(nt._actual_area + segment_id)) / 100.0;
243 static void append_sections_to_to_report_auto_variable(
244 const std::shared_ptr<SecMapping>& sections,
245 std::vector<VarWithMapping>& to_report,
246 const ReportConfiguration& report_conf,
248 std::unordered_map<int, int>& segment_id_2_node_id,
251 nrn_assert(report_conf.var_names.size() == 1);
252 nrn_assert(report_conf.mech_names.size() == 1);
254 const auto& mech_id = report_conf.mech_ids[0];
255 const auto& var_name = report_conf.var_names[0];
256 const auto& mech_name = report_conf.mech_names[0];
257 for (
const auto& section: sections->secmap) {
259 int section_id = section.first;
260 const auto& segment_ids = section.second;
264 for (
const auto& segment_id: segment_ids) {
266 nt, mech_id, var_name, mech_name, segment_id, segment_id_2_node_id, gid);
267 to_report.emplace_back(VarWithMapping(section_id, variable));
271 "Section with an even number of compartments. I cannot pick the middle one. "
272 "This was not expected");
274 const auto segment_id = segment_ids[segment_ids.size() / 2];
276 nt, mech_id, var_name, mech_name, segment_id, segment_id_2_node_id, gid);
277 to_report.emplace_back(VarWithMapping(section_id, variable));
279 std::cerr <<
"[ERROR] Invalid compartments type: "
280 <<
to_string(report_conf.compartments) <<
" in report: " << report_conf.name
289 static void append_sections_to_to_report(
const std::shared_ptr<SecMapping>& sections,
290 std::vector<VarWithMapping>& to_report,
291 double* report_variable,
292 const ReportConfiguration& report_conf) {
293 for (
const auto& section: sections->secmap) {
295 int section_id = section.first;
296 const auto& segment_ids = section.second;
300 for (
const auto& segment_id: segment_ids) {
302 double*
variable = report_variable + segment_id;
303 to_report.emplace_back(VarWithMapping(section_id, variable));
307 "Section with an even number of compartments. I cannot pick the middle one. "
308 "This was not expected");
310 const auto segment_id = segment_ids[segment_ids.size() / 2];
311 double*
variable = report_variable + segment_id;
312 to_report.emplace_back(VarWithMapping(section_id, variable));
314 std::cerr <<
"[ERROR] Invalid compartments type: "
315 <<
to_string(report_conf.compartments) <<
" in report: " << report_conf.name
324 static std::vector<int> get_intersection_ids(
const NrnThread& nt, std::vector<int>& target_gids) {
325 std::unordered_set<int> thread_gids;
326 for (
int i = 0;
i < nt.
ncell;
i++) {
327 thread_gids.insert(nt.presyns[
i].gid_);
329 std::vector<int> intersection_ids;
330 intersection_ids.reserve(target_gids.size());
332 for (
auto i = 0;
i < target_gids.size(); ++
i) {
333 const auto gid = target_gids[
i];
334 if (thread_gids.find(gid) != thread_gids.end()) {
335 intersection_ids.push_back(
i);
339 intersection_ids.shrink_to_fit();
340 return intersection_ids;
344 static VarsToReport get_compartment_set_vars_to_report(
const NrnThread& nt,
345 const std::vector<int>& intersection_ids,
346 const ReportConfiguration& report) {
351 "[ERROR] : Compartment report `sections` should be Invalid");
353 "[ERROR] : Compartment report `compartments` should be Invalid");
355 nrn_assert(report.target.size() == report.point_compartment_ids.size());
356 nrn_assert(report.target.size() == report.point_section_ids.size());
358 const auto& mech_id = report.mech_ids[0];
359 const auto& var_name = report.var_names[0];
360 const auto& mech_name = report.mech_names[0];
362 VarsToReport vars_to_report;
363 const auto*
mapinfo =
static_cast<NrnThreadMappingInfo*
>(nt.mapping);
365 std::cerr <<
"[ERROR] : Compartment report mapping information is missing for a Cell group "
371 std::unordered_map<int, int> segment_id_2_node_id;
372 for (
const auto& intersection_id: intersection_ids) {
373 const auto gid = report.target[intersection_id];
374 const auto section_id = report.point_section_ids[intersection_id];
375 auto compartment_id = report.point_compartment_ids[intersection_id];
377 node_permute(&compartment_id, 1, nt._permute);
380 if (old_gid != gid) {
382 segment_id_2_node_id.clear();
386 nt, mech_id, var_name, mech_name, compartment_id, segment_id_2_node_id, gid);
388 vars_to_report[gid].emplace_back(section_id, variable);
391 return vars_to_report;
395 static VarsToReport get_section_vars_to_report(
const NrnThread& nt,
396 const std::vector<int>& intersection_ids,
397 const ReportConfiguration& report) {
399 "[ERROR] : Compartment report `sections` should not be Invalid");
401 "[ERROR] : Compartment report `compartments` should not be Invalid");
402 VarsToReport vars_to_report;
403 const auto*
mapinfo =
static_cast<NrnThreadMappingInfo*
>(nt.mapping);
405 std::cerr <<
"[ERROR] : Compartment report mapping information is missing for a Cell group "
410 for (
const auto& intersection_id: intersection_ids) {
411 const auto gid = report.target[intersection_id];
412 std::unordered_map<int, int> segment_id_2_node_id;
414 if (cell_mapping ==
nullptr) {
415 std::cerr <<
"[ERROR] : Compartment report mapping information is missing for gid "
419 std::vector<VarWithMapping> to_report;
420 to_report.reserve(cell_mapping->size());
423 const auto& section_mapping = cell_mapping->sec_mappings;
424 for (
const auto& sections: section_mapping) {
425 append_sections_to_to_report_auto_variable(
426 sections, to_report, report, nt, segment_id_2_node_id, gid);
430 if (cell_mapping->get_seclist_section_count(report.sections) > 0) {
431 const auto& sections = cell_mapping->get_seclist_mapping(report.sections);
432 append_sections_to_to_report_auto_variable(
433 sections, to_report, report, nt, segment_id_2_node_id, gid);
436 to_report.shrink_to_fit();
437 vars_to_report[gid] = to_report;
439 return vars_to_report;
443 static VarsToReport get_summation_vars_to_report(
const NrnThread& nt,
444 const std::vector<int>& intersection_ids,
445 const ReportConfiguration& report) {
446 VarsToReport vars_to_report;
447 const auto*
mapinfo =
static_cast<NrnThreadMappingInfo*
>(nt.mapping);
448 auto& summation_report = nt.summation_report_handler_->summation_reports_[report.output_path];
451 std::cerr <<
"[ERROR] : Compartment report mapping information is missing for a Cell group "
456 for (
const auto& intersection_id: intersection_ids) {
457 const auto gid = report.target[intersection_id];
460 if (cell_mapping ==
nullptr) {
461 std::cerr <<
"[ERROR] : Summation report mapping information is missing for gid " << gid
467 for (
auto i = 0;
i < report.mech_ids.size(); ++
i) {
468 const auto& mech_id = report.mech_ids[
i];
469 const auto& var_name = report.var_names[
i];
470 const auto& mech_name = report.mech_names[
i];
471 std::unordered_map<int, std::vector<int>> segment_id_2_node_ids;
473 const auto& section_mapping = cell_mapping->sec_mappings;
474 for (
const auto& sections: section_mapping) {
475 for (
auto& section: sections->secmap) {
476 int section_id = section.first;
477 auto& segment_ids = section.second;
479 for (
const auto& segment_id: segment_ids) {
480 double scaling_factor =
481 get_scaling_factor(mech_name, report.scaling, nt, segment_id);
486 if (scaling_factor == 0.0) {
490 const std::vector<double*> var_ptrs = get_vars(
491 nt, mech_id, var_name, mech_name, segment_id, segment_id_2_node_ids);
492 for (
auto var_ptr: var_ptrs) {
493 summation_report.currents_[segment_id].push_back(
494 std::make_pair(var_ptr, scaling_factor));
501 std::vector<VarWithMapping> to_report;
502 to_report.reserve(cell_mapping->size());
503 summation_report.summation_.resize(nt.
end);
504 double* report_variable = summation_report.summation_.data();
506 "ReportHandler::get_summation_vars_to_report: sections should not be Invalid");
509 if (cell_mapping->get_seclist_section_count(report.sections) > 0) {
510 const auto& sections = cell_mapping->get_seclist_mapping(report.sections);
511 append_sections_to_to_report(sections, to_report, report_variable, report);
515 const auto& section_mapping = cell_mapping->sec_mappings;
516 for (
const auto& sections: section_mapping) {
517 for (
auto& section: sections->secmap) {
519 int section_id = section.first;
520 auto& segment_ids = section.second;
521 for (
const auto& segment_id: segment_ids) {
523 double*
variable = report_variable + segment_id;
524 to_report.emplace_back(VarWithMapping(section_id, variable));
526 summation_report.gid_segments_[gid].push_back(segment_id);
531 vars_to_report[gid] = to_report;
534 return vars_to_report;
537 static VarsToReport get_synapse_vars_to_report(
const NrnThread& nt,
538 const std::vector<int>& intersection_ids,
539 const ReportConfiguration& report) {
543 const auto& mech_id = report.mech_ids[0];
544 const auto& mech_name = report.mech_names[0];
545 const auto& var_name = report.var_names[0];
546 VarsToReport vars_to_report;
548 const auto*
mapinfo =
static_cast<NrnThreadMappingInfo*
>(nt.mapping);
549 for (
const auto& intersection_id: intersection_ids) {
550 const auto gid = report.target[intersection_id];
553 if (cell_mapping ==
nullptr) {
554 std::cerr <<
"[ERROR] : Synapse report mapping information is missing for gid " << gid
560 for (
auto i = 0;
i < report.mech_ids.size(); ++
i) {
561 std::unordered_map<int, std::vector<int>> segment_id_2_node_ids;
563 const auto& section_mapping = cell_mapping->sec_mappings;
564 for (
const auto& sections: section_mapping) {
565 for (
auto& section: sections->secmap) {
566 int section_id = section.first;
567 auto& segment_ids = section.second;
568 for (
const auto& segment_id: segment_ids) {
569 const std::vector<double*> selected_vars = get_vars(nt,
571 "selected_for_report",
574 segment_id_2_node_ids);
575 const std::vector<double*> var_ptrs = get_vars(
576 nt, mech_id, var_name, mech_name, segment_id, segment_id_2_node_ids);
577 const std::vector<double*> synapseIDs = get_vars(
578 nt, mech_id,
"synapseID", mech_name, segment_id, segment_id_2_node_ids);
580 nrn_assert(var_ptrs.size() == synapseIDs.size());
582 selected_vars.size() == var_ptrs.size());
584 for (
auto i = 0;
i < var_ptrs.size(); ++
i) {
585 if (selected_vars.empty() ||
static_cast<bool>(selected_vars[
i])) {
586 vars_to_report[gid].push_back(
587 {
static_cast<int>(*synapseIDs[
i]), var_ptrs[
i]});
595 return vars_to_report;
598 static VarsToReport get_lfp_vars_to_report(
const NrnThread& nt,
599 const std::vector<int>& intersection_ids,
600 ReportConfiguration& report,
601 double* report_variable) {
602 const auto*
mapinfo =
static_cast<NrnThreadMappingInfo*
>(nt.mapping);
604 std::cerr <<
"[ERROR] : LFP report mapping information is missing for a Cell group "
608 auto& summation_report = nt.summation_report_handler_->summation_reports_[report.output_path];
609 VarsToReport vars_to_report;
610 std::size_t offset_lfp = 0;
611 for (
const auto& intersection_id: intersection_ids) {
612 const auto gid = report.target[intersection_id];
614 if (cell_mapping ==
nullptr) {
615 std::cerr <<
"[ERROR] : LFP report mapping information is missing for gid " << gid
619 std::vector<VarWithMapping> to_report;
620 int num_electrodes = cell_mapping->num_electrodes();
621 for (
int electrode_id = 0; electrode_id < num_electrodes; electrode_id++) {
622 to_report.emplace_back(VarWithMapping(electrode_id, report_variable + offset_lfp));
625 if (!to_report.empty()) {
626 vars_to_report[gid] = to_report;
629 return vars_to_report;
640 #ifdef ENABLE_SONATA_REPORTS
641 if (report_config.
start <
t) {
644 report_config.
stop = std::min(report_config.
stop, tstop);
646 for (
const auto& mech: report_config.
mech_names) {
650 std::cerr <<
"[ERROR] Synapse report mechanism to report: " << report_config.
mech_names[0]
651 <<
" is not mapped in this simulation, cannot report on it \n";
662 const std::vector<int> intersection_ids = get_intersection_ids(nt, report_config.
target);
663 VarsToReport vars_to_report;
665 switch (report_config.
type) {
667 vars_to_report = get_section_vars_to_report(nt, intersection_ids, report_config);
668 register_section_report(nt, report_config, vars_to_report, is_soma_target);
673 get_compartment_set_vars_to_report(nt, intersection_ids, report_config);
674 register_section_report(nt, report_config, vars_to_report, is_soma_target);
678 vars_to_report = get_summation_vars_to_report(nt, intersection_ids, report_config);
679 register_custom_report(nt, report_config, vars_to_report);
685 get_lfp_vars_to_report(nt, intersection_ids, report_config,
mapinfo->_lfp.data());
686 register_section_report(nt, report_config, vars_to_report, is_soma_target);
690 vars_to_report = get_synapse_vars_to_report(nt, intersection_ids, report_config);
691 register_custom_report(nt, report_config, vars_to_report);
695 std::cerr <<
"[ERROR] Unknown report type: " <<
to_string(report_config.
type) <<
'\n';
700 if (!vars_to_report.empty()) {
701 auto report_event = std::make_unique<ReportEvent>(
dt,
708 m_report_events.push_back(
std::move(report_event));
714 std::cerr <<
"[WARNING] : Reporting is disabled. Please recompile with libsonata.\n";
virtual void create_report(ReportConfiguration &config, double dt, double tstop, double delay)
double var(InputIterator begin, InputIterator end)
void move(Item *q1, Item *q2, Item *q3)
THIS FILE IS AUTO GENERATED DONT MODIFY IT.
void nrn_abort(int errcode)
double * get_var_location_from_var_name(int mech_id, const std::string_view mech_name, const std::string_view variable_name, Memb_list *ml, int node_index)
int nrn_get_mechtype(const char *name)
Get mechanism type by the mechanism name.
std::string to_string(EnumT e, const std::array< std::pair< EnumT, std::string_view >, N > &mapping, const std::string_view enum_name)
Converts an enum value to its corresponding string representation.
NetCvode * net_cvode_instance
#define nrn_assert(x)
assert()-like macro, independent of NDEBUG status
NrnMappingInfo mapinfo
mapping information
A view into a set of mechanism instances.
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.
Compartment mapping information for NrnThread.
std::vector< int > target
std::vector< std::string > mech_names
std::vector< int > mech_ids