Skip to content

Commit

Permalink
Merge pull request #326 from JamesMcClung/pr/tfield-fix
Browse files Browse the repository at this point in the history
Properly fix when OutputFieldsDefault writes output
  • Loading branch information
germasch authored Sep 28, 2023
2 parents 9978ca6 + a059e51 commit 5e20470
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 64 deletions.
101 changes: 71 additions & 30 deletions src/include/OutputFieldsDefault.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,65 @@ auto make_mfields_gt(E&& gt, const std::string& name,
return mfields_gt<E>{std::forward<E>(gt), name, comp_names};
}

// ======================================================================
// BaseOutputFieldItemParams

struct BaseOutputFieldItemParams
{
int out_interval = 0; // difference between output timesteps (0 = disable)
int out_first = 0; // first output timestep

bool enabled() { return out_interval > 0; }

// Returns whether to write out on this timestep, given the next timestep to
// write on. Ignores `out_interval` and `do_first` except to check
// `enabled()`. In most cases, the given `next_out` equals `next_out() -
// out_interval`, but not when resuming from a checkpoint.
bool do_out(int timestep, int next_out)
{
bool on_out_step = timestep >= next_out;
return enabled() && on_out_step;
}

// Returns the next output timestep after the given timestep.
int next_out(int timestep)
{
if (timestep < out_first)
return out_first;
int n_intervals_elapsed = (timestep - out_first) / out_interval;
return out_first + out_interval * (n_intervals_elapsed + 1);
}
};

struct OutputPfieldItemParams : BaseOutputFieldItemParams
{};

struct OutputTfieldItemParams : BaseOutputFieldItemParams
{
// max range of timesteps over which to average (capped at `out_interval`)
int average_length = 1000000;
// difference between timesteps used for average
int average_every = 1;

// Returns whether to accumulate on this timestep, given the next timestep to
// write on. Like `do_out()`, ignores `out_interval` and `out_first` and
// trusts that `next_out` is correct.
bool do_accum(int timestep, int next_out)
{
bool in_averaging_range = next_out - timestep < average_length;
bool on_averaging_step = (next_out - timestep) % average_every == 0;
return enabled() && in_averaging_range && on_averaging_step;
}
};

// ======================================================================
// OutputFieldsItemParams

struct OutputFieldsItemParams
{
std::string data_dir = ".";
int pfield_interval = 0;
int pfield_first = 0;
int tfield_interval = 0;
int tfield_first = 0;
int tfield_average_every = 1;
OutputPfieldItemParams pfield;
OutputTfieldItemParams tfield;
Int3 rn = {};
Int3 rx = {10000000, 10000000, 10000000};
};
Expand All @@ -85,15 +133,13 @@ class OutputFieldsItem : public OutputFieldsItemParams
OutputFieldsItem(const Grid_t& grid, const OutputFieldsItemParams& prm,
std::string sfx)
: OutputFieldsItemParams{prm},
pfield_next_{prm.pfield_first},
tfield_next_{prm.tfield_first}
pfield_next_{prm.pfield.out_first},
tfield_next_{prm.tfield.out_first}
{
if (pfield_interval > 0) {
if (pfield.enabled())
io_pfd_.open("pfd" + sfx, prm.data_dir);
}
if (tfield_interval > 0) {
if (tfield.enabled())
io_tfd_.open("tfd" + sfx, prm.data_dir);
}
}

template <typename F>
Expand All @@ -108,25 +154,20 @@ class OutputFieldsItem : public OutputFieldsItemParams
}

