• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In
You are now the owner of this repo.

nasa / trick / 25459968639

06 May 2026 08:42PM UTC coverage: 55.916% (-0.8%) from 56.7%
25459968639

Pull #2011

github

web-flow
Merge f11412d5f into 7054e405e
Pull Request #2011: Single-file CI and code style adoption

14607 of 26123 relevant lines covered (55.92%)

466416.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

38.21
/trick_source/trick_utils/SAIntegrator/src/SAIntegrator.cpp
1

2
#include <stdlib.h>
3
#include <math.h>
4
#include <stdexcept>
5
#include <iostream>  // std::cout, std::cerr
6
#include <algorithm> // std::copy
7
#include "SAIntegrator.hh"
8

9
static void nil_dfunc( double x,
×
10
                       double state[] __attribute__((unused)),
11
                       double derivs[],
12
                       void*  udata __attribute__((unused))) {
13
    derivs[0] = 0.0;
×
14
}
×
15
static void nil_gfunc( double t,
×
16
                       double x[] __attribute__((unused)),
17
                       double v[] __attribute__((unused)),
18
                       double derivs[],
19
                       void*  udata __attribute__((unused))) {
20
    derivs[0] = 0.0;
×
21
}
×
22
// ------------------------------------------------------------
23
// Class Integrator
24
// ------------------------------------------------------------
25
// Default Constructor
26
SA::Integrator::Integrator()
1✔
27
: X_in(0.0), X_out(0.0), default_h(1.0), user_data(NULL) {};
1✔
28
// Constructor
29
SA::Integrator::Integrator(double h, void* udata)
23✔
30
: X_in(0.0), X_out(0.0), default_h(h), user_data(udata) {};
23✔
31

32
void SA::Integrator::advanceIndyVar() {
27✔
33
    X_out = X_in + default_h;
27✔
34
}
27✔
35
void SA::Integrator::step() {
7✔
36
    advanceIndyVar();
7✔
37
}
7✔
38
void SA::Integrator::load() {
1,654✔
39
    X_in = X_out;
1,654✔
40
}
1,654✔
41
void SA::Integrator::unload() {
5✔
42
    std::cout << "SA::Integrator : Nothing to unload." << std::endl;
5✔
43
}
5✔
44
void SA::Integrator::integrate() {
611✔
45
    load();
611✔
46
    step();
611✔
47
    unload();
611✔
48
}
611✔
49
double SA::Integrator::undo_integrate() {
4✔
50
    X_out = X_in;
4✔
51
    return (default_h);
4✔
52
}
53
double SA::Integrator::getIndyVar() {
43✔
54
    return X_out;
43✔
55
}
56
void SA::Integrator::setIndyVar(double v) {
8✔
57
    X_out = v;
8✔
58
}
8✔
59
// Insertion Operator
60
std::ostream& SA::operator<<(std::ostream& os, const Integrator& I) {
18✔
61
    os << "\n--- Integrator ---";
18✔
62
    os << "\nX_in      : " << I.X_in;
18✔
63
    os << "\nX_out     : " << I.X_out;
18✔
64
    os << "\ndefault_h : " << I.default_h;
18✔
65
    os << "\nuser_data : " << I.user_data;
18✔
66
    return os;
18✔
67
}
68

69
// ------------------------------------------------------------
70
// Class FirstOrderODEIntegrator
71
// ------------------------------------------------------------
72
// Default Constructor
73
SA::FirstOrderODEIntegrator::FirstOrderODEIntegrator()
1✔
74
: Integrator() {
1✔
75
    state_size = 0;
1✔
76
    inVars = NULL;
1✔
77
    outVars = NULL;
1✔
78
    inState = new double[state_size];
1✔
79
    outState = new double[state_size];
1✔
80
    derivs_func = nil_dfunc;
1✔
81
}
1✔
82
// Constructor
83
SA::FirstOrderODEIntegrator::FirstOrderODEIntegrator(
17✔
84
    double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc dfunc, void* udata)
17✔
85
: Integrator(h, udata) {
17✔
86
    state_size = N;
17✔
87
    inVars = in_vars;
17✔
88
    outVars = out_vars;
17✔
89
    inState = new double[state_size];
17✔
90
    outState = new double[state_size];
17✔
91
    if (dfunc == NULL) throw std::invalid_argument("dfunc must be non-NULL.");
17✔
92
    derivs_func = dfunc;
17✔
93
}
17✔
94
// Copy Constructor
95
SA::FirstOrderODEIntegrator::FirstOrderODEIntegrator(const FirstOrderODEIntegrator& other)
26✔
96
: Integrator(other) {
26✔
97
    state_size = other.state_size;
26✔
98
    inVars = other.inVars;
26✔
99
    outVars = other.outVars;
26✔
100
    inState = new double[state_size];
26✔
101
    std::copy( other.inState, other.inState + state_size, inState);
26✔
102
    outState = new double[state_size];
26✔
103
    std::copy( other.outState, other.outState + state_size, outState);
26✔
104
    derivs_func = other.derivs_func;
26✔
105
}
26✔
106
// Assignment Operator
107
SA::FirstOrderODEIntegrator& SA::FirstOrderODEIntegrator::operator=( const SA::FirstOrderODEIntegrator& rhs) {
1✔
108
    if (this != &rhs) {
1✔
109
        // Call base assignment operator
110
        Integrator::operator=(rhs);
1✔
111
        // Duplicate rhs arrays
112
        double* new_inState = new double[rhs.state_size];
1✔
113
        std::copy( rhs.inState, rhs.inState + rhs.state_size, new_inState);
1✔
114
        double* new_outState = new double[rhs.state_size];
1✔
115
        std::copy( rhs.outState, rhs.outState + rhs.state_size, new_outState);
1✔
116
        // Delete lhs arrays & replace with rhs arrays
117
        if (inState != NULL) delete inState;
1✔
118
        inState = new_inState;
1✔
119
        if (outState != NULL) delete outState;
1✔
120
        outState = new_outState;
1✔
121
        // Copy primitive members
122
        state_size = rhs.state_size;
1✔
123
        inVars = rhs.inVars;
1✔
124
        outVars = rhs.outVars;
1✔
125
        derivs_func = rhs.derivs_func;
1✔
126
    }
127
    return *this;
1✔
128
}
129
// Destructor
130
SA::FirstOrderODEIntegrator::~FirstOrderODEIntegrator() {
44✔
131
    if (inState != NULL) delete inState;
44✔
132
    if (outState != NULL) delete outState;
44✔
133
}
44✔
134
void SA::FirstOrderODEIntegrator::load() {
1,637✔
135
    if (inVars != NULL) {
1,637✔
136
        for (unsigned int i=0 ; i<state_size; i++ ) {
8,143✔
137
            inState[i] = *(inVars[i]);
6,506✔
138
        }
139
        Integrator::load();
1,637✔
140
    } else {
141
        std::cerr << "Error: SA::FirstOrderODEIntegrator::load(). inVars is not set." << std::endl;
×
142
    }
143
}
1,637✔
144
void SA::FirstOrderODEIntegrator::unload() {
1,636✔
145
    if (outVars != NULL) {
1,636✔
146
        for (unsigned int i=0 ; i<state_size; i++ ) {
8,138✔
147
            *(outVars[i]) = outState[i];
6,502✔
148
        }
149
    } else {
150
        std::cerr << "Error: SA::FirstOrderODEIntegrator::load(). outVars is not set." << std::endl;
×
151
    }
152
}
1,636✔
153
void SA::FirstOrderODEIntegrator::load_from_outState(){
10✔
154
    for (unsigned int i=0 ; i<state_size; i++ ) {
50✔
155
        inState[i] = outState[i];
40✔
156
    }
157
    Integrator::load();
10✔
158
}
10✔
159
double** SA::FirstOrderODEIntegrator::set_in_vars( double* in_vars[]){
×
160
    double **ret = inVars;
×
161
    inVars = in_vars;
×
162
    return (ret);
×
163
}
164
double** SA::FirstOrderODEIntegrator::set_out_vars( double* out_vars[]){
2✔
165
    double **ret = outVars;
2✔
166
    outVars = out_vars;
2✔
167
    return (ret);
2✔
168
}
169
double SA::FirstOrderODEIntegrator::undo_integrate() {
3✔
170
    if (inVars != NULL) {
3✔
171
        for (unsigned int i=0 ; i<state_size; i++ ) {
15✔
172
            *(inVars[i]) = inState[i];
12✔
173
        }
174
        std::copy(inState, inState + state_size, outState);
3✔
175
        return (SA::Integrator::undo_integrate());
3✔
176
    } else {
177
        std::cerr << "Error: SA::FirstOrderODEIntegrator::load(). inVars is not set." << std::endl;
×
178
    }
179
    return (0.0);
×
180
}
181
void SA::FirstOrderODEIntegrator::step() {
20✔
182
    double derivs[state_size];
20✔
183
    (*derivs_func)( X_in, inState, derivs, user_data);
20✔
184
    for (unsigned int i=0; i<state_size; i++) {
100✔
185
        outState[i] = inState[i] + derivs[i] * default_h;
80✔
186
    }
187
    advanceIndyVar();
20✔
188
}
40✔
189

