Skip to content

Commit e6ec045

Browse files
authored
get the BackwardEuler solver working with simplified-SDC (#1042)
1 parent 1539b01 commit e6ec045

File tree

9 files changed

+219
-21
lines changed

9 files changed

+219
-21
lines changed

integration/BackwardEuler/Make.package

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
CEXE_headers += actual_integrator.H
1+
ifeq ($(USE_SIMPLIFIED_SDC), TRUE)
2+
CEXE_headers += actual_integrator_simplified_sdc.H
3+
else
4+
ifneq ($(USE_TRUE_SDC), TRUE)
5+
CEXE_headers += actual_integrator.H
6+
endif
7+
endif
8+
29
CEXE_headers += be_integrator.H
310
CEXE_headers += be_type.H
4-
CEXE_headers += be_type_strang.H
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
#ifndef actual_integrator_H
2+
#define actual_integrator_H
3+
4+
#include <iomanip>
5+
6+
#include <be_type.H>
7+
#include <be_integrator.H>
8+
#include <extern_parameters.H>
9+
10+
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
11+
void actual_integrator (burn_t& state, const Real dt)
12+
{
13+
14+
be_t be;
15+
16+
// set the Jacobian type
17+
be.jacobian_type = jacobian;
18+
19+
// Start off by assuming a successful burn.
20+
21+
state.success = true;
22+
23+
// Initialize the integration time.
24+
25+
be.t = 0.0;
26+
be.tout = dt;
27+
28+
// Fill in the initial integration state.
29+
30+
burn_to_int(state, be);
31+
32+
// Save the initial composition and temperature for our later diagnostics.
33+
34+
#ifndef AMREX_USE_GPU
35+
Real xn_in[NumSpec];
36+
for (int n = 0; n < NumSpec; ++n) {
37+
xn_in[n] = state.y[SFS+n] / state.y[SRHO];
38+
}
39+
// we are assuming that the temperature was valid on input
40+
Real T_in = state.T;
41+
#ifdef AUX_THERMO
42+
Real aux_in[NumAux];
43+
for (int n = 0; n < NumAux; ++n) {
44+
aux_in[n] = state.y[SFX+n] / state.y[SRHO];
45+
}
46+
#endif
47+
Real rhoe_in = state.y[SEINT];
48+
#endif
49+
50+
51+
// Set the tolerances.
52+
53+
Real sdc_tol_fac = std::pow(sdc_burn_tol_factor, state.num_sdc_iters - state.sdc_iter - 1);
54+
55+
// we use 1-based indexing inside of BackwardEuler, so we need to shift the
56+
// indices SRHO, SFS, etc by 1
57+
58+
Real sdc_min_density = amrex::min(state.rho, state.rho_orig + state.ydot_a[SRHO] * dt);
59+
60+
be.atol_enuc = sdc_min_density * atol_enuc * sdc_tol_fac;
61+
be.rtol_enuc = rtol_enuc * sdc_tol_fac;
62+
63+
// Note: we define the input atol for species to refer only to the
64+
// mass fraction part, and we multiply by a representative density
65+
// so that atol becomes an absolutely tolerance on (rho X)
66+
67+
be.atol_spec = sdc_min_density * atol_spec * sdc_tol_fac;
68+
be.rtol_spec = rtol_spec * sdc_tol_fac;
69+
70+
// Call the integration routine.
71+
72+
int istate = be_integrator(state, be);
73+
74+
// Get the number of RHS and Jacobian evaluations.
75+
76+
state.n_rhs = be.n_rhs;
77+
state.n_jac = be.n_jac;
78+
state.n_step = be.n_step;
79+
80+
// Copy the integration data back to the burn state.
81+
// This will also update the aux state from X if we are using NSE
82+
83+
int_to_burn(be.t, be, state);
84+
85+
// we only evolved (rho e), not (rho E), so we need to update the
86+
// total energy now to ensure we are conservative
87+
88+
Real rho_Sdot = 0.0_rt;
89+
if (state.time > 0) {
90+
rho_Sdot = (be.y(SEINT+1) - state.rhoe_orig) / state.time - state.ydot_a[SEINT];
91+
}
92+
93+
state.y[SEDEN] += state.time * (state.ydot_a[SEDEN] + rho_Sdot);
94+
95+
// also momentum
96+
97+
state.y[SMX] += state.time * state.ydot_a[SMX];
98+
state.y[SMY] += state.time * state.ydot_a[SMY];
99+
state.y[SMZ] += state.time * state.ydot_a[SMZ];
100+
101+
// normalize the abundances on exit. We'll assume that the driver
102+
// calling this is making use of the conserved state (state.y[]),
103+
// so that is what will be normalized.
104+
105+
normalize_abundances_sdc_burn(state);
106+
107+
if (istate < 0) {
108+
state.success = false;
109+
}
110+
111+
112+
#ifndef AMREX_USE_GPU
113+
if (burner_verbose) {
114+
// Print out some integration statistics, if desired.
115+
std::cout << "integration summary: " << std::endl;
116+
std::cout << "dens: " << state.rho << " temp: " << state.T << std::endl;
117+
std::cout << "energy released: " << state.e << std::endl;
118+
std::cout << "number of steps taken: " << state.n_step << std::endl;
119+
std::cout << "number of f evaluations: " << state.n_rhs << std::endl;
120+
}
121+
#endif
122+
123+
// If we failed, print out the current state of the integration.
124+
125+
if (!state.success) {
126+
#ifndef AMREX_USE_GPU
127+
std::cout << Font::Bold << FGColor::Red << "[ERROR] integration failed in net" << ResetDisplay << std::endl;
128+
std::cout << "istate = " << istate << std::endl;
129+
std::cout << "zone = (" << state.i << ", " << state.j << ", " << state.k << ")" << std::endl;
130+
std::cout << "time = " << be.t << std::endl;
131+
std::cout << "dt = " << std::setprecision(16) << dt << std::endl;
132+
std::cout << "dens start = " << std::setprecision(16) << state.rho_orig << std::endl;
133+
std::cout << "temp start = " << std::setprecision(16) << T_in << std::endl;
134+
std::cout << "rhoe start = " << std::setprecision(16) << rhoe_in << std::endl;
135+
std::cout << "xn start = ";
136+
for (int n = 0; n < NumSpec; ++n) {
137+
std::cout << std::setprecision(16) << xn_in[n] << " ";
138+
}
139+
std::cout << std::endl;
140+
#ifdef AUX_THERMO
141+
std::cout << "aux start = ";
142+
for (int n = 0; n < NumAux; ++n) {
143+
std::cout << std::setprecision(16) << aux_in[n] << " ";
144+
}
145+
std::cout << std::endl;
146+
#endif
147+
std::cout << "dens current = " << std::setprecision(16) << state.rho << std::endl;
148+
std::cout << "temp current = " << std::setprecision(16) << state.T << std::endl;
149+
std::cout << "xn current = ";
150+
for (int n = 0; n < NumSpec; ++n) {
151+
std::cout << std::setprecision(16) << state.xn[n] << " ";
152+
}
153+
std::cout << std::endl;
154+
#ifdef AUX_THERMO
155+
std::cout << "aux current = ";
156+
for (int n = 0; n < NumAux; ++n) {
157+
std::cout << std::setprecision(16) << state.aux[n] << " ";
158+
}
159+
std::cout << std::endl;
160+
#endif
161+
std::cout << "A(rho) = " << std::setprecision(16) << state.ydot_a[SRHO] << std::endl;
162+
std::cout << "A(rho e) = " << std::setprecision(16) << state.ydot_a[SEINT] << std::endl;
163+
std::cout << "A(rho X_k) = ";
164+
for (int n = 0; n < NumSpec; n++) {
165+
std::cout << std::setprecision(16) << state.ydot_a[SFS+n] << " ";
166+
}
167+
std::cout << std::endl;
168+
#ifdef AUX_THERMO
169+
std::cout << "A(rho aux_k) = ";
170+
for (int n = 0; n < NumAux; n++) {
171+
std::cout << std::setprecision(16) << state.ydot_a[SFX+n] << " ";
172+
}
173+
std::cout << std::endl;
174+
#endif
175+
#endif
176+
}
177+
178+
179+
}
180+
181+
#endif

integration/BackwardEuler/be_integrator.H

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@
22
#define BE_INTEGRATOR_H
33

44
#include <be_type.H>
5-
#include <integrator_rhs_strang.H>
65
#include <network.H>
76
#include <actual_network.H>
87
#include <actual_rhs.H>
98
#include <burn_type.H>
109
#include <linpack.H>
1110
#include <numerical_jacobian.H>
12-
11+
#ifdef STRANG
12+
#include <integrator_rhs_strang.H>
13+
#endif
14+
#ifdef SIMPLIFIED_SDC
15+
#include <integrator_rhs_simplified_sdc.H>
16+
#endif
1317

1418
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
1519
Real initial_dt (burn_t& state, be_t& be,
@@ -48,9 +52,9 @@ Real initial_dt (burn_t& state, be_t& be,
4852
// routine
4953

5054
for (int ii = 1; ii <= NumSpec; ii++) {
51-
ewt(ii) = rtol_spec * std::abs(y_old(ii)) + atol_spec;
55+
ewt(ii) = be.rtol_spec * std::abs(y_old(ii)) + be.atol_spec;
5256
}
53-
ewt(net_ienuc) = rtol_enuc * std::abs(y_old(net_ienuc)) + atol_enuc;
57+
ewt(net_ienuc) = be.rtol_enuc * std::abs(y_old(net_ienuc)) + be.atol_enuc;
5458

5559
// Construct the trial point.
5660

@@ -143,13 +147,15 @@ int single_step (burn_t& state, be_t& be, const Real dt)
143147

144148
if (be.jacobian_type == 1) {
145149
jac(be.t, state, be, be.jac);
146-
147150
} else {
148151
jac_info_t jac_info;
149152
jac_info.h = dt;
150153
numerical_jac(state, jac_info, be.jac);
154+
be.n_rhs += (NumSpec+1);
151155
}
152156

157+
be.n_jac++;
158+
153159
if (!integrate_energy) {
154160
for (int j = 1; j <= BE_NEQS; j++) {
155161
be.jac(net_ienuc, j) = 0.0_rt;
@@ -242,6 +248,7 @@ int be_integrator (burn_t& state, be_t& be)
242248
{
243249

244250
be.n_rhs = 0;
251+
be.n_jac = 0;
245252
be.n_step = 0;
246253

247254
int ierr;
@@ -304,9 +311,9 @@ int be_integrator (burn_t& state, be_t& be)
304311

305312
Array1D<Real, 1, BE_NEQS> w;
306313
for (int n = 1; n <= NumSpec; n++) {
307-
w(n) = 1.0_rt / (rtol_spec * std::abs(y_fine(n)) + atol_spec);
314+
w(n) = 1.0_rt / (be.rtol_spec * std::abs(y_fine(n)) + be.atol_spec);
308315
}
309-
w(net_ienuc) = 1.0_rt / (rtol_enuc * std::abs(y_fine(net_ienuc)) + atol_enuc);
316+
w(net_ienuc) = 1.0_rt / (be.rtol_enuc * std::abs(y_fine(net_ienuc)) + be.atol_enuc);
310317

311318
// now look for w |y_fine - y_coarse| < 1
312319

integration/BackwardEuler/be_type.H

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
#include <integrator_data.H>
1010
#ifdef STRANG
1111
#include <integrator_type_strang.H>
12-
#include <integrator_rhs_strang.H>
12+
#endif
13+
#ifdef SIMPLIFIED_SDC
14+
#include <integrator_type_simplified_sdc.H>
1315
#endif
1416
#include <network.H>
1517

@@ -50,7 +52,6 @@ struct be_t {
5052
JacNetArray2D jac;
5153

5254
short jacobian_type;
53-
5455
};
5556

5657
#endif

integration/Make.package

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ endif
1414

1515
CEXE_headers += integrator.H
1616
CEXE_headers += integrator_data.H
17-
ifneq ($(USE_TRUE_SDC), TRUE)
18-
CEXE_headers += integrator_type_strang.H
19-
CEXE_headers += integrator_rhs_strang.H
20-
endif
17+
2118
ifeq ($(USE_SIMPLIFIED_SDC), TRUE)
22-
CEXE_headers += integrator_type_simplified_sdc.H
2319
CEXE_headers += integrator_rhs_simplified_sdc.H
20+
CEXE_headers += integrator_type_simplified_sdc.H
21+
else
22+
ifneq ($(USE_TRUE_SDC), TRUE)
23+
CEXE_headers += integrator_type_strang.H
24+
CEXE_headers += integrator_rhs_strang.H
25+
endif
2426
endif
2527

2628
INCLUDE_LOCATIONS += $(MICROPHYSICS_HOME)/integration/utils

integration/VODE/_parameters

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
@namespace: integrator
22

3-
# SDC iteration tolerance adjustment factor
4-
sdc_burn_tol_factor real 1.d0
5-
63
# for the step rejection logic on mass fractions, we only consider
74
# species that are > X_reject_buffer * atol_spec
85
X_reject_buffer real 1.0

integration/_parameters

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,7 @@ use_number_densities logical .false.
7272

7373
# flag for tuning on the subtraction of internal energy
7474
subtract_internal_energy logical .true.
75+
76+
# SDC iteration tolerance adjustment factor
77+
sdc_burn_tol_factor real 1.d0
78+

integration/integrator_rhs_simplified_sdc.H

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include <nonaka_plot.H>
1717
#endif
1818

19-
// The f_rhs routine provides the right-hand-side for the integrator.
19+
// The f_rhs routine provides the right-hand-side for the integration solver.
2020
// This is a generic interface that calls the specific RHS routine in the
2121
// network you're actually using.
2222

integration/integrator_type_simplified_sdc.H

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ void clean_state(const Real time, burn_t& state, T& int_state)
9595
for (int n = 1; n <= NumSpec; ++n) {
9696
// we use 1-based indexing, so we need to offset SFS
9797
int_state.y(SFS+n) = amrex::max(amrex::min(int_state.y(SFS+n), state.rho),
98-
state.rho * SMALL_X_SAFE);
98+
state.rho * SMALL_X_SAFE);
9999
}
100100
}
101101

0 commit comments

Comments
 (0)