NEURON
newton_thread.hpp
Go to the documentation of this file.
1 /*
2 # =============================================================================
3 # Originally newton.c from SCoP library, Copyright (c) 1987-90 Duke University
4 # =============================================================================
5 # Subsequent extensive prototype and memory layout changes for CoreNEURON
6 #
7 # Copyright (c) 2016 - 2022 Blue Brain Project/EPFL
8 #
9 # See top-level LICENSE file for details.
10 # =============================================================================.
11 */
12 #pragma once
16 
17 #include <algorithm>
18 #include <cmath>
19 
20 namespace coreneuron {
21 #if defined(scopmath_newton_ix) || defined(scopmath_newton_s) || defined(scopmath_newton_x)
22 #error "naming clash on newton_thread.hpp-internal macros"
23 #endif
24 #define scopmath_newton_ix(arg) CNRN_FLAT_INDEX_IML_ROW(arg)
25 #define scopmath_newton_s(arg) _p[CNRN_FLAT_INDEX_IML_ROW(s[arg])]
26 #define scopmath_newton_x(arg) _p[CNRN_FLAT_INDEX_IML_ROW(arg)]
27 namespace detail {
28 /**
29  * @brief Calculate the Jacobian matrix using finite central differences.
30  *
31  * Creates the Jacobian matrix by computing partial derivatives by finite
32  * central differences. If the column variable is nonzero, an increment of 2% of
33  * the variable is used. STEP is the minimum increment allowed; it is currently
34  * set to 1.0E-6.
35  *
36  * @param n number of variables
37  * @param x pointer to array of addresses of the solution vector elements
38  * @param p array of parameter values
39  * @param func callable that computes the deviation from zero of each equation
40  * in the model
41  * @param value pointer to array of addresses of function values
42  * @param[out] jacobian computed jacobian matrix
43  */
44 template <typename F>
46  int n,
47  int* index,
48  F const& func,
49  double* value,
50  double** jacobian,
52  double* high_value = ns->high_value;
53  double* low_value = ns->low_value;
54 
55  /* Compute partial derivatives by central finite differences */
56 
57  for (int j = 0; j < n; j++) {
58  double increment = std::max(std::fabs(0.02 * (scopmath_newton_x(index[j]))), STEP);
59  scopmath_newton_x(index[j]) += increment;
60  func(_threadargs_); // std::invoke in C++17
61  for (int i = 0; i < n; i++)
63  scopmath_newton_x(index[j]) -= 2.0 * increment;
64  func(_threadargs_); // std::invoke in C++17
65  for (int i = 0; i < n; i++) {
67 
68  /* Insert partials into jth column of Jacobian matrix */
69 
70  jacobian[i][scopmath_newton_ix(j)] = (high_value[scopmath_newton_ix(i)] -
71  low_value[scopmath_newton_ix(i)]) /
72  (2.0 * increment);
73  }
74 
75  /* Restore original variable and function values. */
76 
77  scopmath_newton_x(index[j]) += increment;
78  func(_threadargs_); // std::invoke in C++17
79  }
80 }
81 #undef scopmath_newton_x
82 } // namespace detail
83 
84 /**
85  * Iteratively solves simultaneous nonlinear equations by Newton's method, using
86  * a Jacobian matrix computed by finite differences.
87  *
88  * @return 0 if no error; 2 if matrix is singular or ill-conditioned; 1 if
89  * maximum iterations exceeded.
90  * @param n number of variables to solve for
91  * @param x pointer to array of the solution vector elements possibly indexed by
92  * index
93  * @param p array of parameter values
94  * @param func callable that computes the deviation from zero of each equation
95  * in the model
96  * @param value pointer to array to array of the function values
97  * @param[out] x contains the solution value or the most recent iteration's
98  * result in the event of an error.
99  */
100 template <typename F>
102  int n,
103  int* s,
104  F func,
105  double* value,
107  int count = 0, error = 0;
108  double change = 1.0, max_dev, temp;
109  int done = 0;
110  /*
111  * Create arrays for Jacobian, variable increments, function values, and
112  * permutation vector
113  */
114  double* delta_x = ns->delta_x;
115  double** jacobian = ns->jacobian;
116  int* perm = ns->perm;
117  /* Iteration loop */
118  while (!done) {
119  if (count++ >= MAXITERS) {
121  done = 2;
122  }
123  if (!done && change > MAXCHANGE) {
124  /*
125  * Recalculate Jacobian matrix if solution has changed by more
126  * than MAXCHANGE
127  */
129  for (int i = 0; i < n; i++)
130  value[scopmath_newton_ix(i)] = -value[scopmath_newton_ix(i)]; /* Required correction
131  * to
132  * function values */
134  if (error != SUCCESS) {
135  done = 2;
136  }
137  }
138 
139  if (!done) {
140  nrn_scopmath_solve_thread(n, jacobian, value, perm, delta_x, (int*) 0, _threadargs_);
141 
142  /* Update solution vector and compute norms of delta_x and value */
143 
144  change = 0.0;
145  if (s) {
146  for (int i = 0; i < n; i++) {
147  if (std::fabs(scopmath_newton_s(i)) > ZERO &&
148  (temp = std::fabs(delta_x[scopmath_newton_ix(i)] /
149  (scopmath_newton_s(i)))) > change)
150  change = temp;
151  scopmath_newton_s(i) += delta_x[scopmath_newton_ix(i)];
152  }
153  } else {
154  for (int i = 0; i < n; i++) {
155  if (std::fabs(scopmath_newton_s(i)) > ZERO &&
156  (temp = std::fabs(delta_x[scopmath_newton_ix(i)] /
157  (scopmath_newton_s(i)))) > change)
158  change = temp;
159  scopmath_newton_s(i) += delta_x[scopmath_newton_ix(i)];
160  }
161  }
162  // Evaulate function values with new solution.
163  func(_threadargs_); // std::invoke in C++17
164  max_dev = 0.0;
165  for (int i = 0; i < n; i++) {
166  value[scopmath_newton_ix(i)] = -value[scopmath_newton_ix(i)]; /* Required correction
167  * to function
168  * values */
169  if ((temp = std::fabs(value[scopmath_newton_ix(i)])) > max_dev)
170  max_dev = temp;
171  }
172 
173  /* Check for convergence or maximum iterations */
174 
175  if (change <= CONVERGE && max_dev <= ZERO) {
176  // break;
177  done = 1;
178  }
179  }
180  } /* end of while loop */
181 
182  return (error);
183 }
184 #undef scopmath_newton_ix
185 #undef scopmath_newton_s
186 
187 NewtonSpace* nrn_cons_newtonspace(int n, int n_instance);
188 void nrn_destroy_newtonspace(NewtonSpace* ns);
189 } // namespace coreneuron
#define i
Definition: md1redef.h:19
static double jacobian(void *v)
Definition: cvodeobj.cpp:245
#define MAXITERS
Definition: errcodes.h:37
#define EXCEED_ITERS
Definition: errcodes.h:49
#define STEP
Definition: errcodes.h:33
#define MAXCHANGE
Definition: errcodes.h:35
#define CONVERGE
Definition: errcodes.h:34
#define SUCCESS
Definition: errcodes.h:48
#define ZERO
Definition: errcodes.h:32
double(* func)(double)
Definition: hoc_init.cpp:85
#define _threadargsproto_
#define _threadargs_
fabs
Definition: extdef.h:3
error
Definition: extdef.h:3
void nrn_buildjacobian_thread(NewtonSpace *ns, int n, int *index, F const &func, double *value, double **jacobian, _threadargsproto_)
Calculate the Jacobian matrix using finite central differences.
THIS FILE IS AUTO GENERATED DONT MODIFY IT.
int nrn_newton_thread(NewtonSpace *ns, int n, int *s, F func, double *value, _threadargsproto_)
Iteratively solves simultaneous nonlinear equations by Newton's method, using a Jacobian matrix compu...
void nrn_scopmath_solve_thread(int n, double **a, double *b, int *perm, double *p, int *y, _threadargsproto_)
Performs forward substitution algorithm to transform the constant vector in the linear simultaneous e...
NewtonSpace * nrn_cons_newtonspace(int n, int n_instance)
int nrn_crout_thread(NewtonSpace *ns, int n, double **a, int *perm, _threadargsproto_)
Performs an LU triangular factorization of a real matrix by the Crout algorithm using partial pivotin...
void nrn_destroy_newtonspace(NewtonSpace *ns)
#define scopmath_newton_s(arg)
#define scopmath_newton_ix(arg)
#define scopmath_newton_x(arg)
int const size_t const size_t n
Definition: nrngsl.h:10
size_t j
s
Definition: multisend.cpp:521
short index
Definition: cabvars.h:11
static double done(void *v)
Definition: ocbbs.cpp:251
static uint32_t value
Definition: scoprand.cpp:25