forked from AMReX-Astro/Microphysics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathactual_integrator.H
210 lines (163 loc) · 6.49 KB
/
actual_integrator.H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#ifndef actual_integrator_H
#define actual_integrator_H
// Common variables and routines for burners
// that use VODE for their integration.
#include <iomanip>
#include <network.H>
#include <burn_type.H>
#include <eos_type.H>
#include <eos.H>
#include <extern_parameters.H>
#include <vode_type.H>
#include <vode_dvode.H>
using namespace integrator_rp;
template <typename BurnT>
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
void actual_integrator (BurnT& state, Real dt, bool is_retry=false)
{
constexpr int int_neqs = integrator_neqs<BurnT>();
dvode_t<int_neqs> vode_state{};
// Set the tolerances.
if (!is_retry) {
vode_state.atol_spec = atol_spec; // mass fractions
vode_state.atol_enuc = atol_enuc; // energy generated
vode_state.rtol_spec = rtol_spec; // mass fractions
vode_state.rtol_enuc = rtol_enuc; // energy generated
} else {
vode_state.atol_spec = retry_atol_spec; // mass fractions
vode_state.atol_enuc = retry_atol_enuc; // energy generated
vode_state.rtol_spec = retry_rtol_spec; // mass fractions
vode_state.rtol_enuc = retry_rtol_enuc; // energy generated
}
// set the Jacobian type
if (is_retry && retry_swap_jacobian) {
vode_state.jacobian_type = (jacobian == 1) ? 2 : 1;
} else {
vode_state.jacobian_type = static_cast<short>(jacobian);
}
// Start off by assuming a successful burn.
state.success = true;
// Initialize the integration time.
vode_state.t = 0.0_rt;
vode_state.tout = dt;
// Initialize ydot to zero for Strang burn.
for (int n = 0; n < SVAR; ++n) {
state.ydot_a[n] = 0;
}
// Set the (inverse of the) timestep limiter.
vode_state.HMXI = 1.0_rt / ode_max_dt;
// We assume that (rho, T) coming in are valid, do an EOS call
// to fill the rest of the thermodynamic variables.
eos(eos_input_rt, state);
// set the scaling for energy if we integrate it dimensionlessly
state.e_scale = state.e;
if (scale_system) {
// the absolute tol for energy needs to reflect the scaled
// energy the integrator sees
vode_state.atol_enuc /= state.e_scale;
}
// Fill in the initial integration state.
burn_to_integrator(state, vode_state);
// Save the initial composition, temperature, and energy for our later diagnostics.
#ifndef AMREX_USE_GPU
Real xn_in[NumSpec];
for (int n = 0; n < NumSpec; ++n) {
xn_in[n] = state.xn[n];
}
const Real T_in = state.T;
#endif
const Real e_in = state.e;
// Call the integration routine.
int istate = dvode(state, vode_state);
state.error_code = istate;
// Copy the integration data back to the burn state.
integrator_to_burn(vode_state, state);
#ifdef NSE
// compute the temperature based on the energy release -- we need
// this in case we failed in our burn here because we entered NSE
#ifdef AUX_THERMO
// need to sync the auxiliary data up with the new mass fractions
set_aux_comp_from_X(state);
#endif
if (call_eos_in_rhs) {
eos(eos_input_re, state);
}
#endif
// Subtract off the initial energy (the application codes expect
// to get back only the generated energy during the burn).
// Don't subtract it for primordial chem
if (subtract_internal_energy) {
state.e -= e_in;
}
// Normalize the final abundances.
// Don't normalize for primordial chem
if (!use_number_densities) {
normalize_abundances_burn(state);
}
// Get the number of RHS and Jacobian evaluations.
state.n_rhs = vode_state.NFE;
state.n_jac = vode_state.NJE;
state.n_step = vode_state.NST;
// VODE does not always fail even though it can lead to unphysical states.
// Add some checks that indicate a burn fail even if VODE thinks the
// integration was successful.
if (istate != IERR_SUCCESS) {
state.success = false;
}
for (int n = 1; n <= NumSpec; ++n) {
if (vode_state.y(n) < -species_failure_tolerance) {
state.success = false;
}
// Don't enforce the condition below
// for primordial chem
if (!use_number_densities) {
if (vode_state.y(n) > 1.0_rt + species_failure_tolerance) {
state.success = false;
}
}
}
#ifndef AMREX_USE_GPU
if (burner_verbose) {
// Print out some integration statistics, if desired.
std::cout << "integration summary: " << std::endl;
std::cout << "dens: " << state.rho << " temp: " << state.T << std::endl;
std::cout << " energy released: " << state.e << std::endl;
std::cout << "number of steps taken: " << vode_state.NST << std::endl;
std::cout << "number of f evaluations: " << vode_state.NFE << std::endl;
}
#endif
// If we failed, print out the current state of the integration.
if (!state.success) {
if (istate != IERR_ENTERED_NSE) {
#ifndef AMREX_USE_GPU
std::cout << Font::Bold << FGColor::Red << "[ERROR] integration failed in net" << ResetDisplay << std::endl;
std::cout << "istate = " << istate << std::endl;
if (istate == IERR_SUCCESS) {
std::cout << " VODE exited successfully, but a check on the data values failed" << std::endl;
}
std::cout << "zone = (" << state.i << ", " << state.j << ", " << state.k << ")" << std::endl;
std::cout << "time = " << vode_state.t << std::endl;
std::cout << "dt = " << std::setprecision(16) << dt << std::endl;
std::cout << "temp start = " << std::setprecision(16) << T_in << std::endl;
std::cout << "xn start = ";
for (const double x : xn_in) {
std::cout << std::setprecision(16) << x << " ";
}
std::cout << std::endl;
std::cout << "dens current = " << std::setprecision(16) << state.rho << std::endl;
std::cout << "temp current = " << std::setprecision(16) << state.T << std::endl;
std::cout << "xn current = ";
for (const double x : state.xn) {
std::cout << std::setprecision(16) << x << " ";
}
std::cout << std::endl;
std::cout << "energy generated = " << state.e << std::endl;
#endif
} else {
#ifndef AMREX_USE_GPU
std::cout << "burn entered NSE during integration (after " << vode_state.NST << " steps), zone = (" << state.i << ", " << state.j << ", " << state.k << ")" << std::endl;
#endif
}
}
}
#endif