@@ -16,9 +16,9 @@ class Model;
16
16
class BackwardProblem ;
17
17
18
18
/* *
19
- * @brief Computes the weighted root mean square norm.
19
+ * @brief Computes the weighted root- mean- square norm.
20
20
*
21
- * This class is used to compute the weighted root mean square of the residuals
21
+ * This class is used to compute the weighted root- mean- square of the residuals
22
22
* and maintains its work space to avoid reallocation.
23
23
*/
24
24
class WRMSComputer {
@@ -41,7 +41,7 @@ class WRMSComputer {
41
41
, mask_(mask) {}
42
42
43
43
/* *
44
- * @brief Compute the weighted root mean square of the residuals.
44
+ * @brief Compute the weighted root- mean- square of the residuals.
45
45
* @param x Vector to compute the WRMS for.
46
46
* @param x_ref The reference vector from which to compute the error
47
47
* weights.
@@ -66,30 +66,67 @@ class WRMSComputer {
66
66
/* *
67
67
* @brief Implements Newton's method for finding steady states.
68
68
*
69
- * TODO: To be extended after further disentangling SteadyStateProblem.
69
+ * See also:
70
+ * Lines et al. (2019), IFAC-PapersOnLine 52 (26): 32–37.
71
+ * https://doi.org/10.1016/j.ifacol.2019.12.232
70
72
*/
71
73
class NewtonsMethod {
72
74
public:
73
75
/* *
74
76
* @brief Constructor.
75
- * @param nx Number of solver states (nx_solver).
77
+ * @param model Number of solver states (nx_solver).
78
+ * @param solver NewtonSolver instance to compute the Newton step.
79
+ * Expected to be correctly initialized.
76
80
* @param sunctx A SUNDIALS context for the NVector.
77
81
* @param max_steps
78
82
* @param damping_factor_mode
79
83
* @param damping_factor_lower_bound
84
+ * @param check_delta
80
85
*/
81
86
NewtonsMethod (
82
- int nx, SUNContext sunctx,
87
+ gsl::not_null<Model*> model, SUNContext sunctx,
88
+ gsl::not_null<NewtonSolver*> solver,
83
89
NewtonDampingFactorMode damping_factor_mode,
84
- realtype damping_factor_lower_bound,
85
- int max_steps
86
- )
87
- : max_steps_(max_steps)
88
- , delta_(nx, sunctx)
89
- , delta_old_(nx, sunctx)
90
- , damping_factor_mode_(damping_factor_mode)
91
- , damping_factor_lower_bound_(damping_factor_lower_bound) {}
90
+ realtype damping_factor_lower_bound, int max_steps, bool check_delta
91
+ );
92
+
93
+ /* *
94
+ * @brief Run the Newton solver iterations and checks for convergence
95
+ * to steady state.
96
+ * @param xdot Time derivative of the state vector `state.x`.
97
+ * @param state SimulationState instance containing the current state.
98
+ * @param wrms_computer WRMSComputer instance to compute the WRMS norm.
99
+ */
100
+ void
101
+ run (AmiVector& xdot, SimulationState& state, WRMSComputer& wrms_computer);
102
+
103
+ /* *
104
+ * @brief Compute the Newton step for the current state_.x and xdot and
105
+ * store it in delta_.
106
+ * @param xdot Time derivative of the state vector `state.x`.
107
+ * @param state SimulationState instance containing the current state.
108
+ */
109
+ void compute_step (AmiVector const & xdot, SimulationState const & state);
110
+
111
+ /* *
112
+ * @brief Get the last Newton step.
113
+ * @return Newton step
114
+ */
115
+ [[nodiscard]] AmiVector const & get_delta () const { return delta_; }
116
+
117
+ /* *
118
+ * @brief Get the number of steps taken in the current iteration.
119
+ * @return Number of steps taken.
120
+ */
121
+ [[nodiscard]] int get_num_steps () const { return i_step; }
122
+
123
+ /* *
124
+ * @brief Get the current WRMS norm.
125
+ * @return The current WRMS norm.
126
+ */
127
+ [[nodiscard]] realtype get_wrms () const { return wrms_; }
92
128
129
+ private:
93
130
/* *
94
131
* @brief Update the damping factor gamma that determines step size.
95
132
*
@@ -101,43 +138,76 @@ class NewtonsMethod {
101
138
* dampening (false)
102
139
*/
103
140
104
- bool updateDampingFactor (bool step_successful, double & gamma) {
105
- if (damping_factor_mode_ != NewtonDampingFactorMode::on)
106
- return true ;
107
-
108
- if (step_successful) {
109
- gamma = fmin (1.0 , 2.0 * gamma);
110
- } else {
111
- gamma /= 4.0 ;
112
- }
113
-
114
- if (gamma < damping_factor_lower_bound_) {
115
- throw NewtonFailure (
116
- AMICI_DAMPING_FACTOR_ERROR,
117
- " Newton solver failed: the damping factor "
118
- " reached its lower bound"
119
- );
120
- }
121
- return step_successful;
122
- }
141
+ bool update_damping_factor (bool step_successful, double & gamma);
142
+
143
+ /* *
144
+ * @brief Compute the weighted root-mean-square of the residuals.
145
+ * @param xdot
146
+ * @param state
147
+ * @param wrms_computer
148
+ * @return WRMS norm.
149
+ */
150
+ realtype compute_wrms (
151
+ AmiVector const & xdot, SimulationState const & state,
152
+ WRMSComputer& wrms_computer
153
+ );
154
+
155
+ /* *
156
+ * @brief Check for convergence.
157
+ *
158
+ * Check if NewtonsMethod::wrms_ is below the convergence threshold,
159
+ * make the state non-negative if requested, and recompute and check
160
+ * the WRMS norm again.
161
+ *
162
+ * @param xdot
163
+ * @param state
164
+ * @param wrms_computer
165
+ * @return Whether convergence has been reached.
166
+ */
167
+ bool has_converged (
168
+ AmiVector& xdot, SimulationState& state, WRMSComputer& wrms_computer
169
+ );
170
+
171
+ static constexpr realtype conv_thresh = 1.0 ;
123
172
124
- // TODO: make private after further disentangling SteadyStateProblem
173
+ /* * Pointer to the model instance. */
174
+ gsl::not_null<Model*> model_;
125
175
126
176
/* * Maximum number of iterations. */
127
177
int max_steps_{0 };
128
178
179
+ /* * damping factor flag */
180
+ NewtonDampingFactorMode damping_factor_mode_{NewtonDampingFactorMode::on};
181
+
182
+ /* * damping factor lower bound */
183
+ realtype damping_factor_lower_bound_{1e-8 };
184
+
185
+ /* *
186
+ * Whether to check the Newton step (delta) or the right-hand side (xdot)
187
+ * during the convergence check.
188
+ */
189
+ bool check_delta_;
190
+
191
+ /* * Pointer to the Newton solver instance to compute the Newton step. */
192
+ gsl::not_null<NewtonSolver*> solver_;
193
+
129
194
/* * Newton step (size: nx_solver). */
130
195
AmiVector delta_;
131
196
132
- /* * previous newton step (size: nx_solver). */
197
+ /* * Previous Newton step (size: nx_solver). */
133
198
AmiVector delta_old_;
134
199
135
- private:
136
- /* * damping factor flag */
137
- NewtonDampingFactorMode damping_factor_mode_{NewtonDampingFactorMode::on};
200
+ /* * Newton step (size: nx_solver). */
201
+ AmiVector x_old_;
138
202
139
- /* * damping factor lower bound */
140
- realtype damping_factor_lower_bound_{1e-8 };
203
+ /* *
204
+ * WRMS norm based on the current state and delta or xdot
205
+ * (depending on `check_delta_`).
206
+ */
207
+ realtype wrms_ = INFINITY;
208
+
209
+ /* * The current number of Newton iterations. */
210
+ int i_step = 0 ;
141
211
};
142
212
143
213
/* *
@@ -152,7 +222,7 @@ class SteadystateProblem {
152
222
* @param solver Solver instance
153
223
* @param model Model instance
154
224
*/
155
- explicit SteadystateProblem (Solver const & solver, Model const & model);
225
+ explicit SteadystateProblem (Solver const & solver, Model& model);
156
226
157
227
/* *
158
228
* @brief Compute the steady state in the forward case.
@@ -219,7 +289,7 @@ class SteadystateProblem {
219
289
}
220
290
221
291
/* *
222
- * @brief Get the CPU time taken to solvethe forward problem.
292
+ * @brief Get the CPU time taken to solve the forward problem.
223
293
* @return The CPU time in milliseconds.
224
294
*/
225
295
[[nodiscard]] double getCPUTime () const { return cpu_time_; }
@@ -248,7 +318,7 @@ class SteadystateProblem {
248
318
249
319
/* *
250
320
* @brief Get the weighted root mean square of the residuals.
251
- * @return The weighted root mean square of the residuals.
321
+ * @return The weighted root- mean- square of the residuals.
252
322
*/
253
323
[[nodiscard]] realtype getResidualNorm () const { return wrms_; }
254
324
@@ -305,7 +375,7 @@ class SteadystateProblem {
305
375
/* *
306
376
* @brief Handle the computation of the steady state.
307
377
*
308
- * Throws an AmiException, if no steady state was found.
378
+ * Throws an AmiException if no steady state was found.
309
379
*
310
380
* @param solver Solver instance.
311
381
* @param model Model instance.
@@ -398,15 +468,7 @@ class SteadystateProblem {
398
468
realtype getWrmsFSA (Model& model);
399
469
400
470
/* *
401
- * @brief Run the Newton solver iterations and checks for convergence
402
- * to steady state.
403
- * @param model Model instance.
404
- * @param newton_retry flag indicating if Newton solver is rerun
405
- */
406
- void applyNewtonsMethod (Model& model, bool newton_retry);
407
-
408
- /* *
409
- * @brief Launch forward simulation if Newton solver or linear system solve
471
+ * @brief Launch simulation if Newton solver or linear system solve
410
472
* fail or are disabled.
411
473
* @param solver Solver instance.
412
474
* @param model Model instance.
@@ -428,7 +490,7 @@ class SteadystateProblem {
428
490
* @param solver Solver instance
429
491
* @param model Model instance.
430
492
* @param forwardSensis flag switching on integration with FSA
431
- * @param backward flag switching on quadratures computation
493
+ * @param backward flag switching on quadrature computation
432
494
* @return A unique pointer to the created Solver instance.
433
495
*/
434
496
std::unique_ptr<Solver> createSteadystateSimSolver (
@@ -447,21 +509,13 @@ class SteadystateProblem {
447
509
* @brief Initialize backward computation.
448
510
* @param solver Solver instance
449
511
* @param model Model instance.
450
- * @param bwd pointer to backward problem
512
+ * @param bwd pointer to the backward problem
451
513
* @return flag indicating whether backward computation to be carried out
452
514
*/
453
515
bool initializeBackwardProblem (
454
516
Solver const & solver, Model& model, BackwardProblem const * bwd
455
517
);
456
518
457
- /* *
458
- * @brief Ensure state positivity if requested, and repeat the convergence
459
- * check if necessary.
460
- * @param model Model instance.
461
- */
462
- bool makePositiveAndCheckConvergence (Model& model);
463
-
464
-
465
519
/* *
466
520
* @brief Update member variables to indicate that state_.x has been
467
521
* updated and xdot_, delta_, etc. need to be recomputed.
@@ -482,13 +536,6 @@ class SteadystateProblem {
482
536
*/
483
537
void updateRightHandSide (Model& model);
484
538
485
- /* *
486
- * @brief Compute the Newton step for the current state_.x and set the
487
- * corresponding flag to indicate delta_ is up to date.
488
- * @param model Model instance
489
- */
490
- void getNewtonStep (Model& model);
491
-
492
539
/* * WRMS computer for x */
493
540
WRMSComputer wrms_computer_x_;
494
541
/* * WRMS computer for xQB */
@@ -548,7 +595,10 @@ class SteadystateProblem {
548
595
/* * Newton's method for finding steady states */
549
596
NewtonsMethod newtons_method_;
550
597
551
- /* * whether newton step should be used for convergence steps */
598
+ /* *
599
+ * Whether the Newton step should be used instead of xdot for convergence
600
+ * checks during simulation and Newton's method.
601
+ */
552
602
bool newton_step_conv_{false };
553
603
/* *
554
604
* whether sensitivities should be checked for convergence to steady state
@@ -557,10 +607,6 @@ class SteadystateProblem {
557
607
558
608
/* * flag indicating whether xdot_ has been computed for the current state */
559
609
bool xdot_updated_{false };
560
- /* *
561
- * flag indicating whether delta_ has been computed for the current state
562
- */
563
- bool delta_updated_{false };
564
610
/* *
565
611
* flag indicating whether simulation sensitivities have been retrieved for
566
612
* the current state
0 commit comments