Skip to content

Commit 547b24a

Browse files
authored
Post processing logic fix (#1683)
* unit tests to check output at end, use of delay. time_output_end currently fails * modify enforce test to differentiate between time and step intervals * fixing unit test * adding unit test for aborts * add information to documentation * remove unused variable
1 parent 56f79ad commit 547b24a

File tree

4 files changed

+182
-9
lines changed

4 files changed

+182
-9
lines changed

amr-wind/utilities/PostProcessing.H

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ public:
114114
"enforce_output_time_dt is true, but output_time_interval "
115115
"has not been specified.");
116116
}
117+
118+
// Because of default, turn off step interval when time interval is
119+
// meant to replace it
120+
if (has_valid_time_int && !(has_interval || has_frequency)) {
121+
m_out_interval = -1;
122+
}
117123
}
118124

119125
//! Determine if output will happen this time step

docs/sphinx/user/inputs_post_processing.rst

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ actual keyword is determined by the labels provided to
1313
``incflo.post_processing = my_postproc``, then the options must be prefixed with
1414
``my_postproc.``.
1515

16+
For post-processing If plotfile output is active,
17+
a plotfile will be written at the end of a simulation (when
18+
:input_param:`time.stop_time` or :input_param:`time.max_step` is reached), regardless
19+
of the output timing parameters.
20+
1621
.. input_param:: postproc.type
1722

1823
**type:** String, optional, default = Sampling
@@ -24,7 +29,10 @@ data via fields that are output to plotfiles; therefore, these types do
2429
not have specific outputs to files in the post_processing directory. However,
2530
for the rest of these routines, which do output data to post-processing files,
2631
there are general input arguments to designate when to write these files,
27-
and these arguments are described below.
32+
and these arguments are described below. Note that for these post-processing types,
33+
output will automatically occur at the end of a simulation (when
34+
:input_param:`time.stop_time` or :input_param:`time.max_step` is reached), regardless
35+
of the output timing parameters.
2836

2937
.. input_param:: postproc.output_interval
3038

@@ -33,7 +41,7 @@ and these arguments are described below.
3341
Specify the output interval (in time steps) when post-processing is performed
3442
and output to disk. This quantity can instead be specified as ``output_frequency``,
3543
which was the legacy input argument. Because ``output_interval`` is a more
36-
accurate name, this is the preferred input argument.
44+
accurate name, this is the preferred input argument.
3745

3846
.. input_param:: postproc.output_time_interval
3947

docs/sphinx/user/inputs_time.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,10 @@ This section also addresses the time-dependent nature of checkpoint files, plot
111111
**type:** Integer, optional, default = -1
112112

113113
If this value is greater than zero, it indicates the frequency (in timesteps)
114-
at which outputs (plot files) are written to disk.
114+
at which outputs (plot files) are written to disk. If plotfile output is active,
115+
a plotfile will be written at the end of a simulation (when
116+
:input_param:`time.stop_time` or :input_param:`time.max_step` is reached), regardless
117+
of the output timing parameters.
115118

116119
.. input_param:: time.plot_time_interval
117120

@@ -147,7 +150,10 @@ This section also addresses the time-dependent nature of checkpoint files, plot
147150
**type:** Integer
148151

149152
If this value is greater than zero, it indicates the frequency (in timesteps)
150-
at which checkpoint (restart) files are written to disk.
153+
at which checkpoint (restart) files are written to disk. If checkpoint output is active,
154+
a checkpoint will be written at the end of a simulation (when
155+
:input_param:`time.stop_time` or :input_param:`time.max_step` is reached), regardless
156+
of the output timing parameters.
151157

152158
.. input_param:: time.checkpoint_time_interval
153159

unit_tests/utilities/test_post_processing_time.cpp

Lines changed: 158 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,11 @@ TEST_F(PostProcTimeTest, enforce_time_interval)
9494
{
9595
amrex::ParmParse pp("time");
9696
pp.add("stop_time", 1.0);
97-
pp.add("max_step", 10);
97+
pp.add("max_step", 20);
9898
}
9999
{
100100
amrex::ParmParse pp("fnorm");
101-
pp.add("output_time_interval", 0.5);
101+
pp.add("output_time_interval", 0.45);
102102
pp.add("enforce_output_time_dt", true);
103103
}
104104
initialize_mesh();
@@ -136,14 +136,167 @@ TEST_F(PostProcTimeTest, enforce_time_interval)
136136
out_time_sum += data_time;
137137
}
138138

139-
EXPECT_EQ(out_counter, 1 + 2);
140-
EXPECT_NEAR(out_time_sum, 1.5, 1e-8);
141-
EXPECT_EQ(out_step_sum, 2 + 6);
139+
EXPECT_EQ(out_counter, 3);
140+
EXPECT_NEAR(out_time_sum, 0. + 0.45 + 2. * 0.45, 1e-8);
141+
EXPECT_EQ(out_step_sum, 2 + 9);
142142

143143
// Remove file
144144
if (ifh.good()) {
145145
remove(fname.c_str());
146146
}
147147
}
148148