int timestep = grid.timestep();
if (first_time_) {
first_time_ = false;
if (timestep != 0) {
pfield_next_ = timestep + pfield_interval;
tfield_next_ = timestep + tfield_interval;

tfield_next_ = timestep / tfield_interval * tfield_interval;
if (timestep % tfield_interval > 0)
tfield_next_ += tfield_interval;
}
bool restarting_from_checkpoint = first_time_ && timestep != 0;
if (restarting_from_checkpoint) {
if (pfield.enabled())
pfield_next_ = pfield.next_out(timestep);
if (tfield.enabled())
tfield_next_ = tfield.next_out(timestep);
}
first_time_ = false;

bool do_pfield = pfield_interval > 0 && timestep >= pfield_next_;
bool do_tfield = tfield_interval > 0 && timestep >= tfield_next_;
bool doaccum_tfield = timestep >= (tfield_next_ - tfield_average_every + 1);
doaccum_tfield = doaccum_tfield && (tfield_interval > 0);
doaccum_tfield = doaccum_tfield || (timestep == 0);
bool do_pfield = pfield.do_out(timestep, pfield_next_);
bool do_tfield = tfield.do_out(timestep, tfield_next_);
bool do_tfield_accum = tfield.do_accum(timestep, tfield_next_);

if (do_pfield || doaccum_tfield) {
if (do_pfield || do_tfield_accum) {
prof_start(pr_eval);
auto&& item = get_item();
auto&& pfd = psc::mflds::interior(grid, item.gt);
Expand All @@ -136,12 +177,12 @@ class OutputFieldsItem : public OutputFieldsItemParams
prof_start(pr_pfd);
mpi_printf(grid.comm(), "***** Writing PFD output for '%s'\n",
item.name.c_str());
pfield_next_ += pfield_interval;
pfield_next_ += pfield.out_interval;
io_pfd_.write_step(grid, rn, rx, pfd, item.name, item.comp_names);
prof_stop(pr_pfd);
}

if (doaccum_tfield) {
if (do_tfield_accum) {
if (!tfd_) {
tfd_.reset(new Mfields{grid, item.gt.shape(3), {}});
}
Expand All @@ -157,7 +198,7 @@ class OutputFieldsItem : public OutputFieldsItemParams
prof_start(pr_tfd);
mpi_printf(grid.comm(), "***** Writing TFD output for '%s'\n",
item.name.c_str());
tfield_next_ += tfield_interval;
tfield_next_ += tfield.out_interval;

// convert accumulated values to correct temporal mean
tfd_->gt() = (1. / naccum_) * tfd_->gt();
Expand Down
70 changes: 64 additions & 6 deletions src/libpsc/tests/test_mfields_io.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ TYPED_TEST(OutputFieldsTest, OutputFieldsMRC)

OutputFieldsParams outf_params{};
OutputFieldsItemParams outf_item_params{};
outf_item_params.pfield_interval = 1;
outf_item_params.tfield_interval = 0;
outf_item_params.tfield_average_every = 40;
outf_item_params.pfield.out_interval = 1;
outf_item_params.tfield.out_interval = 0;
outf_item_params.tfield.average_every = 40;
outf_params.fields = outf_item_params;
outf_params.moments = outf_item_params;
OutputFields<Mfields, Mparticles, dim_xyz, WriterMRC> outf{grid, outf_params};
Expand All @@ -210,9 +210,9 @@ TYPED_TEST(OutputFieldsTest, OutputFieldsADIOS2)

OutputFieldsParams outf_params{};
OutputFieldsItemParams outf_item_params{};
outf_item_params.pfield_interval = 1;
outf_item_params.tfield_interval = 0;
outf_item_params.tfield_average_every = 40;
outf_item_params.pfield.out_interval = 1;
outf_item_params.tfield.out_interval = 0;
outf_item_params.tfield.average_every = 40;
outf_params.fields = outf_item_params;
outf_params.moments = outf_item_params;
OutputFields<Mfields, Mparticles, dim_xyz, WriterADIOS2> outf{grid,
Expand All @@ -223,6 +223,64 @@ TYPED_TEST(OutputFieldsTest, OutputFieldsADIOS2)

#endif

// ======================================================================
// OutputFieldsParamsTest test suite

TEST(OutputFieldsParamsTest, Enabled)
{
BaseOutputFieldItemParams prm;
EXPECT_FALSE(prm.enabled());
prm.out_interval = 1;
EXPECT_TRUE(prm.enabled());
}

TEST(OutputFieldsParamsTest, DoOut)
{
BaseOutputFieldItemParams prm;
EXPECT_FALSE(prm.do_out(0, 0)); // should be disabled
prm.out_interval = 10; // now enabled
EXPECT_TRUE(prm.do_out(0, 0));

prm.out_first = 100;
EXPECT_FALSE(prm.do_out(0, 1));
EXPECT_TRUE(prm.do_out(1, 1));
}

TEST(OutputFieldsParamsTest, NextOut)
{
BaseOutputFieldItemParams prm;
prm.out_interval = 100;
EXPECT_EQ(prm.next_out(0), 100);
prm.out_first = 1;
EXPECT_EQ(prm.next_out(0), 1);
EXPECT_EQ(prm.next_out(1), 101);
EXPECT_EQ(prm.next_out(50), 101);
EXPECT_EQ(prm.next_out(100), 101);
EXPECT_EQ(prm.next_out(101), 201);
}

TEST(OutputFieldsParamsTest, Tfield_DoAccum)
{
OutputTfieldItemParams prm; // default: use every step between outs
EXPECT_FALSE(prm.do_accum(0, 0)); // should be disabled
prm.out_interval = 100; // now enabled
EXPECT_TRUE(prm.do_accum(0, 0)); // accum on out step itself

EXPECT_TRUE(prm.do_accum(0, 100));
prm.average_length = 50;
EXPECT_FALSE(prm.do_accum(0, 100));
EXPECT_FALSE(prm.do_accum(50, 100));
EXPECT_TRUE(prm.do_accum(51, 100));
EXPECT_TRUE(prm.do_accum(52, 100));
EXPECT_TRUE(prm.do_accum(53, 100));

prm.average_every = 2;
EXPECT_FALSE(prm.do_accum(51, 100));
EXPECT_TRUE(prm.do_accum(52, 100));
EXPECT_FALSE(prm.do_accum(53, 100));
EXPECT_TRUE(prm.do_accum(100, 100));
}

// ======================================================================
// main

Expand Down
14 changes: 7 additions & 7 deletions src/psc_2d_shock.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -465,16 +465,16 @@ void run()
OutputFieldsItemParams outf_item_params{};
OutputFieldsParams outf_params{};
#if CASE == CASE_1D
outf_item_params.pfield_interval = 5000;
outf_item_params.tfield_interval = 5000;
outf_item_params.pfield.out_interval = 5000;
outf_item_params.tfield.out_interval = 5000;
#elif CASE == CASE_2D_SMALL
outf_item_params.pfield_interval = 10000;
outf_item_params.tfield_interval = 10000;
outf_item_params.pfield.out_interval = 10000;
outf_item_params.tfield.out_interval = 10000;
#else
outf_item_params.pfield_interval = 1500;
outf_item_params.tfield_interval = 1500;
outf_item_params.pfield.out_interval = 1500;
outf_item_params.tfield.out_interval = 1500;
#endif
outf_item_params.tfield_average_every = 50;
outf_item_params.tfield.average_every = 50;

outf_params.fields = outf_item_params;
outf_params.moments = outf_item_params;
Expand Down
4 changes: 2 additions & 2 deletions src/psc_bgk.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -468,8 +468,8 @@ static void run(int argc, char** argv)

// -- output fields
OutputFieldsParams outf_params{};
outf_params.fields.pfield_interval = g.fields_every;
outf_params.moments.pfield_interval = g.moments_every;
outf_params.fields.pfield.out_interval = g.fields_every;
outf_params.moments.pfield.out_interval = g.moments_every;
OutputFields<MfieldsState, Mparticles, Dim> outf{grid, outf_params};

// -- output particles
Expand Down
2 changes: 1 addition & 1 deletion src/psc_bubble_yz.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ static void run()

// -- output fields
OutputFieldsParams outf_params{};
outf_params.fields.pfield_interval = 200;
outf_params.fields.pfield.out_interval = 200;
OutputFields<MfieldsState, Mparticles, Dim> outf{grid, outf_params};

// -- output particles
Expand Down
16 changes: 8 additions & 8 deletions src/psc_flatfoil_yz.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -516,19 +516,19 @@ void run()
OutputFieldsItemParams outf_item_params{};
OutputFieldsParams outf_params{};
#if CASE == CASE_1D
outf_item_params.pfield_interval = 100;
outf_item_params.tfield_interval = -100;
outf_item_params.pfield.out_interval = 100;
outf_item_params.tfield.out_interval = -100;
#elif CASE == CASE_2D_SMALL
outf_item_params.pfield_interval = 4;
outf_item_params.tfield_interval = 4;
outf_item_params.pfield.out_interval = 4;
outf_item_params.tfield.out_interval = 4;
#else
outf_item_params.pfield_interval = 500;
outf_item_params.tfield_interval = 500;
outf_item_params.pfield.out_interval = 500;
outf_item_params.tfield.out_interval = 500;
#endif
#if CASE == CASE_2D_SMALL
outf_item_params.tfield_average_every = 2;
outf_item_params.tfield.average_every = 2;
#else
outf_item_params.tfield_average_every = 50;
outf_item_params.tfield.average_every = 50;
#endif

outf_params.fields = outf_item_params;
Expand Down
12 changes: 6 additions & 6 deletions src/psc_harris_xz.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,8 @@ class Diagnostics
MPI_Comm comm = grid.comm();

int timestep = grid.timestep();
if (outf_.fields.pfield_interval > 0 &&
timestep % outf_.fields.pfield_interval == 0) {
if (outf_.fields.pfield.out_interval > 0 &&
timestep % outf_.fields.pfield.out_interval == 0) {
mpi_printf(comm, "***** Writing PFD output\n");
io_pfd_.begin_step(grid);

Expand All @@ -536,7 +536,7 @@ class Diagnostics
io_pfd_.end_step();
}

if (outf_.fields.tfield_interval > 0) {
if (outf_.fields.tfield.out_interval > 0) {
auto result_state = outf_state_(mflds);

for (int p = 0; p < mflds_acc_state_.n_patches(); p++) {
Expand All @@ -562,7 +562,7 @@ class Diagnostics

n_accum_++;

if (timestep % outf_.fields.tfield_interval == 0) {
if (timestep % outf_.fields.tfield.out_interval == 0) {
mpi_printf(comm, "***** Writing TFD output\n");
io_tfd_.begin_step(grid);
mflds_acc_state_.storage() =
Expand Down Expand Up @@ -874,9 +874,9 @@ void run()
// -- output fields
OutputFieldsParams outf_params;
double output_field_interval = .1;
outf_params.fields.pfield_interval = 100;
outf_params.fields.pfield.out_interval = 100;
// int((output_field_interval / (phys.wci * grid.dt)));
outf_params.fields.tfield_interval = -1;
outf_params.fields.tfield.out_interval = -1;
// int((output_field_interval / (phys.wci * grid.dt)));
OutputFields<MfieldsState, Mparticles, dim_xz> outf{grid, outf_params};

Expand Down
6 changes: 3 additions & 3 deletions src/psc_harris_yz.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,9 @@ void run()
// -- output fields
OutputFieldsItemParams outf_item_params{};
OutputFieldsParams outf_params{};
outf_item_params.pfield_interval = 100;
outf_item_params.tfield_interval = -4;
outf_item_params.tfield_average_every = 50;
outf_item_params.pfield.out_interval = 100;
outf_item_params.tfield.out_interval = -4;
outf_item_params.tfield.average_every = 50;

outf_params.fields = outf_item_params;
outf_params.moments = outf_item_params;
Expand Down
2 changes: 1 addition & 1 deletion src/psc_whistler.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ void run()

// -- output fields
OutputFieldsParams outf_params{};
outf_params.fields.pfield_interval = 200;
outf_params.fields.pfield.out_interval = 200;
OutputFields<MfieldsState, Mparticles, Dim> outf{grid, outf_params};

// -- output particles
Expand Down

0 comments on commit 5e20470

Please sign in to comment.