190
static std::ostream& stream_double_array(std::ostream& os, unsigned int n, double* d_array) {
28✔
191
    if (d_array == NULL) {
28✔
192
        os << " NULL\n";
×
193
    } else {
194
        os << "[";
28✔
195
        for (int i=0; i<n ; i++) {
140✔
196
            if (i==0) { os << d_array[i]; }
112✔
197
            else { os << " ," << d_array[i]; }
84✔
198
        }
199
        os << "]";
28✔
200
    }
201
    return os;
28✔
202
}
203
// Insertion Operator
204
std::ostream& SA::operator<<(std::ostream& os, const FirstOrderODEIntegrator& I) {
14✔
205
        os << (SA::Integrator)I;
14✔
206
        os << "\n--- FirstOrderODEIntegrator ---";
14✔
207
        os << "\nstate_size: " << I.state_size;
14✔
208
        os << "\ninState   :";
14✔
209
        stream_double_array(os, I.state_size, I.inState);
14✔
210
        os << "\noutState  :";
14✔
211
        stream_double_array(os, I.state_size, I.outState);
14✔
212
        os << "\ninVars    : " << (void*)I.inVars;
14✔
213
        os << "\noutVars   : " << (void*)I.outVars;
14✔
214
        return os;
14✔
215
}
216

217
// ------------------------------------------------------------
218
// Class FirstOrderODEVariableStepIntegrator
219
// ------------------------------------------------------------
220
// Default Constructor
221
SA::FirstOrderODEVariableStepIntegrator::FirstOrderODEVariableStepIntegrator()
1✔
222
: FirstOrderODEIntegrator() {
1✔
223
    root_finder = (RootFinder*) NULL;
1✔
224
    root_error_func = (RootErrorFunc) NULL;
1✔
225
}
1✔
226
// Constructor
227
SA::FirstOrderODEVariableStepIntegrator::FirstOrderODEVariableStepIntegrator(
9✔
228
    double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc dfunc, void* udata)
9✔
229
: FirstOrderODEIntegrator(h, N, in_vars, out_vars, dfunc, udata) {
9✔
230
    root_finder = (RootFinder*) NULL;
9✔
231
    root_error_func = (RootErrorFunc) NULL;
9✔
232
}
9✔
233

234
// Copy Constructor
235
SA::FirstOrderODEVariableStepIntegrator::FirstOrderODEVariableStepIntegrator(
14✔
236
const FirstOrderODEVariableStepIntegrator& other)
14✔
237
: FirstOrderODEIntegrator(other) {
14✔
238
    if (other.root_finder != NULL) {
14✔
239
        root_finder = new RootFinder(*(other.root_finder));
×
240
    } else {
241
        root_finder = NULL;
14✔
242
    }
243
    root_error_func = other.root_error_func;
14✔
244
}
14✔
245
// Assignment Operator
246
SA::FirstOrderODEVariableStepIntegrator& SA::
1✔
247
FirstOrderODEVariableStepIntegrator::operator=( const SA::FirstOrderODEVariableStepIntegrator& rhs) {
248
    FirstOrderODEIntegrator::operator=(rhs);
1✔
249
    if (root_finder != NULL) delete root_finder;
1✔
250
    if (rhs.root_finder != NULL) {
1✔
251
        root_finder = new RootFinder(*(rhs.root_finder));
×
252
    } else {
253
        root_finder = NULL;
1✔
254
    }
255
    root_error_func = rhs.root_error_func;
1✔
256
    return *this;
1✔
257
}
258
// Destructor
259
SA::FirstOrderODEVariableStepIntegrator::~FirstOrderODEVariableStepIntegrator() {
24✔
260
    if (root_finder != NULL) {
24✔
261
        delete root_finder;
×
262
    }
263
}
24✔
264
double SA::FirstOrderODEVariableStepIntegrator::undo_integrate() {
2✔
265
    SA::FirstOrderODEIntegrator::undo_integrate();
2✔
266
    return (last_h);
2✔
267
}
268
void SA::FirstOrderODEVariableStepIntegrator::add_Rootfinder( double tolerance, SlopeConstraint constraint, RootErrorFunc rfunc) {
×
269
    root_finder = new RootFinder(tolerance, constraint);
×
270
    if (rfunc == NULL) {
×
271
        throw std::invalid_argument("OOPS! RootErrorFunc function-pointer is NULL.");
×
272
    }
273
    root_error_func = rfunc;
×
274
}
×
275
void SA::FirstOrderODEVariableStepIntegrator::advanceIndyVar(double h) {
1,602✔
276
    last_h = h; X_out = X_in + h;
1,602✔
277
}
1,602✔
278
void SA::FirstOrderODEVariableStepIntegrator::variable_step( double h) {
×
279
    double derivs[state_size];
×
280
    (*derivs_func)( X_in, inState, derivs, user_data);
×
281
    for (unsigned int i=0; i<state_size; i++) {
×
282
        outState[i] = inState[i] + derivs[i] * h;
×
283
    }
284
    advanceIndyVar(h);
×
285
}
×
286
void SA::FirstOrderODEVariableStepIntegrator::find_roots(double h, unsigned int depth) {
×
287
    double new_h;
288
    double h_correction = (*root_error_func)( getIndyVar(), outState, root_finder, user_data );
×
289
    if (h_correction < 0.0) {
×
290
        while (h_correction != 0.0) {
×
291
            new_h = undo_integrate() + h_correction;
×
292
            variable_step(new_h);
×
293
            h_correction = (*root_error_func)( getIndyVar(), outState, root_finder, user_data );
×
294
        }
295
        load_from_outState();
×
296
        variable_step(h-new_h);
×
297
        if (depth > 0) {
×
298
            find_roots(h-new_h, depth-1);
×
299
        }
300
    }
301
}
×
302
void SA::FirstOrderODEVariableStepIntegrator::step() {
1,602✔
303
    variable_step( default_h );
1,602✔
304
    if ((root_finder != NULL) && (root_error_func != NULL)) {
1,602✔
305
        find_roots( default_h, 5 );
×
306
    }
307
}
1,602✔
308
// Insertion Operator
309
std::ostream& SA::operator<<(std::ostream& os, const FirstOrderODEVariableStepIntegrator& I) {
10✔
310
    os << (SA::FirstOrderODEIntegrator)I;
10✔
311
    os << "\n--- FirstOrderODEVariableStepIntegrator ---";
10✔
312
    if (I.root_error_func == NULL) {
10✔
313
        os << "\nroot_error_func: NULL.";
10✔
314
    } else {
315
        os << "\nroot_error_func: " << (void*)I.root_error_func;
×
316
    }
317
    if (I.root_finder == NULL) {
10✔
318
        os << "\nroot_finder: NULL.";
10✔
319
    } else {
320
        os << "\nroot_finder -> " << *(I.root_finder);
×
321
    }
322
    return os;
10✔
323
}
324

325
// ------------------------------------------------------------
326
// Class EulerIntegrator
327
// ------------------------------------------------------------
328
// Default Constructor
329
SA::EulerIntegrator::EulerIntegrator()
×
330
: FirstOrderODEVariableStepIntegrator() {}
×
331
// Constructor
332
SA::EulerIntegrator::EulerIntegrator(
2✔
333
    double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc dfunc, void* udata)
2✔
334
    : FirstOrderODEVariableStepIntegrator(h, N, in_vars, out_vars, dfunc, udata) {}
2✔
335
// Constructor
336
SA::EulerIntegrator::EulerIntegrator(
×
337
double h, unsigned int N, double* in_out_vars[], DerivsFunc dfunc, void* udata)
×
338
: EulerIntegrator(h, N, in_out_vars, in_out_vars, dfunc, udata) {}
×
339
// Copy Constructor
340
SA::EulerIntegrator::EulerIntegrator(const EulerIntegrator& other)
×
341
    : FirstOrderODEVariableStepIntegrator(other) {}
×
342
// Assignment Operator
343
SA::EulerIntegrator& SA::EulerIntegrator::operator=( const SA::EulerIntegrator& rhs) {
×
344
    if (this != &rhs) {
×
345
        FirstOrderODEVariableStepIntegrator::operator=(rhs);
×
346
    }
347
    return *this;
×
348
}
349
//Destructor
350
SA::EulerIntegrator::~EulerIntegrator() {}
2✔
351

352
void SA::EulerIntegrator::variable_step( double h) {
202✔
353
    double derivs[state_size];
202✔
354
    (*derivs_func)( X_in, inState, derivs, user_data);
202✔
355
    for (unsigned int i=0; i<state_size; i++) {
1,010✔
356
        outState[i] = inState[i] + derivs[i] * h;
808✔
357
    }
358
    advanceIndyVar(h);
202✔
359
}
404✔
360

