NEURON
lfp.cpp
Go to the documentation of this file.
1 /*
2 # =============================================================================
3 # Copyright (c) 2016 - 2022 Blue Brain Project/EPFL
4 #
5 # See top-level LICENSE file for details.
6 # =============================================================================.
7 */
8 #include "coreneuron/io/lfp.hpp"
11 #include "coreneuron/mpi/nrnmpi.h"
12 
13 #include <catch2/catch_test_macros.hpp>
14 #include <catch2/matchers/catch_matchers_floating_point.hpp>
15 
16 #include <iostream>
17 
18 using namespace coreneuron;
19 using namespace coreneuron::lfputils;
20 
21 template <typename F>
22 double integral(F f, double a, double b, int n) {
23  double step = (b - a) / n; // width of each small rectangle
24  double area = 0.0; // signed area
25  for (int i = 0; i < n; i++) {
26  area += f(a + (i + 0.5) * step) * step; // sum up each small rectangle
27  }
28  return area;
29 }
30 
31 
32 TEST_CASE("LFP_PointSource_LineSource") {
33 #if NRNMPI
34  nrnmpi_init(nullptr, nullptr, false);
35 #endif
36  double segment_length{1.0e-6};
37  double segment_start_val{1.0e-6};
38  std::array<double, 3> segment_start = std::array<double, 3>{0.0, 0.0, segment_start_val};
39  std::array<double, 3> segment_end =
40  paxpy(segment_start, 1.0, std::array<double, 3>{0.0, 0.0, segment_length});
41  double floor{1.0e-6};
42  pi = 3.141592653589;
43 
44  std::array<double, 10> vals;
45  double circling_radius{1.0e-6};
46  std::array<double, 3> segment_middle{0.0, 0.0, 1.5e-6};
47  double medium_resistivity_fac{1.0};
48  for (auto k = 0; k < 10; k++) {
49  std::array<double, 3> approaching_elec =
50  paxpy(segment_middle, 1.0, std::array<double, 3>{0.0, 1.0e-5 - k * 1.0e-6, 0.0});
51  std::array<double, 3> circling_elec =
52  paxpy(segment_middle,
53  1.0,
54  std::array<double, 3>{0.0,
55  circling_radius * std::cos(2.0 * pi * k / 10),
56  circling_radius * std::sin(2.0 * pi * k / 10)});
57 
58  double analytic_approaching_lfp = line_source_lfp_factor(
59  approaching_elec, segment_start, segment_end, floor, medium_resistivity_fac);
60  double analytic_circling_lfp = line_source_lfp_factor(
61  circling_elec, segment_start, segment_end, floor, medium_resistivity_fac);
62  double numeric_circling_lfp = integral(
63  [&](double x) {
64  return 1.0 / std::max(floor,
65  norm(paxpy(circling_elec,
66  -1.0,
67  paxpy(segment_end,
68  x,
69  paxpy(segment_start, -1.0, segment_end)))));
70  },
71  0.0,
72  1.0,
73  10000);
74  // TEST of analytic vs numerical integration
75  std::clog << "ANALYTIC line source " << analytic_circling_lfp
76  << " vs NUMERIC line source LFP " << numeric_circling_lfp << "\n";
77  REQUIRE_THAT(analytic_circling_lfp,
78  Catch::Matchers::WithinRel(numeric_circling_lfp,
79  std::numeric_limits<float>::epsilon() * 100.));
80  // TEST of LFP Flooring
81  if (approaching_elec[1] < 0.866e-6) {
82  REQUIRE(analytic_approaching_lfp == 1.0e6);
83  }
84  vals[k] = analytic_circling_lfp;
85  }
86  // TEST of SYMMETRY of LFP FORMULA
87  for (size_t k = 0; k < 5; k++) {
88  REQUIRE(std::abs((vals[k] - vals[k + 5]) /
89  std::max(std::abs(vals[k]), std::abs(vals[k + 5]))) < 1.0e-12);
90  }
91  std::vector<std::array<double, 3>> segments_starts = {{0., 0., 1.},
92  {0., 0., 0.5},
93  {0.0, 0.0, 0.0},
94  {0.0, 0.0, -0.5}};
95  std::vector<std::array<double, 3>> segments_ends = {{0., 0., 0.},
96  {0., 0., 1.},
97  {0., 0., 0.5},
98  {0.0, 0.0, 0.0}};
99  std::vector<double> radii{0.1, 0.1, 0.1, 0.1};
100  std::vector<std::array<double, 3>> electrodes = {{0.0, 0.3, 0.0}, {0.0, 0.7, 0.8}};
101  std::vector<int> indices = {0, 1, 2, 3};
102  LFPCalculator<LineSource> lfp(segments_starts, segments_ends, radii, indices, electrodes, 1.0);
103  lfp.template lfp<std::vector<double>>({0.0, 1.0, 2.0, 3.0});
104  std::vector<double> res_line_source = lfp.lfp_values();
106  segments_starts, segments_ends, radii, indices, electrodes, 1.0);
107  lfpp.template lfp<std::vector<double>>({0.0, 1.0, 2.0, 3.0});
108  std::vector<double> res_point_source = lfpp.lfp_values();
109  REQUIRE_THAT(res_line_source[0], Catch::Matchers::WithinAbs(res_point_source[0], 1.0));
110  REQUIRE_THAT(res_line_source[1], Catch::Matchers::WithinAbs(res_point_source[1], 1.0));
111 #if NRNMPI
112  nrnmpi_finalize();
113 #endif
114 }
115 
116 #ifdef ENABLE_SONATA_REPORTS
117 #define CATCH_CONFIG_MAIN
118 
119 TEST_CASE("LFP_ReportEvent") {
120  const std::string report_name = "compartment_report";
121  const std::vector<uint64_t> gids = {42, 134};
122  const std::vector<int> segment_ids = {0, 1, 2, 3, 4};
123  std::vector<double> curr(segment_ids.size());
124 
125  NrnThread nt;
126  nt.mapping = new NrnThreadMappingInfo;
127  auto* mapinfo = static_cast<NrnThreadMappingInfo*>(nt.mapping);
128  // Generate mapinfo CellMapping
129  for (const auto& gid: gids) {
130  mapinfo->mappingvec.push_back(new CellMapping(gid));
131  for (const auto& segment: segment_ids) {
132  std::vector<double> lfp_factors{segment + 1.0, segment + 2.0};
133  mapinfo->mappingvec.back()->add_segment_lfp_factor(segment, lfp_factors);
134  }
135  }
136  mapinfo->prepare_lfp();
137  // Total number of electrodes 2 gids * 2 factors
138 
139  CellMapping* c42 = mapinfo->mappingvec[0];
140  CellMapping* c134 = mapinfo->mappingvec[1];
141  REQUIRE(c42->lfp_factors.size() == 5);
142  REQUIRE(c134->num_electrodes() == 2);
143 
144  // Pass _lfp variable to vars_to_report
145  size_t offset_lfp = 0;
146  VarsToReport vars_to_report;
147  for (const auto& gid: gids) {
148  std::vector<VarWithMapping> to_report;
149  const auto& cell_mapping = mapinfo->get_cell_mapping(gid);
150  int num_electrodes = cell_mapping->num_electrodes();
151  for (int electrode_id = 0; electrode_id < num_electrodes; electrode_id++) {
152  to_report.emplace_back(VarWithMapping(electrode_id, mapinfo->_lfp.data() + offset_lfp));
153  offset_lfp++;
154  }
155  if (!to_report.empty()) {
156  vars_to_report[gid] = to_report;
157  }
158  }
159 
160  // Generate summation for IClamp
161  nt.summation_report_handler_ = std::make_unique<SummationReportMapping>(
163  for (const auto& segment_id: segment_ids) {
164  curr[segment_id] = (segment_id + 1) / 10.0;
165  nt.summation_report_handler_->summation_reports_[report_name]
166  .currents_[segment_id]
167  .push_back(std::make_pair(curr.data() + segment_id, -1));
168  }
169 
170  // Generate currents
171  std::vector<double> currents = {0.2, 0.4, 0.6, 0.8, 1.0};
172  nt.nrn_fast_imem = new NrnFastImem;
173  nt.nrn_fast_imem->nrn_sav_rhs = currents.data();
174 
175  const double dt = 0.025;
176  const double tstart = 0.0;
177  const double report_dt = 0.1;
178  ReportType report_type = CompartmentReport;
179 
180  ReportEvent event(dt, tstart, vars_to_report, report_name.data(), report_dt, report_type);
181  event.lfp_calc(&nt);
182 
183  REQUIRE_THAT(mapinfo->_lfp[0], Catch::Matchers::WithinAbs(5.5, 1.0));
184  REQUIRE_THAT(mapinfo->_lfp[3], Catch::Matchers::WithinAbs(7.0, 1.0));
185 
186  delete mapinfo;
187  delete nt.nrn_fast_imem;
188 }
189 #endif
#define area
Definition: md1redef.h:12
#define i
Definition: md1redef.h:19
static RNG::key_type k
Definition: nrnran123.cpp:9
floor
Definition: extdef.h:4
sin
Definition: extdef.h:3
cos
Definition: extdef.h:3
step
Definition: extdef.h:7
Point3D paxpy(const Point3D &p1, const double alpha, const Point3D &p2)
Definition: lfp.hpp:30
double norm(const Point3D &p1)
Definition: lfp.hpp:22
double line_source_lfp_factor(const Point3D &e_pos, const Point3D &seg_0, const Point3D &seg_1, const double radius, const double f)
Definition: lfp.cpp:12
THIS FILE IS AUTO GENERATED DONT MODIFY IT.
@ CompartmentReport
Definition: nrnreport.hpp:75
List * currents
Definition: nocpout.cpp:124
NrnMappingInfo mapinfo
mapping information
int const size_t const size_t n
Definition: nrngsl.h:10
void nrnmpi_init(int nrnmpi_under_nrncontrol, int *pargc, char ***pargv)
Definition: nrnmpi.cpp:55
CellMapping * get_cell_mapping(int gid)
get cell mapping information for given gid if exist otherwise return NULL.
Compartment mapping information for a cell.
std::unordered_map< int, std::vector< double > > lfp_factors
map containing segment ids an its respective lfp factors
int num_electrodes() const
return the number of electrodes in the lfp_factors map
LFPCalculator allows calculation of LFP given membrane currents.
Definition: lfp.hpp:72
const std::vector< double > & lfp_values() const noexcept
Definition: lfp.hpp:93
NrnFastImem * nrn_fast_imem
Definition: multicore.hpp:124
std::unique_ptr< SummationReportMapping > summation_report_handler_
Definition: multicore.hpp:144
Compartment mapping information for NrnThread.
double integral(F f, double a, double b, int n)
Definition: lfp.cpp:22
TEST_CASE("LFP_PointSource_LineSource")
Definition: lfp.cpp:32