149+
TEST_F(PostProcTimeTest, output_end)
150+
{
151+
populate_parameters();
152+
{
153+
amrex::ParmParse pp("time");
154+
pp.add("fixed_dt", 0.3);
155+
pp.add("stop_time", 10.0);
156+
pp.add("max_step", 21);
157+
}
158+
{
159+
amrex::ParmParse pp("fnorm");
160+
pp.add("output_delay", 1000);
161+
}
162+
initialize_mesh();
163+
164+
auto& m_sim = sim();
165+
amr_wind::PostProcessManager& post_manager = m_sim.post_manager();
166+
auto& time = sim().time();
167+
post_manager.pre_init_actions();
168+
post_manager.post_init_actions();
169+
170+
int out_counter = 0;
171+
amrex::Real out_time_sum = 0.0;
172+
int out_step_sum = 0;
173+
while (time.new_timestep()) {
174+
time.set_current_cfl(0.45 / 0.3, 0.0, 0.0);
175+
time.advance_time();
176+
post_manager.post_advance_work();
177+
}
178+
post_manager.final_output();
179+
180+
// Read file output for time steps, times
181+
std::string fname = "post_processing/fnorm00000.txt";
182+
std::ifstream ifh(fname, std::ios::in);
183+
if (!ifh.good()) {
184+
amrex::Abort("Cannot find file: " + fname);
185+
}
186+
int data_tstep;
187+
amrex::Real data_time;
188+
ifh.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
189+
while (ifh >> data_tstep) {
190+
ifh >> data_time;
191+
++out_counter;
192+
out_step_sum += data_tstep;
193+
out_time_sum += data_time;
194+
}
195+
196+
EXPECT_EQ(out_counter, 1);
197+
EXPECT_NEAR(out_time_sum, 6.3, 1e-8);
198+
EXPECT_EQ(out_step_sum, 21);
199+
200+
// Remove file
201+
if (ifh.good()) {
202+
remove(fname.c_str());
203+
}
204+
}
205+
206+
TEST_F(PostProcTimeTest, time_output_end)
207+
{
208+
populate_parameters();
209+
{
210+
amrex::ParmParse pp("time");
211+
pp.add("fixed_dt", 0.3);
212+
pp.add("stop_time", 10.0);
213+
pp.add("max_step", 21);
214+
}
215+
{
216+
amrex::ParmParse pp("fnorm");
217+
pp.add("output_time_interval", 1.0);
218+
pp.add("output_time_delay", 1000.0);
219+
}
220+
initialize_mesh();
221+
222+
auto& m_sim = sim();
223+
amr_wind::PostProcessManager& post_manager = m_sim.post_manager();
224+
auto& time = sim().time();
225+
post_manager.pre_init_actions();
226+
post_manager.post_init_actions();
227+
228+
int out_counter = 0;
229+
amrex::Real out_time_sum = 0.0;
230+
int out_step_sum = 0;
231+
while (time.new_timestep()) {
232+
time.set_current_cfl(0.45 / 0.3, 0.0, 0.0);
233+
time.advance_time();
234+
post_manager.post_advance_work();
235+
}
236+
post_manager.final_output();
237+
238+
// Read file output for time steps, times
239+
std::string fname = "post_processing/fnorm00000.txt";
240+
std::ifstream ifh(fname, std::ios::in);
241+
if (!ifh.good()) {
242+
amrex::Abort("Cannot find file: " + fname);
243+
}
244+
int data_tstep;
245+
amrex::Real data_time;
246+
ifh.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
247+
while (ifh >> data_tstep) {
248+
ifh >> data_time;
249+
++out_counter;
250+
out_step_sum += data_tstep;
251+
out_time_sum += data_time;
252+
}
253+
254+
EXPECT_EQ(out_counter, 1);
255+
EXPECT_NEAR(out_time_sum, 6.3, 1e-8);
256+
EXPECT_EQ(out_step_sum, 21);
257+
258+
// Remove file
259+
if (ifh.good()) {
260+
remove(fname.c_str());
261+
}
262+
}
263+
264+
TEST_F(PostProcTimeTest, conflict_fails)
265+
{
266+
populate_parameters();
267+
initialize_mesh();
268+
269+
auto& m_sim = sim();
270+
amr_wind::PostProcessManager& post_manager = m_sim.post_manager();
271+
post_manager.pre_init_actions();
272+
// Confirm no fail with default arguments
273+
post_manager.post_init_actions();
274+
// Confirm no fail with time interval
275+
{
276+
amrex::ParmParse pp("fnorm");
277+
pp.add("output_time_interval", 1.0);
278+
}
279+
post_manager.post_init_actions();
280+
// Should fail when overspecified arguments
281+
{
282+
amrex::ParmParse pp("fnorm");
283+
pp.add("output_interval", 1);
284+
}
285+
EXPECT_THROW(post_manager.post_init_actions(), std::runtime_error);
286+
// Should fail when both invalid
287+
{
288+
amrex::ParmParse pp("fnorm");
289+
pp.add("output_interval", -1);
290+
pp.add("output_time_interval", -1.0);
291+
}
292+
EXPECT_THROW(post_manager.post_init_actions(), std::runtime_error);
293+
// Should fail for combination of enforce and step interval
294+
{
295+
amrex::ParmParse pp("fnorm");
296+
pp.add("output_interval", 1);
297+
pp.add("enforce_output_time_dt", true);
298+
}
299+
EXPECT_THROW(post_manager.post_init_actions(), std::runtime_error);
300+
}
301+
149302
} // namespace amr_wind_tests

0 commit comments

Comments
 (0)