361
// Insertion Operator
362
std::ostream& SA::operator<<(std::ostream& os, const EulerIntegrator& I) {
×
363
    os << (SA::FirstOrderODEVariableStepIntegrator)I;
×
364
    return os;
×
365
}
366
// ------------------------------------------------------------
367
// Class HeunsMethod
368
// ------------------------------------------------------------
369
// Default Constructor
370
SA::HeunsMethod::HeunsMethod()
×
371
: FirstOrderODEVariableStepIntegrator() {}
×
372
// Constructor
373
SA::HeunsMethod::HeunsMethod(
×
374
    double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc dfunc, void* udata)
×
375
    : FirstOrderODEVariableStepIntegrator(h, N, in_vars, out_vars, dfunc, udata) {}
×
376
// Constructor
377
SA::HeunsMethod::HeunsMethod(
×
378
double h, unsigned int N, double* in_out_vars[], DerivsFunc dfunc, void* udata)
×
379
: HeunsMethod(h, N, in_out_vars, in_out_vars, dfunc, udata) {}
×
380
// Copy Constructor
381
SA::HeunsMethod::HeunsMethod(const HeunsMethod& other)
×
382
    : FirstOrderODEVariableStepIntegrator(other) {}
×
383
// Assignment Operator
384
SA::HeunsMethod& SA::HeunsMethod::operator=( const SA::HeunsMethod& rhs) {
×
385
    if (this != &rhs) {
×
386
        FirstOrderODEVariableStepIntegrator::operator=(rhs);
×
387
    }
388
    return *this;
×
389
}
390
// Destructor
391
SA::HeunsMethod::~HeunsMethod() {}
×
392
void SA::HeunsMethod::variable_step( double h) {
×
393
    double wstate[state_size];
×
394
    double derivs[2][state_size];
×
395

396
    (*derivs_func)( X_in, inState, derivs[0], user_data);
×
397
    for (unsigned int i=0; i<state_size; i++) {
×
398
        wstate[i] = inState[i] + h * derivs[0][i];
×
399
    }
400
    (*derivs_func)( X_in, wstate, derivs[1], user_data);
×
401
    for (unsigned int i=0; i<state_size; i++) {
×
402
        outState[i] = inState[i] + (h/2) * ( derivs[0][i] +  derivs[1][i] );
×
403
    }
404
    advanceIndyVar(h);
×
405
}
×
406

407
// Insertion Operator
408
std::ostream& SA::operator<<(std::ostream& os, const HeunsMethod& I) {
×
409
    os << (SA::FirstOrderODEVariableStepIntegrator)I;
×
410
    return os;
×
411
}
412
// ------------------------------------------------------------
413
// Class RK2Integrator
414
// ------------------------------------------------------------
415
// Default Constructor
416
SA::RK2Integrator::RK2Integrator()
1✔
417
    : FirstOrderODEVariableStepIntegrator() {}
1✔
418
// Constructor
419
SA::RK2Integrator::RK2Integrator(
4✔
420
    double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc dfunc, void* udata)
4✔
421
    : FirstOrderODEVariableStepIntegrator(h, N, in_vars, out_vars, dfunc, udata) {}
4✔
422
SA::RK2Integrator::RK2Integrator(
×
423
double h, unsigned int N, double* in_out_vars[], DerivsFunc dfunc, void* udata)
×
424
: RK2Integrator(h, N, in_out_vars, in_out_vars, dfunc, udata) {}
×
425
// Copy Constructor
426
SA::RK2Integrator::RK2Integrator(const RK2Integrator& other)
1✔
427
    : FirstOrderODEVariableStepIntegrator(other) {}
1✔
428
// Assignment Operator
429
SA::RK2Integrator& SA::RK2Integrator::operator=( const SA::RK2Integrator& rhs) {
1✔
430
    if (this != &rhs) {
1✔
431
        FirstOrderODEVariableStepIntegrator::operator=(rhs);
1✔
432
    }
433
    return *this;
1✔
434
}
435
// Destructor
436
SA::RK2Integrator::~RK2Integrator() {}
6✔
437

438
void SA::RK2Integrator::variable_step( double h) {
800✔
439
    double wstate[state_size];
800✔
440
    double derivs[2][state_size];
800✔
441
    (*derivs_func)( X_in, inState, derivs[0], user_data);
800✔
442
    for (unsigned int i=0; i<state_size; i++) {
4,000✔
443
        wstate[i] = inState[i] + 0.5 * h * derivs[0][i];
3,200✔
444
    }
445
    (*derivs_func)( X_in + 0.5 * h , wstate, derivs[1], user_data);
800✔
446
    for (unsigned int i=0; i<state_size; i++) {
4,000✔
447
        outState[i] = inState[i] + h * derivs[1][i];
3,200✔
448
    }
449
    advanceIndyVar(h);
800✔
450
}
1,600✔
451

452
// Insertion Operator
453
std::ostream& SA::operator<<(std::ostream& os, const RK2Integrator& I) {
4✔
454
    os << (SA::FirstOrderODEVariableStepIntegrator)I;
4✔
455
    return os;
4✔
456
}
457
// ------------------------------------------------------------
458
// Class RK4Integrator
459
// ------------------------------------------------------------
460
// Default Constructor
461
SA::RK4Integrator::RK4Integrator()
×
462
    : FirstOrderODEVariableStepIntegrator() {}
×
463
// Constructor
464
SA::RK4Integrator::RK4Integrator(
1✔
465
    double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc dfunc, void* udata)
1✔
466
    : FirstOrderODEVariableStepIntegrator(h, N, in_vars, out_vars, dfunc, udata) {}
1✔
467
// Constructor
468
SA::RK4Integrator::RK4Integrator(
×
469
double h, unsigned int N, double* in_out_vars[], DerivsFunc dfunc, void* udata)
×
470
: RK4Integrator(h, N, in_out_vars, in_out_vars, dfunc, udata) {}
×
471
// Copy Constructor
472
SA::RK4Integrator::RK4Integrator(const RK4Integrator& other)
1✔
473
    : FirstOrderODEVariableStepIntegrator(other) {}
1✔
474
// Assignment Operator
475
SA::RK4Integrator& SA::RK4Integrator::operator=( const SA::RK4Integrator& rhs) {
×
476
    if (this != &rhs) {
×
477
        FirstOrderODEVariableStepIntegrator::operator=(rhs);
×
478
    }
479
    return *this;
×
480
}
481
// Destructor
482
SA::RK4Integrator::~RK4Integrator() {}
2✔
483

484
void SA::RK4Integrator::variable_step( double h) {
200✔
485
    double wstate[3][state_size];
200✔
486
    double derivs[4][state_size];
200✔
487

488
    (*derivs_func)( X_in, inState, derivs[0], user_data);
200✔
489
    for (unsigned int i=0; i<state_size; i++) {
1,000✔
490
        wstate[0][i] = inState[i] + 0.5 * derivs[0][i] * h;
800✔
491
    }
492
    (*derivs_func)( X_in + 0.5 * h , wstate[0], derivs[1], user_data);
200✔
493
    for (unsigned int i=0; i<state_size; i++) {
1,000✔
494
        wstate[1][i] = inState[i] + 0.5 * derivs[1][i] * h;
800✔
495
    }
496
    (*derivs_func)( X_in + 0.5 * h , wstate[1], derivs[2], user_data);
200✔
497
    for (unsigned int i=0; i<state_size; i++) {
1,000✔
498
        wstate[2][i] = inState[i] + derivs[2][i] * h;
800✔
499
    }
500
    (*derivs_func)( X_in + h , wstate[2], derivs[3], user_data);
200✔
501
    for (unsigned int i=0; i<state_size; i++) {
1,000✔
502
        outState[i] = inState[i] + ((1/6.0)* derivs[0][i] +
800✔
503
                                 (1/3.0)* derivs[1][i] +
800✔
504
                                 (1/3.0)* derivs[2][i] +
800✔
505
                                 (1/6.0)* derivs[3][i]) * h;
800✔
506
    }
507
    advanceIndyVar(h);
200✔
508
}
400✔
509

510
// Insertion Operator
511
std::ostream& SA::operator<<(std::ostream& os, const RK4Integrator& I) {
2✔
512
    os << (SA::FirstOrderODEVariableStepIntegrator)I;
2✔
513
    return os;
2✔
514
}
515
// ------------------------------------------------------------
516
// Class RK3_8Integrator
517
// ------------------------------------------------------------
518
// Default Constructor
519
SA::RK3_8Integrator::RK3_8Integrator()
×
520
    : FirstOrderODEVariableStepIntegrator() {}
×
521
// Constructor
522
SA::RK3_8Integrator::RK3_8Integrator(
2✔
523
    double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc dfunc, void* udata)
2✔
524
    : FirstOrderODEVariableStepIntegrator(h, N, in_vars, out_vars ,dfunc, udata) {}
