Skip to content

Commit

Permalink
add fixedpoint_begin and fixedpoint_end execute flag and use_legacy_f…
Browse files Browse the repository at this point in the history
…ixed_point_execute_on idaholab#28930
  • Loading branch information
YaqiWang committed Oct 26, 2024
1 parent 0d384a3 commit 7b767cc
Show file tree
Hide file tree
Showing 13 changed files with 204 additions and 61 deletions.
3 changes: 3 additions & 0 deletions framework/include/executioners/Executioner.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ class Executioner : public MooseObject,
virtual PostprocessorValue & addAttributeReporter(const std::string & name,
Real initial_value = 0);

/// Flag to indicate timestep_begin/end objects are to be executed within a fixed point iteration
const bool _legacy_execute_on;

FEProblemBase & _fe_problem;

MooseEnum _iteration_method;
Expand Down
18 changes: 12 additions & 6 deletions framework/include/executioners/FixedPointSolve.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class FixedPointSolve : public SolveObject

static InputParameters validParams();

/// Custom execute flags for fixed point iterations
static const ExecFlagType EXEC_FIXEDPOINT_BEGIN;
static const ExecFlagType EXEC_FIXEDPOINT_END;

/**
* Iteratively solves the FEProblem.
* @return True if solver is converged.
Expand Down Expand Up @@ -143,8 +147,8 @@ class FixedPointSolve : public SolveObject
/**
* Perform one fixed point iteration or a full solve.
*
* @param begin_norm Residual norm after timestep_begin execution
* @param end_norm Residual norm after timestep_end execution
* @param begin_norm Residual norm after fixedpoint_begin execution
* @param end_norm Residual norm after fixedpoint_end execution
* @param transformed_dofs DoFs targetted by the fixed point algorithm
*
* @return True if both nonlinear solve and the execution of multiapps are successful.
Expand Down Expand Up @@ -193,6 +197,8 @@ class FixedPointSolve : public SolveObject
/// Print information about the fixed point convergence
void printFixedPointConvergenceReason();

/// Flag to indicate timestep_begin/end objects are to be executed within a fixed point iteration
const bool _legacy_execute_on;
/// Minimum fixed point iterations
unsigned int _min_fixed_point_its;
/// Maximum fixed point iterations
Expand Down Expand Up @@ -239,10 +245,10 @@ class FixedPointSolve : public SolveObject
unsigned int _main_fixed_point_it;
/// Initial residual norm
Real _fixed_point_initial_norm;
/// Full history of residual norm after evaluation of timestep_begin
std::vector<Real> _fixed_point_timestep_begin_norm;
/// Full history of residual norm after evaluation of timestep_end
std::vector<Real> _fixed_point_timestep_end_norm;
/// Full history of residual norm after evaluation of fixedpoint_begin
std::vector<Real> _fixed_point_begin_norm;
/// Full history of residual norm after evaluation of fixedpoint_end
std::vector<Real> _fixed_point_end_norm;
/// Status of fixed point solve
MooseFixedPointConvergenceReason _fixed_point_status;
///@}
Expand Down
6 changes: 6 additions & 0 deletions framework/src/base/MooseApp.C
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,12 @@ MooseApp::validParams()
"solution modifying objects are executed prior to the initial (0th nonlinear iteration) "
"residual evaluation. The new behavior skips that redundant residual evaluation unless the "
"parameter Executioner/use_pre_SMO_residual is set to true.");
params.addParam<bool>(
"use_legacy_fixed_point_execute_on",
true,
"The legacy behavior executes objects including aux kernels, user objects, postprocessors, "
"MultiApps, transfers, etc. on timestep_begin and timestep_end within a fixed point "
"iteration.");

params.addParam<bool>(
MeshGeneratorSystem::allow_data_driven_param,
Expand Down
14 changes: 14 additions & 0 deletions framework/src/executioners/Eigenvalue.C
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,14 @@ Eigenvalue::execute()
#endif // LIBMESH_ENABLE_AMR
_eigen_problem.timestepSetup();

if (!_legacy_execute_on)
{
_eigen_problem.execute(EXEC_TIMESTEP_BEGIN);
_time = _time_step;
_eigen_problem.outputStep(EXEC_TIMESTEP_BEGIN);
_time = _system_time;
}

_last_solve_converged = _fixed_point_solve->solve();
if (!lastSolveConverged())
{
Expand All @@ -270,6 +278,12 @@ Eigenvalue::execute()
_eigen_problem.computeIndicators();
_eigen_problem.computeMarkers();
}

if (!_legacy_execute_on)
{
_eigen_problem.onTimestepEnd();
_eigen_problem.execute(EXEC_TIMESTEP_END);
}
// need to keep _time in sync with _time_step to get correct output
_time = _time_step;
_eigen_problem.outputStep(EXEC_TIMESTEP_END);
Expand Down
2 changes: 2 additions & 0 deletions framework/src/executioners/Executioner.C
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Executioner::Executioner(const InputParameters & parameters)
PostprocessorInterface(this),
Restartable(this, "Executioners"),
PerfGraphInterface(this),
_legacy_execute_on(_app.parameters().get<bool>("use_legacy_fixed_point_execute_on")),
_fe_problem(*getCheckedPointerParam<FEProblemBase *>(
"_fe_problem_base", "This might happen if you don't have a mesh")),
_iteration_method(getParam<MooseEnum>("fixed_point_algorithm")),
Expand Down Expand Up @@ -91,6 +92,7 @@ Executioner::Executioner(const InputParameters & parameters, bool)
PostprocessorInterface(this),
Restartable(this, "Executioners"),
PerfGraphInterface(this),
_legacy_execute_on(_app.parameters().get<bool>("use_legacy_fixed_point_execute_on")),
_fe_problem(*getCheckedPointerParam<FEProblemBase *>(
"_fe_problem_base", "This might happen if you don't have a mesh")),
_iteration_method(getParam<MooseEnum>("fixed_point_algorithm")),
Expand Down
105 changes: 73 additions & 32 deletions framework/src/executioners/FixedPointSolve.C
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
#include "AllLocalDofIndicesThread.h"
#include "Console.h"
#include "EigenExecutionerBase.h"
#include "ExecFlagRegistry.h"

const ExecFlagType FixedPointSolve::EXEC_FIXEDPOINT_BEGIN =
registerDefaultExecFlag("FIXEDPOINT_BEGIN");
const ExecFlagType FixedPointSolve::EXEC_FIXEDPOINT_END = registerDefaultExecFlag("FIXEDPOINT_END");

InputParameters
FixedPointSolve::validParams()
Expand Down Expand Up @@ -51,7 +56,8 @@ FixedPointSolve::validParams()
params.addParam<bool>(
"fixed_point_force_norms",
false,
"Force the evaluation of both the TIMESTEP_BEGIN and TIMESTEP_END norms regardless of the "
"Force the evaluation of residual norms after executing objects and MultiApps on "
"fixedpoint_begin and fixedpoint_end regardless of the "
"existence of active MultiApps with those execute_on flags, default: false.");

// Parameters for using a custom postprocessor for convergence checks
Expand Down Expand Up @@ -116,7 +122,7 @@ FixedPointSolve::validParams()
"Maximum number of times to update XFEM crack topology in a step due to evolving cracks");
params.addParam<bool>("update_xfem_at_timestep_begin",
false,
"Should XFEM update the mesh at the beginning of the timestep");
"Should XFEM update the mesh at the beginning of a fixed point iteration");

params.addParamNamesToGroup("max_xfem_update update_xfem_at_timestep_begin",
"XFEM fixed point iterations");
Expand All @@ -126,6 +132,7 @@ FixedPointSolve::validParams()

FixedPointSolve::FixedPointSolve(Executioner & ex)
: SolveObject(ex),
_legacy_execute_on(_app.parameters().get<bool>("use_legacy_fixed_point_execute_on")),
_min_fixed_point_its(getParam<unsigned int>("fixed_point_min_its")),
_max_fixed_point_its(getParam<unsigned int>("fixed_point_max_its")),
_has_fixed_point_its(_max_fixed_point_its > 1),
Expand Down Expand Up @@ -198,18 +205,23 @@ FixedPointSolve::solve()

Real current_dt = _problem.dt();

_fixed_point_timestep_begin_norm.clear();
_fixed_point_timestep_end_norm.clear();
_fixed_point_timestep_begin_norm.resize(_max_fixed_point_its);
_fixed_point_timestep_end_norm.resize(_max_fixed_point_its);
_fixed_point_begin_norm.clear();
_fixed_point_end_norm.clear();
_fixed_point_begin_norm.resize(_max_fixed_point_its);
_fixed_point_end_norm.resize(_max_fixed_point_its);

bool converged = true;

// need to back up multi-apps even when not doing fixed point iteration for recovering from failed
// multiapp solve
_problem.backupMultiApps(EXEC_MULTIAPP_FIXED_POINT_BEGIN);
_problem.backupMultiApps(EXEC_TIMESTEP_BEGIN);
_problem.backupMultiApps(EXEC_TIMESTEP_END);
if (_legacy_execute_on)
{
_problem.backupMultiApps(EXEC_TIMESTEP_BEGIN);
_problem.backupMultiApps(EXEC_TIMESTEP_END);
}
_problem.backupMultiApps(EXEC_FIXEDPOINT_BEGIN);
_problem.backupMultiApps(EXEC_FIXEDPOINT_END);
_problem.backupMultiApps(EXEC_MULTIAPP_FIXED_POINT_END);

// Prepare to relax variables as a main app
Expand Down Expand Up @@ -273,8 +285,13 @@ FixedPointSolve::solve()
{
// For every iteration other than the first, we need to restore the state of the MultiApps
_problem.restoreMultiApps(EXEC_MULTIAPP_FIXED_POINT_BEGIN);
_problem.restoreMultiApps(EXEC_TIMESTEP_BEGIN);
_problem.restoreMultiApps(EXEC_TIMESTEP_END);
if (_legacy_execute_on)
{
_problem.restoreMultiApps(EXEC_TIMESTEP_BEGIN);
_problem.restoreMultiApps(EXEC_TIMESTEP_END);
}
_problem.restoreMultiApps(EXEC_FIXEDPOINT_BEGIN);
_problem.restoreMultiApps(EXEC_FIXEDPOINT_END);
_problem.restoreMultiApps(EXEC_MULTIAPP_FIXED_POINT_END);
}

Expand All @@ -288,8 +305,8 @@ FixedPointSolve::solve()
_pp_old = *_fixed_point_custom_pp;

// Solve a single application for one time step
bool solve_converged = solveStep(_fixed_point_timestep_begin_norm[_fixed_point_it],
_fixed_point_timestep_end_norm[_fixed_point_it],
bool solve_converged = solveStep(_fixed_point_begin_norm[_fixed_point_it],
_fixed_point_end_norm[_fixed_point_it],
transformed_dofs);

// Get new value and print history for the custom postprocessor convergence criterion
Expand Down Expand Up @@ -335,8 +352,8 @@ FixedPointSolve::solve()
current_dt; // _dt might be smaller than this at this point for multistep methods
}

// Save postprocessors after the solve and their potential timestep_end execution
// The postprocessors could be overwritten at timestep_begin, which is why they are saved
// Save postprocessors after the solve and their potential fixedpoint_end execution
// The postprocessors could be overwritten at fixedpoint_begin, which is why they are saved
// after the solve. They could also be saved right after the transfers.
if (_old_entering_time == _problem.time())
savePostprocessorValues(false);
Expand Down Expand Up @@ -377,13 +394,15 @@ FixedPointSolve::solveStep(Real & begin_norm,
bool auto_advance = autoAdvance();

// Compute previous norms for coloring the norm output
Real begin_norm_old = (_fixed_point_it > 0 ? _fixed_point_timestep_begin_norm[_fixed_point_it - 1]
Real begin_norm_old = (_fixed_point_it > 0 ? _fixed_point_begin_norm[_fixed_point_it - 1]
: std::numeric_limits<Real>::max());
Real end_norm_old = (_fixed_point_it > 0 ? _fixed_point_timestep_end_norm[_fixed_point_it - 1]
Real end_norm_old = (_fixed_point_it > 0 ? _fixed_point_end_norm[_fixed_point_it - 1]
: std::numeric_limits<Real>::max());

_executioner.preSolve();
_problem.execTransfers(EXEC_TIMESTEP_BEGIN);
if (_legacy_execute_on)
_problem.execTransfers(EXEC_TIMESTEP_BEGIN);
_problem.execTransfers(EXEC_FIXEDPOINT_BEGIN);

if (_fixed_point_it == 0)
{
Expand All @@ -397,7 +416,12 @@ FixedPointSolve::solveStep(Real & begin_norm,
_problem.outputStep(EXEC_MULTIAPP_FIXED_POINT_BEGIN);
}

if (!_problem.execMultiApps(EXEC_TIMESTEP_BEGIN, auto_advance))
if (_legacy_execute_on && !_problem.execMultiApps(EXEC_TIMESTEP_BEGIN, auto_advance))
{
_fixed_point_status = MooseFixedPointConvergenceReason::DIVERGED_FAILED_MULTIAPP;
return false;
}
if (!_problem.execMultiApps(EXEC_FIXEDPOINT_BEGIN, auto_advance))
{
_fixed_point_status = MooseFixedPointConvergenceReason::DIVERGED_FAILED_MULTIAPP;
return false;
Expand All @@ -406,27 +430,32 @@ FixedPointSolve::solveStep(Real & begin_norm,
if (_problem.haveXFEM() && _update_xfem_at_timestep_begin)
_problem.updateMeshXFEM();

_problem.execute(EXEC_TIMESTEP_BEGIN);
if (_legacy_execute_on)
_problem.execute(EXEC_TIMESTEP_BEGIN);
_problem.execute(EXEC_FIXEDPOINT_BEGIN);

// Transform the fixed point postprocessors before solving, but after the timestep_begin transfers
// have been received
// Transform the fixed point postprocessors before solving, but after the fixedpoint_begin
// transfers have been received
if (_transformed_pps.size() > 0 && useFixedPointAlgorithmUpdateInsteadOfPicard(true))
transformPostprocessors(true);
if (_secondary_transformed_pps.size() > 0 && useFixedPointAlgorithmUpdateInsteadOfPicard(false) &&
_problem.time() == _old_entering_time)
transformPostprocessors(false);

if (_has_fixed_point_its && _has_fixed_point_norm)
if (_problem.hasMultiApps(EXEC_TIMESTEP_BEGIN) || _fixed_point_force_norms)
if ((_legacy_execute_on && _problem.hasMultiApps(EXEC_TIMESTEP_BEGIN)) ||
_problem.hasMultiApps(EXEC_FIXEDPOINT_BEGIN) || _fixed_point_force_norms)
{
begin_norm = _problem.computeResidualL2Norm();

_console << COLOR_MAGENTA << "Fixed point residual norm after TIMESTEP_BEGIN MultiApps: "
_console << COLOR_MAGENTA << "Fixed point residual norm after FIXEDPOINT_BEGIN MultiApps: "
<< Console::outputNorm(begin_norm_old, begin_norm) << std::endl;
}

// Perform output for timestep begin
_problem.outputStep(EXEC_TIMESTEP_BEGIN);
if (_legacy_execute_on)
_problem.outputStep(EXEC_TIMESTEP_BEGIN);
_problem.outputStep(EXEC_FIXEDPOINT_BEGIN);

// Update warehouse active objects
_problem.updateActiveObjects();
Expand Down Expand Up @@ -466,11 +495,22 @@ FixedPointSolve::solveStep(Real & begin_norm,
_console << "\nXFEM did not modify mesh, continuing" << std::endl;
}

_problem.onTimestepEnd();
_problem.execute(EXEC_TIMESTEP_END);
if (_legacy_execute_on)
{
_problem.onTimestepEnd();
_problem.execute(EXEC_TIMESTEP_END);

_problem.execTransfers(EXEC_TIMESTEP_END);
if (!_problem.execMultiApps(EXEC_TIMESTEP_END, auto_advance))
{
_fixed_point_status = MooseFixedPointConvergenceReason::DIVERGED_FAILED_MULTIAPP;
return false;
}
}
_problem.execute(EXEC_FIXEDPOINT_END);

_problem.execTransfers(EXEC_TIMESTEP_END);
if (!_problem.execMultiApps(EXEC_TIMESTEP_END, auto_advance))
_problem.execTransfers(EXEC_FIXEDPOINT_END);
if (!_problem.execMultiApps(EXEC_FIXEDPOINT_END, auto_advance))
{
_fixed_point_status = MooseFixedPointConvergenceReason::DIVERGED_FAILED_MULTIAPP;
return false;
Expand All @@ -486,11 +526,12 @@ FixedPointSolve::solveStep(Real & begin_norm,
_executioner.postSolve();

if (_has_fixed_point_its && _has_fixed_point_norm)
if (_problem.hasMultiApps(EXEC_TIMESTEP_END) || _fixed_point_force_norms)
if ((_legacy_execute_on && _problem.hasMultiApps(EXEC_TIMESTEP_END)) ||
_problem.hasMultiApps(EXEC_FIXEDPOINT_END) || _fixed_point_force_norms)
{
end_norm = _problem.computeResidualL2Norm();

_console << COLOR_MAGENTA << "Fixed point residual norm after TIMESTEP_END MultiApps: "
_console << COLOR_MAGENTA << "Fixed point residual norm after FIXEDPOINT_END MultiApps: "
<< Console::outputNorm(end_norm_old, end_norm) << std::endl;
}

Expand All @@ -516,8 +557,8 @@ FixedPointSolve::examineFixedPointConvergence(bool & converged)
{
if (_fixed_point_it + 2 > _min_fixed_point_its)
{
Real max_norm = std::max(_fixed_point_timestep_begin_norm[_fixed_point_it],
_fixed_point_timestep_end_norm[_fixed_point_it]);
Real max_norm =
std::max(_fixed_point_begin_norm[_fixed_point_it], _fixed_point_end_norm[_fixed_point_it]);

Real max_relative_drop = max_norm / _fixed_point_initial_norm;

Expand Down
11 changes: 5 additions & 6 deletions framework/src/executioners/PicardSolve.C
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ PicardSolve::validParams()
"picard_max_its",
1,
"Specifies the maximum number of Picard iterations. "
"Mainly used when wanting to do Picard iterations with MultiApps "
"that are set to execute_on timestep_end or timestep_begin. "
"Mainly used when wanting to do Picard iterations with MultiApps "
"that are set to execute_on fixedpoint_end or fixedpoint_begin. "
"Setting this parameter to 1 turns off the Picard iterations.",
"Deprecated, use fixed_point_max_its");
params.addDeprecatedParam<bool>(
Expand Down Expand Up @@ -60,8 +60,8 @@ PicardSolve::validParams()
params.addDeprecatedParam<bool>(
"picard_force_norms",
false,
"Force the evaluation of both the TIMESTEP_BEGIN and TIMESTEP_END norms regardless of the "
"existence of active MultiApps with those execute_on flags, default: false.",
"Force the evaluation of both the FIXEDPOINT_BEGIN and FIXEDPOINT_END norms regardless of "
"the existence of active MultiApps with those execute_on flags, default: false.",
"Deprecated, use fixed_point_force_norms");

return params;
Expand Down Expand Up @@ -265,8 +265,7 @@ PicardSolve::printFixedPointConvergenceHistory()
Real max_norm_old = _fixed_point_initial_norm;
for (unsigned int i = 0; i <= _fixed_point_it; ++i)
{
Real max_norm =
std::max(_fixed_point_timestep_begin_norm[i], _fixed_point_timestep_end_norm[i]);
Real max_norm = std::max(_fixed_point_begin_norm[i], _fixed_point_end_norm[i]);
_console << std::setw(2) << i + 1
<< " Picard |R| = " << Console::outputNorm(max_norm_old, max_norm) << '\n';
max_norm_old = max_norm;
Expand Down
Loading

0 comments on commit 7b767cc

Please sign in to comment.