2✔
525
// Constructor
526
SA::RK3_8Integrator::RK3_8Integrator(
×
527
double h, unsigned int N, double* in_out_vars[], DerivsFunc dfunc, void* udata)
×
528
: RK3_8Integrator(h, N, in_out_vars, in_out_vars, dfunc, udata) {}
×
529
// Copy Constructor
530
SA::RK3_8Integrator::RK3_8Integrator(const RK3_8Integrator& other)
2✔
531
    : FirstOrderODEVariableStepIntegrator(other) {}
2✔
532
// Assignment Operator
533
SA::RK3_8Integrator& SA::RK3_8Integrator::operator=( const SA::RK3_8Integrator& rhs) {
×
534
    if (this != &rhs) {
×
535
        FirstOrderODEVariableStepIntegrator::operator=(rhs);
×
536
    }
537
    return *this;
×
538
}
539
// Destructor
540
SA::RK3_8Integrator::~RK3_8Integrator() {}
4✔
541

542
void SA::RK3_8Integrator::variable_step( double h) {
400✔
543
    double wstate[3][state_size];
400✔
544
    double derivs[4][state_size];
400✔
545

546
    (*derivs_func)( X_in, inState, derivs[0], user_data);
400✔
547
    for (unsigned int i=0; i<state_size; i++) {
2,000✔
548
        wstate[0][i] = inState[i] + h * (1/3.0) * derivs[0][i];
1,600✔
549
    }
550
    (*derivs_func)( X_in + (1/3.0) * h , wstate[0], derivs[1], user_data);
400✔
551
    for (unsigned int i=0; i<state_size; i++) {
2,000✔
552
        wstate[1][i] = inState[i] + h * ((-1/3.0) * derivs[0][i] + derivs[1][i]);
1,600✔
553
    }
554
    (*derivs_func)( X_in + (2/3.0) * h , wstate[1], derivs[2], user_data);
400✔
555
    for (unsigned int i=0; i<state_size; i++) {
2,000✔
556
        wstate[2][i] = inState[i] + h * (derivs[0][i] - derivs[1][i] + derivs[2][i]);
1,600✔
557
    }
558
    (*derivs_func)( X_in + h , wstate[2], derivs[3], user_data);
400✔
559
    for (unsigned int i=0; i<state_size; i++) {
2,000✔
560
        outState[i] = inState[i] + ((1/8.0)* derivs[0][i] +
1,600✔
561
                                 (3/8.0)* derivs[1][i] +
1,600✔
562
                                 (3/8.0)* derivs[2][i] +
1,600✔
563
                                 (1/8.0)* derivs[3][i]) * h;
1,600✔
564
    }
565
    advanceIndyVar(h);
400✔
566
}
800✔
567

568
// Insertion Operator
569
std::ostream& SA::operator<<(std::ostream& os, const RK3_8Integrator& I) {
4✔
570
    os << (SA::FirstOrderODEVariableStepIntegrator)I;
4✔
571
    return os;
4✔
572
}
573

574
// ------------------------------------------------------------
575
// Class RKF45Integrator
576
// ------------------------------------------------------------
577
// Default Constructor
578
SA::RKF45Integrator::RKF45Integrator() : FirstOrderODEIntegrator() {
×
579
    epsilon = 0.00000000001;
×
580
    next_h = default_h;
×
581
}
×
582
// Constructor
583
SA::RKF45Integrator::RKF45Integrator(double eps,
2✔
584
    double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc dfunc, void* udata)
2✔
585
    : FirstOrderODEIntegrator(h, N, in_vars, out_vars, dfunc, udata) {
2✔
586
        epsilon = eps;
2✔
587
        next_h = h;
2✔
588
    }
2✔
589
// Constructor
590
SA::RKF45Integrator::RKF45Integrator(double eps,
2✔
591
double h, unsigned int N, double* in_out_vars[], DerivsFunc dfunc, void* udata)
2✔
592
: RKF45Integrator(eps, h, N, in_out_vars, in_out_vars, dfunc, udata) {}
2✔
593
// Copy Constructor
594
SA::RKF45Integrator::RKF45Integrator(const RKF45Integrator& other)
×
595
    : FirstOrderODEIntegrator(other) {
×
596
        epsilon = other.epsilon;
×
597
        next_h = other.next_h;
×
598
    }
×
599
// Assignment Operator
600
SA::RKF45Integrator& SA::RKF45Integrator::operator=( const SA::RKF45Integrator& rhs) {
×
601
    if (this != &rhs) {
×
602
        FirstOrderODEIntegrator::operator=(rhs);
×
603
    }
604
    epsilon = rhs.epsilon;
×
605
    next_h  = rhs.next_h;
×
606
    return *this;
×
607
}
608
// Destructor
609
SA::RKF45Integrator::~RKF45Integrator() {}
2✔
610

611
void SA::RKF45Integrator::advanceIndyVar(double h) {
25✔
612
    last_h = h; X_out = X_in + h;
25✔
613
}
25✔
614
void SA::RKF45Integrator::step() {
×
615
    adaptive_step( next_h );
×
616
}
×
617

618
double SA::RKF45Integrator::getLastStepSize() {return last_h;}
×
619

620
double SA::RKF45Integrator::adaptive_step(double h) {
25✔
621
    double wstate[5][state_size];
25✔
622
    double derivs[6][state_size];
25✔
623
    double w2[state_size];
25✔
624
    double R;
625
    do {
626

627
        (*derivs_func)( X_in, inState, derivs[0], user_data);
27✔
628
        for (unsigned int i=0; i<state_size; i++) {
87✔
629
            wstate[0][i] = inState[i] + h * (1/4.0) * derivs[0][i];
60✔
630
        }
631
        (*derivs_func)( X_in + (1/4.0) * h , wstate[0], derivs[1], user_data);
27✔
632
        for (unsigned int i=0; i<state_size; i++) {
87✔
633
            wstate[1][i] = inState[i] + h * ((3/32.0)*derivs[0][i] +
60✔
634
                                             (9/32.0)*derivs[1][i]);
60✔
635
        }
636
        (*derivs_func)( X_in + (3/8.0) * h , wstate[1], derivs[2], user_data);
27✔
637
        for (unsigned int i=0; i<state_size; i++) {
87✔
638
            wstate[2][i] = inState[i] + h * (( 1932/2197.0) * derivs[0][i] +
60✔
639
                                             (-7200/2197.0) * derivs[1][i] +
60✔
640
                                             ( 7296/2197.0) * derivs[2][i]);
60✔
641
        }
642
        (*derivs_func)( X_in + (12/13.0) * h , wstate[2], derivs[3], user_data);
27✔
643
        for (unsigned int i=0; i<state_size; i++) {
87✔
644
            wstate[3][i] = inState[i] + h * (( 439/216.0)  * derivs[0][i] +
60✔
645
                                             (-8.0)        * derivs[1][i] +
60✔
646
                                             ( 3680/513.0) * derivs[2][i] +
60✔
647
                                             (-845/4104.0) * derivs[3][i]);
60✔
648
        }
649
        (*derivs_func)( X_in + h , wstate[3], derivs[4], user_data);
27✔
650
        for (unsigned int i=0; i<state_size; i++) {
87✔
651
            wstate[4][i] = inState[i] + h * ((-8/27.0) * derivs[0][i] +
60✔
652
                                             ( 2.0) * derivs[1][i] +
60✔
653
                                             (-3544/2565.0) * derivs[2][i] +
60✔
654
                                             ( 1859/4104.0) * derivs[3][i] +
60✔
655
                                             (-11/40.0) * derivs[4][i]);
60✔
656
        }
657
        (*derivs_func)( X_in + (1/2.0)* h , wstate[4], derivs[5], user_data);
27✔
658
        for (unsigned int i=0; i<state_size; i++) {
87✔
659
            outState[i] = inState[i] + ((25/216.0) * derivs[0][i] +
60✔
660
                                 (1408/2565.0) * derivs[2][i] +
60✔
661
                                 (2197/4104.0) * derivs[3][i] +
60✔
662
                                 (-1/5.0) * derivs[4][i]) * h;
60✔
663
        }
664
        for (unsigned int i=0; i<state_size; i++) {
87✔
665
            w2[i] = inState[i] + (( 16/135.0) * derivs[0][i] +
60✔
666
                                  ( 6656/12825.0) * derivs[2][i] +
60✔
667
                                  ( 28561/56430.0) * derivs[3][i] +
60✔
668
                                  (-9/50.0) * derivs[4][i] +
60✔
669
                                  ( 2/55.0) * derivs[5][i]) * h;
60✔
670
        }
671
        last_h = h;
27✔
672
        R = 0.0;
27✔
673
        for (unsigned int i=0; i<state_size; i++) {
87✔
674
            double RI = fabs(outState[i] - w2[i]) / h;
60✔
675
            if (RI>R) R = RI;
60✔
676
        }
677
        if (R == 0.0) {
27✔
678
            next_h = default_h;
6✔
679
        } else {
680
            double delta = 0.84 * pow((epsilon/R), 0.25);
21✔
681
            next_h = delta * h;
21✔
682
            if (next_h > default_h)
21✔
683
                next_h = default_h;
6✔
684
        }
685
        h = next_h;
27✔
686
    } while (R > epsilon);
27✔
687

688
    advanceIndyVar(last_h);
25✔
689
    return (next_h);
25✔
690
}
25✔
691

692
// Insertion Operator
693
std::ostream& SA::operator<<(std::ostream& os, const RKF45Integrator& I) {
×
694
    os << (SA::FirstOrderODEIntegrator)I;
×
695
    os << "\nepsilon: " << I.epsilon;
×
696
    os << "\nnext_h: " << I.next_h;
×
697
    return os;
×
698
}
699

700
// ------------------------------------------------------------
701
// Class EulerCromerIntegrator
702
// ------------------------------------------------------------
703
// Default Constructor
704
SA::EulerCromerIntegrator::EulerCromerIntegrator()
×
705
    :Integrator() {
×
706
    nDimensions  = 1;
×
707
    last_h = 0.0;
×
708
    pos_p = NULL;
×
709
    pos_in  = new double[nDimensions];
×
710
    pos_out = new double[nDimensions];
×
711
    vel_p = NULL;
×
712
    vel_in  = new double[nDimensions];
×
713
    vel_out = new double[nDimensions];
×
714
    g_out   = new double[nDimensions];
×
715
    gderivs = nil_gfunc;
×
716
}
×
717
// Constructor
718
SA::EulerCromerIntegrator::EulerCromerIntegrator(
×
719
    double dt, unsigned int N, double* xp[], double* vp[], Derivs2Func gfunc, void* udata)
×
720
    :Integrator(dt, udata) {
×
721
    nDimensions  = N;
×
722
    last_h = 0.0;
×
723
    pos_p = xp;
×
724
    pos_in  = new double[N];
×
725
    pos_out = new double[N];
×
726
    vel_p = vp;
×
727
    vel_in  = new double[N];
×
728
    vel_out = new double[N];
×
729
    g_out   = new double[N];
×
730
    gderivs = gfunc;
×
731
}
×
732
// Copy Constructor
733
SA::EulerCromerIntegrator::EulerCromerIntegrator(const EulerCromerIntegrator& other)
×
734
: Integrator(other.default_h, other.user_data) {
×
735
    nDimensions = other.nDimensions;
×
736
    last_h = other.last_h;
×
737
    pos_p = other.pos_p;
×
738
    pos_in = new double[nDimensions];
×
739
    std::copy( other.pos_in, other.pos_in + nDimensions, pos_in);
×
740
    pos_out = new double[nDimensions];
×
741
    std::copy( other.pos_out, other.pos_out + nDimensions, pos_out);
×
742
    vel_p = other.vel_p;
×
743
    std::copy( other.vel_p, other.vel_p + nDimensions, vel_p);
×
744
    vel_in = new double[nDimensions];
×
745
    std::copy( other.vel_in, other.vel_in + nDimensions, vel_in);
×
746
    vel_out = new double[nDimensions];
×
747
    std::copy( other.vel_out, other.vel_out + nDimensions, vel_out);
×
748
    g_out = new double[nDimensions];
×
749
    std::copy( other.g_out, other.g_out + nDimensions, g_out);
×
750
    gderivs = other.gderivs;
×
751
}
×
752
// Assignment Operator
753
SA::EulerCromerIntegrator& SA::EulerCromerIntegrator::operator=( const SA::EulerCromerIntegrator& rhs) {
×
754
    if (this != &rhs) {
×
755
        // Call base assignment operator
756
        Integrator::operator=(rhs);
×
757
        // Duplicate the rhs arrays
758
        double* new_pos_in  = new double[rhs.nDimensions];
×
759
        std::copy( rhs.pos_in, rhs.pos_in + rhs.nDimensions, new_pos_in);
×
760
        double* new_pos_out = new double[rhs.nDimensions];
×
761
        std::copy( rhs.pos_out, rhs.pos_out + rhs.nDimensions, new_pos_out);
×
762
        double* new_vel_in  = new double[rhs.nDimensions];
×
763
        std::copy( rhs.vel_in, rhs.vel_in + rhs.nDimensions, new_vel_in);
×
764
        double* new_vel_out = new double[rhs.nDimensions];
×
765
        std::copy( rhs.vel_out, rhs.vel_out + rhs.nDimensions, new_vel_out);
×
766
        double* new_g_out = new double[rhs.nDimensions];
×
767
        std::copy( rhs.g_out, rhs.g_out + rhs.nDimensions, new_g_out);
×
768
        // Delete lhs arrays & replace with rhs arrays
769
        if (pos_in != NULL) delete pos_in;
×
770
        pos_in = new_pos_in;
×
771
        if (pos_out != NULL) delete pos_out;
×
772
        pos_out = new_pos_out;
×
773
        if (vel_in != NULL) delete vel_in;
×
774
        vel_in = new_vel_in;
×
775
        if (vel_out != NULL) delete vel_out;
×
776
        vel_out = new_vel_out;
×
777
        if (g_out != NULL) delete g_out;
×
778
        g_out = new_g_out;
×
779
        // Copy primitive members
780
        last_h = rhs.last_h;
×
781
        pos_p = rhs.pos_p;
×
782
        vel_p = rhs.vel_p;
×
783
        nDimensions = rhs.nDimensions;
×
784
        gderivs = rhs.gderivs;
×
785
    }
786
    return *this;
×
787
}
788
// Destructor
789
SA::EulerCromerIntegrator::~EulerCromerIntegrator() {
×
790
    if (pos_in != NULL)  delete pos_in;
×
791
    if (pos_out != NULL) delete pos_out;
×
792
    if (vel_in != NULL)  delete vel_in;
×
793
    if (vel_out != NULL) delete vel_out;
×
794
    if (g_out != NULL)   delete g_out;
×
795
}
×
796
void SA::EulerCromerIntegrator::advanceIndyVar(double h) {
×
797
    last_h = h; X_out = X_in + h;
×
798
}
×
799
void SA::EulerCromerIntegrator::step( double dt) {
×
800
    (*gderivs)( X_in, pos_in, vel_in, g_out, user_data);
×
801
    for (int i=0 ; i<nDimensions; i++ ) {
×
802
        vel_out[i] = vel_in[i] + g_out[i] * dt;
×
803
        pos_out[i] = pos_in[i] + vel_out[i] * dt;
×
804
    }
805
    advanceIndyVar(dt);
×
806
}
×
807
void SA::EulerCromerIntegrator::step() {
×
808
    step(default_h);
×
809
}
×
810
void SA::EulerCromerIntegrator::load() {
×
811
    if ((pos_in != NULL) && (vel_in != NULL)) {
×
812
        for (int i=0 ; i<nDimensions; i++ ) {
×
813
            pos_in[i] = *(pos_p[i]);
×
814
            vel_in[i] = *(vel_p[i]);
×
815
        }
816
        Integrator::load();
×
817
    } else {
×
818
        std::cerr << "Error: SA::EulerCromerIntegrator::load(). Input variable pointers (pos_in, vel_in) aren't set." << std::endl;
×
819
    }
820
}
×
821
void SA::EulerCromerIntegrator::unload(){
×
822
    if ((pos_in != NULL) && (vel_in != NULL)) {
×
823
        for (int i=0 ; i<nDimensions; i++ ) {
×
824
            *(pos_p[i]) = pos_out[i];
×
825
            *(vel_p[i]) = vel_out[i];
×
826
        }
827
    } else {
×
828
        std::cerr << "Error: SA::EulerCromerIntegrator::load(). Input variable pointers (pos_in, vel_in) aren't set." << std::endl;
×
829
    }
830
}
×
831
double SA::EulerCromerIntegrator::undo_integrate() {
×
832
    if ((pos_in != NULL) && (vel_in != NULL)) {
×
833
        for (unsigned int i=0 ; i<nDimensions; i++ ) {
×
834
            *(pos_p[i]) = pos_in[i];
×
835
            *(vel_p[i]) = vel_in[i];
×
836
        }
837
        std::copy(pos_in, pos_in + nDimensions, pos_out);
×
838
        std::copy(vel_in, vel_in + nDimensions, vel_out);
×
839
        return (SA::Integrator::undo_integrate());
×
840
    } else {
841
        std::cerr << "Error: SA::EulerCromerIntegrator::undo_integrate(). Input variable pointers (pos_in, vel_in) aren't set." << std::endl;
×
842
    }
843
    return (last_h);
×
844
}
845
// Insertion Operator
846
std::ostream& SA::operator<<(std::ostream& os, const EulerCromerIntegrator& I) {
×
847
    os << (SA::Integrator)I;
×
848
    os << "\n--- EulerCromerIntegrator ---";
×
849
    os << "\nnDimensions : " << I.nDimensions;
×
850
    os << "\nlast_h      : " << I.last_h;
×
851
    os << "\npos_p       :" << I.pos_p;
×
852
    os << "\nvel_p       :" << I.vel_p;
×
853
    os << "\npos_in    :";
×
854
    stream_double_array(os, I.nDimensions, I.pos_in);
×
855
    os << "\npos_out    :";
×
856
    stream_double_array(os, I.nDimensions, I.pos_out);
×
857
    os << "\nvel_in    :";
×
858
    stream_double_array(os, I.nDimensions, I.vel_in);
×
859
    os << "\nvel_out    :";
×
860
    stream_double_array(os, I.nDimensions, I.vel_out);
×
861
    os << "\ng_out    :";
×
862
    stream_double_array(os, I.nDimensions, I.g_out);
×
863
    return os;
×
864
}
865

866
// ------------------------------------------------------------
867
// Class ABMIntegrator
868
// ------------------------------------------------------------
869
// // Adams-Bashforth Coefficients
870
static const double ABCoeffs[5][5] = {
871
  {1.0,           0.0,           0.0,          0.0,           0.0},
872
  {(3/2.0),      (-1/2.0),       0.0,          0.0,           0.0},
873
  {(23/12.0),    (-16/12.0),    (5/12.0),      0.0,           0.0},
874
  {(55/24.0),    (-59/24.0),    (37/24.0),    (-9/24.0),      0.0},
875
  {(1901/720.0), (-2774/720.0), (2616/720.0), (-1274/720.0), (251/720.0)}
876
};
877
//
878
// // Adams-Moulton Coefficients
879
static const double AMCoeffs[5][5] = {
880
  {1.0,          0.0,         0.0,          0.0,         0.0},
881
  {(1/2.0),     (1/2.0),      0.0,          0.0,         0.0},
882
  {(5/12.0),    (8/12.0),    (-1/12.0),     0.0,         0.0},
883
  {(9/24.0),    (19/24.0),   (-5/24.0),    (1/24.0),     0.0},
884
  {(251/720.0), (646/720.0), (-264/720.0), (106/720.0), (-19/720.0)}
885
};
886

887
// Default Constructor
888

889
// Constructor
890
SA::ABMIntegrator::ABMIntegrator ( unsigned int history_size, double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc func, void* udata)
×
891
    : FirstOrderODEIntegrator(h, N, in_vars, out_vars ,func, udata) {
×
892
    if ((history_size < 1) || (history_size > 5)) {
×
893
        throw std::invalid_argument("history_size must be in the range [1..5].");
×
894
    }
895
    algorithmHistorySize=history_size; // The amount of history that we intend to use in this ABM integrator.
×
896
    bufferSize=algorithmHistorySize+1; // The size of the buffer needs to be one more than the history so that an integration step can be reset.
×
897
    hix=0;
×
898
    currentHistorySize=0;              // How much derivative history is currently stored int the history buffer. Initially there will be none until we've primed the integrator.
×
899
    deriv_history = new double*[bufferSize];
×
900
    for (unsigned int i=0; i<bufferSize ; i++) {
×
901
        deriv_history[i] = new double[state_size];
×
902
    }
903
    composite_deriv = new double[state_size];
×
904
}
×
905
// Constructor
906
SA::ABMIntegrator::ABMIntegrator(
×
907
unsigned int history_size, double h, unsigned int N, double* in_out_vars[], DerivsFunc dfunc, void* udata)
×
908
: ABMIntegrator(history_size, h, N, in_out_vars, in_out_vars, dfunc, udata) {}
×
909

910
// Copy Constructor
911
SA::ABMIntegrator::ABMIntegrator(const ABMIntegrator& other)
×
912
: FirstOrderODEIntegrator(other) {
×
913
    bufferSize = other.bufferSize;
×
914
    algorithmHistorySize = other.algorithmHistorySize;
×
915
    hix = other.hix;
×
916
    currentHistorySize = other.currentHistorySize;
×
917
    deriv_history = new double*[bufferSize];
×
918
    for (unsigned int i=0; i<bufferSize ; i++) {
×
919
        deriv_history[i] = new double[state_size];
×
920
        std::copy(other.deriv_history[i], other.deriv_history[i]+state_size, deriv_history[i]);
×
921
    }
922
    composite_deriv = new double[state_size];
×
923
    std::copy(other.composite_deriv, other.composite_deriv+state_size, composite_deriv);
×
924
}
×
925
// Assignment Operator
926
SA::ABMIntegrator& SA::ABMIntegrator::operator=( const SA::ABMIntegrator& rhs) {
×
927
    if (this != &rhs) {
×
928
        // Call base assignment operator
929
        FirstOrderODEIntegrator::operator=(rhs);
×
930
        // Duplicate rhs arrays
931
        double** new_deriv_history = new double*[rhs.bufferSize];
×
932
        for (unsigned int i=0 ; i<rhs.bufferSize; i++ ) {
×
933
            new_deriv_history[i] = new double[rhs.state_size];
×
934
            std::copy(rhs.deriv_history[i], rhs.deriv_history[i] + rhs.state_size, new_deriv_history[i]);
×
935
        }
936
        double* new_composite_deriv = new double[rhs.state_size];
×
937
        std::copy(rhs.composite_deriv, rhs.composite_deriv+rhs.state_size, new_composite_deriv);
×
938
        // Delete lhs arrays & replace with rhs arrays
939
        for (unsigned int i=0 ; i<bufferSize; i++ ) {
×
940
            delete deriv_history[i];
×
941
        }
942
        delete deriv_history;
×
943
        deriv_history = new_deriv_history;
×
944
        delete composite_deriv;
×
945
        composite_deriv = new_composite_deriv;
×
946
        // Copy primitive members
947
        bufferSize = rhs.bufferSize;
×
948
        algorithmHistorySize = rhs.algorithmHistorySize;
×
949
        hix = rhs.hix;
×
950
        currentHistorySize = rhs.currentHistorySize;
×
951
    }
952
    return *this;
×
953
}
954
// Destructor
955
SA::ABMIntegrator::~ABMIntegrator() {
×
956
    for (int i=0; i<bufferSize ; i++) {
×
957
        delete (deriv_history[i]);
×
958
    }
959
    delete(deriv_history);
×
960
    delete(composite_deriv);
×
961
}
×
962
void SA::ABMIntegrator::step() {
×
963

964
    hix = (hix+1)%bufferSize;                                      // Move history index forward
×
965
    (*derivs_func)( X_in, inState, deriv_history[hix], user_data); // Calculated and store the deriv for current, corrected state.
×
966
    // Increase the size of the stored history, up to the limit specified by the user.
967
    currentHistorySize = (currentHistorySize < algorithmHistorySize) ? currentHistorySize+1 : algorithmHistorySize;
×
968
    // (Predictor) Predict the next state using the Adams-Bashforth explicit method.
969
    for (int i=0; i<state_size; i++) {
×
970
        composite_deriv[i] = 0.0;
×
971
        for (int n=0,j=hix; n<currentHistorySize ; n++,j=(j+bufferSize-1)%bufferSize) {
×
972
            composite_deriv[i] += ABCoeffs[currentHistorySize-1][n] * deriv_history[j][i];
×
973
        }
974
        outState[i] = inState[i] + default_h * composite_deriv[i];
×
975
    }
976
    // Move history index forward, so we can temporarily store the derivative of the predicted next state.
977
    // We do not increase the currentHistorySize.
978
    hix = (hix+1)%bufferSize;
×
979
    (*derivs_func)( X_out, outState, deriv_history[hix], user_data); // Calc deriv for predicted next state.
×
980
    // (Corrector) Refine the next state using the Adams-Moulton implicit method. This is the corrected next state.
981
    for (int i=0; i<state_size; i++) {
×
982
        composite_deriv[i] = 0.0;
×
983
        for (int n=0,j=hix; n<currentHistorySize ; n++,j=(j+bufferSize-1)%bufferSize) {
×
984
            composite_deriv[i] += AMCoeffs[currentHistorySize-1][n] * deriv_history[j][i];
×
985
        }
986
        outState[i] = inState[i] + default_h * composite_deriv[i];
×
987
    }
988
    // Move history index backward, so we over-write the predicted state with the corrected state on our next step().
989
    hix = (hix+bufferSize-1)%bufferSize;
×
990
    advanceIndyVar();
×
991
}
×
992
double SA::ABMIntegrator::undo_integrate() {
×
993
    hix = (hix+bufferSize-1)%bufferSize;
×
994
    return (FirstOrderODEIntegrator::undo_integrate());
×
995
}
996
// Insertion Operator
997
std::ostream& SA::operator<<(std::ostream& os, const ABMIntegrator& I) {
×
998
    os << (SA::FirstOrderODEIntegrator)I;
×
999
    os << "\n--- ABMIntegrator ---";
×
1000
    os << "\nbufferSize           : " << I.bufferSize;
×
1001
    os << "\nalgorithmHistorySize : " << I.algorithmHistorySize;
×
1002
    os << "\nhix                  : " << I.hix;
×
1003
    os << "\ncurrentHistorySize   : " << I.currentHistorySize;
×
1004
    os << "\nderiv_history        :[";
×
1005
    for (int i=0; i<I.bufferSize ; i++) {
×
1006
        os << "\n";
×
1007
        stream_double_array(os, I.state_size, I.deriv_history[i]);
×
1008
    }
1009
    os << "\n]";
×
1010
    os << "\ncomposite_deriv     :";
×
1011
    stream_double_array(os, I.state_size, I.composite_deriv);
×
1012
    return os;
×
1013
}
1014

1015
// ************************************************************
1016
//                       ATTENTION!!!
1017
// ABM Integrators CAN NOT have a variable step, because of its
1018
// derivative history.
1019
// ************************************************************
1020

1021
// ------------------------------------------------------------
1022
// Class ABM2Integrator
1023
// ------------------------------------------------------------
1024
static const double AB2Coeffs[2] = {(3/2.0), (-1/2.0)};
1025
static const double AM2Coeffs[2] = {(1/2.0),  (1/2.0)};
1026

1027
SA::ABM2Integrator::ABM2Integrator (
×
1028
    double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc dfunc, void* udata)
×
1029
    : FirstOrderODEIntegrator(h, N, in_vars, out_vars, dfunc, udata) {
×
1030
    // The amount of history that we intend to use in this ABM integrator.
1031
    bufferSize=2+1; // The size of the buffer needs to be one more than the history so that an integration step can be reset.
×
1032
    hix=0;
×
1033
    currentHistorySize=0;            // How much derivative history is currently stored int the history buffer. Initially there will be none until we've primed the integrator.
×
1034
    deriv_history = new double*[bufferSize];
×
1035
    for (unsigned int i=0; i<bufferSize ; i++) {
×
1036
        deriv_history[i] = new double[state_size];
×
1037
    }
1038
    composite_deriv = new double[state_size];
×
1039

1040
    // Create a priming integrator.
1041
    double** priming_integrator_in_vars = new double*[state_size];
×
1042
    for (unsigned int i=0; i<N ; i++) {
×
1043
        priming_integrator_in_vars[i] = &(inState[i]);
×
1044
    }
1045
    double** priming_integrator_out_vars = new double*[state_size];
×
1046
    for (unsigned int i=0; i<N ; i++) {
×
1047
        priming_integrator_out_vars[i] = &(outState[i]);
×
1048
    }
1049
    priming_integrator = new SA::RK2Integrator(h, N, priming_integrator_in_vars, priming_integrator_out_vars, dfunc, udata);
×
1050
}
×
1051
// Constructor
1052
SA::ABM2Integrator::ABM2Integrator(
×
1053
double h, unsigned int N, double* in_out_vars[], DerivsFunc dfunc, void* udata)
×
1054
: ABM2Integrator(h, N, in_out_vars, in_out_vars, dfunc, udata) {}
×
1055

1056
SA::ABM2Integrator::ABM2Integrator(const ABM2Integrator& other)
×
1057
: FirstOrderODEIntegrator(other) {
×
1058
    bufferSize = other.bufferSize;
×
1059
    hix = other.hix;
×
1060
    currentHistorySize = other.currentHistorySize;
×
1061
    deriv_history = new double*[bufferSize];
×
1062
    for (unsigned int i=0; i<bufferSize ; i++) {
×
1063
        deriv_history[i] = new double[state_size];
×
1064
        std::copy(other.deriv_history[i], other.deriv_history[i]+state_size, deriv_history[i]);
×
1065
    }
1066
    composite_deriv = new double[state_size];
×
1067
    std::copy(other.composite_deriv, other.composite_deriv+state_size, composite_deriv);
×
1068

1069
    priming_integrator = new RK2Integrator(*other.priming_integrator);
×
1070
}
×
1071
// Assignment Operator
1072
SA::ABM2Integrator& SA::ABM2Integrator::operator=( const SA::ABM2Integrator& rhs) {
×
1073
    if (this != &rhs) {
×
1074
        // Call base assignment operator
1075
        FirstOrderODEIntegrator::operator=(rhs);
×
1076
        // Duplicate rhs arrays
1077
        double** new_deriv_history = new double*[rhs.bufferSize];
×
1078
        for (unsigned int i=0 ; i<rhs.bufferSize; i++ ) {
×
1079
            new_deriv_history[i] = new double[rhs.state_size];
×
1080
            std::copy(rhs.deriv_history[i], rhs.deriv_history[i] + rhs.state_size, new_deriv_history[i]);
×
1081
        }
1082
        double* new_composite_deriv = new double[rhs.state_size];
×
1083
        std::copy(rhs.composite_deriv, rhs.composite_deriv+rhs.state_size, new_composite_deriv);
×
1084
        // Delete lhs arrays & replace with rhs arrays
1085
        for (unsigned int i=0 ; i<bufferSize; i++ ) {
×
1086
            delete deriv_history[i];
×
1087
        }
1088
        delete deriv_history;
×
1089
        deriv_history = new_deriv_history;
×
1090
        delete composite_deriv;
×
1091
        composite_deriv = new_composite_deriv;
×
1092
        // Copy primitive members
1093
        bufferSize = rhs.bufferSize;
×
1094
        hix = rhs.hix;
×
1095
        currentHistorySize = rhs.currentHistorySize;
×
1096
    }
1097
    return *this;
×
1098
}
1099

1100
SA::ABM2Integrator::~ABM2Integrator() {
×
1101
    for (int i=0; i<bufferSize ; i++) {
×
1102
        delete (deriv_history[i]);
×
1103
    }
1104
    delete(deriv_history);
×
1105
    delete(composite_deriv);
×
1106
    delete priming_integrator;
×
1107
}
×
1108
void SA::ABM2Integrator::step() {
×
1109

1110
    hix = (hix+1)%bufferSize;                          // Move history index forward
×
1111
    (*derivs_func)( X_in, inState, deriv_history[hix], user_data); // Calculated and store the deriv for current, corrected state.
×
1112
    // Increase the size of the stored history, up to the limit specified by the user.
1113
    currentHistorySize = (currentHistorySize < 2) ? currentHistorySize+1 : 2;
×
1114

1115
    if ( currentHistorySize < 2 ) {
×
1116
        priming_integrator->load();
×
1117
        priming_integrator->step();
×
1118
        priming_integrator->unload();
×
1119
    } else {
1120
        // (Predictor) Predict the next state using the Adams-Bashforth explicit method.
1121
        for (int i=0; i<state_size; i++) {
×
1122
            composite_deriv[i] = 0.0;
×
1123
            for (int n=0,j=hix; n<2 ; n++,j=(j+bufferSize-1)%bufferSize) {
×
1124
                composite_deriv[i] += AB2Coeffs[n] * deriv_history[j][i];
×
1125
            }
1126
            outState[i] = inState[i] + default_h * composite_deriv[i];
×
1127
        }
1128
        // Move history index forward, so we can temporarily store the derivative of the predicted next state.
1129
        // We do not increase the currentHistorySize.
1130
        hix = (hix+1)%bufferSize;
×
1131
        (*derivs_func)( X_in, outState, deriv_history[hix], user_data); // Calc deriv for predicted next state.
×
1132
        // (Corrector) Refine the next state using the Adams-Moulton implicit method. This is the corrected next state.
1133
        for (int i=0; i<state_size; i++) {
×
1134
            composite_deriv[i] = 0.0;
×
1135
            for (int n=0,j=hix; n<2 ; n++,j=(j+bufferSize-1)%bufferSize) {
×
1136
                composite_deriv[i] += AM2Coeffs[n] * deriv_history[j][i];
×
1137
            }
1138
            outState[i] = inState[i] + default_h * composite_deriv[i];
×
1139
        }
1140
        // Move history index backward, so we over-write the predicted state with the corrected state on our next step().
1141
        hix = (hix+bufferSize-1)%bufferSize;
×
1142
    }
1143
    advanceIndyVar();
×
1144
}
×
1145
double SA::ABM2Integrator::undo_integrate() {
×
1146
    hix = (hix+bufferSize-1)%bufferSize;
×
1147
    return ( FirstOrderODEIntegrator::undo_integrate());
×
1148
}
1149

1150
// Insertion Operator
1151
std::ostream& SA::operator<<(std::ostream& os, const ABM2Integrator& I) {
×
1152
    os << (SA::FirstOrderODEIntegrator)I;
×
1153
    os << "\n--- ABM2Integrator ---";
×
1154
    os << "\nbufferSize           : " << I.bufferSize;
×
1155
    os << "\nhix                  : " << I.hix;
×
1156
    os << "\ncurrentHistorySize   : " << I.currentHistorySize;
×
1157
    os << "\nderiv_history        :[";
×
1158
    for (int i=0; i<I.bufferSize ; i++) {
×
1159
        os << "\n";
×
1160
        stream_double_array(os, I.state_size, I.deriv_history[i]);
×
1161
    }
1162
    os << "\n]";
×
1163
    os << "\ncomposite_deriv     :";
×
1164
    stream_double_array(os, I.state_size, I.composite_deriv);
×
1165
    return os;
×
1166
}
1167
// ------------------------------------------------------------
1168
// Class ABM4Integrator
1169
// ------------------------------------------------------------
1170
static const double AB4Coeffs[4] = {(55/24.0), (-59/24.0), (37/24.0), (-9/24.0)};
1171
static const double AM4Coeffs[4] = {(9/24.0), (19/24.0), (-5/24.0), (1/24.0)};
1172

1173
SA::ABM4Integrator::ABM4Integrator (
×
1174
    double h, unsigned int N, double* in_vars[], double* out_vars[], DerivsFunc dfunc, void* udata)
×
1175
    : FirstOrderODEIntegrator(h, N, in_vars, out_vars, dfunc, udata) {
×
1176

1177
    // The amount of history that we intend to use in this ABM integrator.
1178
    bufferSize=4+1; // The size of the buffer needs to be one more than the history so that an integration step can be reset.
×
1179
    hix=0;
×
1180
    currentHistorySize=0;            // How much derivative history is currently stored int the history buffer. Initially there will be none until we've primed the integrator.
×
1181
    deriv_history = new double*[bufferSize];
×
1182
    for (unsigned int i=0; i<bufferSize ; i++) {
×
1183
        deriv_history[i] = new double[state_size];
×
1184
    }
1185
    composite_deriv = new double[state_size];
×
1186
    // NEW: Create a priming integrator.
1187
    double** priming_integrator_in_vars = new double*[state_size];
×
1188
    for (unsigned int i=0; i<N ; i++) {
×
1189
        priming_integrator_in_vars[i] = &(inState[i]);
×
1190
    }
1191
    double** priming_integrator_out_vars = new double*[state_size];
×
1192
    for (unsigned int i=0; i<N ; i++) {
×
1193
        priming_integrator_out_vars[i] = &(outState[i]);
×
1194
    }
1195
    priming_integrator = new SA::RK4Integrator(h, N, priming_integrator_in_vars, priming_integrator_out_vars, dfunc, udata);
×
1196
}
×
1197
// Constructor
1198
SA::ABM4Integrator::ABM4Integrator(
×
1199
double h, unsigned int N, double* in_out_vars[], DerivsFunc dfunc, void* udata)
×
1200
: ABM4Integrator(h, N, in_out_vars, in_out_vars, dfunc, udata) {}
×
1201

1202
SA::ABM4Integrator::ABM4Integrator(const ABM4Integrator& other)
×
1203
: FirstOrderODEIntegrator(other) {
×
1204
    bufferSize = other.bufferSize;
×
1205
    hix = other.hix;
×
1206
    currentHistorySize = other.currentHistorySize;
×
1207
    deriv_history = new double*[bufferSize];
×
1208
    for (unsigned int i=0; i<bufferSize ; i++) {
×
1209
        deriv_history[i] = new double[state_size];
×
1210
        std::copy(other.deriv_history[i], other.deriv_history[i]+state_size, deriv_history[i]);
×
1211
    }
1212
    composite_deriv = new double[state_size];
×
1213
    std::copy(other.composite_deriv, other.composite_deriv+state_size, composite_deriv);
×
1214

1215
    priming_integrator = new RK4Integrator(*other.priming_integrator);
×
1216
}
×
1217
// Assignment Operator
1218
SA::ABM4Integrator& SA::ABM4Integrator::operator=( const SA::ABM4Integrator& rhs) {
×
1219
    if (this != &rhs) {
×
1220
        // Call base assignment operator
1221
        FirstOrderODEIntegrator::operator=(rhs);
×
1222
        // Duplicate rhs arrays
1223
        double** new_deriv_history = new double*[rhs.bufferSize];
×
1224
        for (unsigned int i=0 ; i<rhs.bufferSize; i++ ) {
×
1225
            new_deriv_history[i] = new double[rhs.state_size];
×
1226
            std::copy(rhs.deriv_history[i], rhs.deriv_history[i] + rhs.state_size, new_deriv_history[i]);
×
1227
        }
1228
        double* new_composite_deriv = new double[rhs.state_size];
×
1229
        std::copy(rhs.composite_deriv, rhs.composite_deriv+rhs.state_size, new_composite_deriv);
×
1230
        // Delete lhs arrays & replace with rhs arrays
1231
        for (unsigned int i=0 ; i<bufferSize; i++ ) {
×
1232
            delete deriv_history[i];
×
1233
        }
1234
        delete deriv_history;
×
1235
        deriv_history = new_deriv_history;
×
1236
        delete composite_deriv;
×
1237
        composite_deriv = new_composite_deriv;
×
1238
        // Copy primitive members
1239
        bufferSize = rhs.bufferSize;
×
1240
        hix = rhs.hix;
×
1241
        currentHistorySize = rhs.currentHistorySize;
×
1242
    }
1243
    return *this;
×
1244
}
1245
SA::ABM4Integrator::~ABM4Integrator() {
×
1246
    for (int i=0; i<bufferSize ; i++) {
×
1247
        delete (deriv_history[i]);
×
1248
    }
1249
    delete(deriv_history);
×
1250
    delete(composite_deriv);
×
1251
    delete priming_integrator;
×
1252
}
×
1253
void SA::ABM4Integrator::step() {
×
1254

1255
    hix = (hix+1)%bufferSize;                          // Move history index forward
×
1256
    (*derivs_func)( X_in, inState, deriv_history[hix], user_data); // Calculated and store the deriv for current, corrected state.
×
1257
    // Increase the size of the stored history, up to the limit specified by the user.
1258
    currentHistorySize = (currentHistorySize < 4) ? currentHistorySize+1 : 4;
×
1259
    if ( currentHistorySize < 4 ) {
×
1260
        priming_integrator->load();
×
1261
        priming_integrator->step();
×
1262
        priming_integrator->unload();
×
1263
    } else {
1264
        // (Predictor) Predict the next state using the Adams-Bashforth explicit method.
1265
        for (int i=0; i<state_size; i++) {
×
1266
            composite_deriv[i] = 0.0;
×
1267
            for (int n=0,j=hix; n<4 ; n++,j=(j+bufferSize-1)%bufferSize) {
×
1268
                composite_deriv[i] += AB4Coeffs[n] * deriv_history[j][i];
×
1269
            }
1270
            outState[i] = inState[i] + default_h * composite_deriv[i];
×
1271
        }
1272
        // Move history index forward, so we can temporarily store the derivative of the predicted next state.
1273
        // We do not increase the currentHistorySize.
1274
        hix = (hix+1)%bufferSize;
×
1275
        (*derivs_func)( X_out, outState, deriv_history[hix], user_data); // Calc deriv for predicted next state.
×
1276
        // (Corrector) Refine the next state using the Adams-Moulton implicit method. This is the corrected next state.
1277
        for (int i=0; i<state_size; i++) {
×
1278
            composite_deriv[i] = 0.0;
×
1279
            for (int n=0,j=hix; n<4 ; n++,j=(j+bufferSize-1)%bufferSize) {
×
1280
                composite_deriv[i] += AM4Coeffs[n] * deriv_history[j][i];
×
1281
            }
1282
            outState[i] = inState[i] + default_h * composite_deriv[i];
×
1283
        }
1284
        // Move history index backward, so we over-write the predicted state with the corrected state on our next step().
1285
        hix = (hix+bufferSize-1)%bufferSize;
×
1286
    }
1287
    advanceIndyVar();
×
1288
}
×
1289
double SA::ABM4Integrator::undo_integrate() {
×
1290
    hix = (hix+bufferSize-1)%bufferSize;
×
1291
    return (FirstOrderODEIntegrator::undo_integrate());
×
1292
}
1293
// Insertion Operator
1294
std::ostream& SA::operator<<(std::ostream& os, const ABM4Integrator& I) {
×
1295
    os << (SA::FirstOrderODEIntegrator)I;
×
1296
    os << "\n--- ABM4Integrator ---";
×
1297
    os << "\nbufferSize           : " << I.bufferSize;
×
1298
    os << "\nhix                  : " << I.hix;
×
1299
    os << "\ncurrentHistorySize   : " << I.currentHistorySize;
×
1300
    os << "\nderiv_history        :[";
×
1301
    for (int i=0; i<I.bufferSize ; i++) {
×
1302
        os << "\n";
×
1303
        stream_double_array(os, I.state_size, I.deriv_history[i]);
×
1304
    }
1305
    os << "\n]";
×
1306
    os << "\ncomposite_deriv     :";
×
1307
    stream_double_array(os, I.state_size, I.composite_deriv);
×
1308
    return os;
×
1309
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc