Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrea Rovinelli committed Dec 2, 2020
1 parent 87beb7f commit 0cef780
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 1 deletion.
12 changes: 11 additions & 1 deletion framework/include/problems/FEProblemBase.h
Expand Up @@ -99,7 +99,8 @@ enum class MooseNonlinearConvergenceReason
DIVERGED_FUNCTION_COUNT = -2,
DIVERGED_FNORM_NAN = -4,
DIVERGED_LINE_SEARCH = -6,
DIVERGED_DTOL = -9
DIVERGED_DTOL = -9,
DIVERGED_NL_RESIDUAL_PINGPONG = -10
};

// The idea with these enums is to abstract the reasons for
Expand Down Expand Up @@ -1879,6 +1880,11 @@ class FEProblemBase : public SubProblem, public Restartable
const std::vector<Real> * const weights = nullptr,
THREAD_ID tid = 0) override;

void setMaxNLPingPong(const unsigned int n_max_nl_pingpong)
{
_n_max_nl_pingpong = n_max_nl_pingpong;
}

protected:
/// Create extra tagged vectors and matrices
void createTagVectors();
Expand All @@ -1901,6 +1907,10 @@ class FEProblemBase : public SubProblem, public Restartable
Real & _dt;
Real & _dt_old;

/// maximum numbver
unsigned int _n_nl_pingpong = 0;
unsigned int _n_max_nl_pingpong = std::numeric_limits<unsigned int>::max();

std::shared_ptr<NonlinearSystemBase> _nl;
std::shared_ptr<AuxiliarySystem> _aux;

Expand Down
7 changes: 7 additions & 0 deletions framework/src/executioners/FEProblemSolve.C
Expand Up @@ -74,6 +74,11 @@ FEProblemSolve::validParams()
params.addParam<Real>("nl_div_tol", 1.0e10, "Nonlinear Divergence Tolerance");
params.addParam<Real>("nl_abs_step_tol", 0., "Nonlinear Absolute step Tolerance");
params.addParam<Real>("nl_rel_step_tol", 0., "Nonlinear Relative step Tolerance");
params.addParam<unsigned int>(
"n_max_nonlinear_pinpong",
100,
"The maximum number of times the non linear residual can ping pong "
"before requesting halting the current evalution and requesting timestep cut");
params.addParam<bool>(
"snesmf_reuse_base",
true,
Expand Down Expand Up @@ -169,6 +174,8 @@ FEProblemSolve::FEProblemSolve(Executioner * ex)

_problem.skipExceptionCheck(getParam<bool>("skip_exception_check"));

_problem.setMaxNLPingPong(getParam<unsigned int>("n_max_nonlinear_pinpong"));

_nl.setDecomposition(_splitting);
}

Expand Down
27 changes: 27 additions & 0 deletions framework/src/problems/FEProblemBase.C
Expand Up @@ -6559,12 +6559,34 @@ FEProblemBase::checkNonlinearConvergence(std::string & msg,
NonlinearSystemBase & system = getNonlinearSystemBase();
MooseNonlinearConvergenceReason reason = MooseNonlinearConvergenceReason::ITERATING;

Real fnorm_old;
// This is the first residual before any iterations have been done,
// but after preset BCs (if any) have been imposed on the solution
// vector. We save it, and use it to detect convergence if
// compute_initial_residual_before_preset_bcs=false.
if (it == 0)
{
system._initial_residual_after_preset_bcs = fnorm;
fnorm_old = fnorm;
_n_nl_pingpong = 0;
}
else
fnorm_old = system._last_nl_rnorm;

// ping pong will alwasy start with an increase in the residual value.
const bool increase = fnorm > fnorm_old ? true : false;

if (_n_nl_pingpong == 0 && increase)
_n_nl_pingpong += 1;
else if (_n_nl_pingpong == 0 && !increase)
_n_nl_pingpong = 0;
else
{
if ((_n_nl_pingpong % 2 == 1 && !increase) || (_n_nl_pingpong % 2 == 0 && increase))
_n_nl_pingpong += 1;
else
_n_nl_pingpong = 0;
}

std::ostringstream oss;
if (fnorm != fnorm)
Expand Down Expand Up @@ -6614,6 +6636,11 @@ FEProblemBase::checkNonlinearConvergence(std::string & msg,
<< divtol << " * initial residual " << the_residual << '\n';
reason = MooseNonlinearConvergenceReason::DIVERGED_DTOL;
}
else if (_n_nl_pingpong > _n_max_nl_pingpong)
{
oss << "Diverged due to maximum non linear residual pingpong achieved" << '\n';
reason = MooseNonlinearConvergenceReason::DIVERGED_NL_RESIDUAL_PINGPONG;
}
}

system._last_nl_rnorm = fnorm;
Expand Down
4 changes: 4 additions & 0 deletions framework/src/utils/PetscSupport.C
Expand Up @@ -435,6 +435,10 @@ petscNonlinearConverged(SNES snes,
*reason = SNES_DIVERGED_LINE_SEARCH;
#endif
break;

case MooseNonlinearConvergenceReason::DIVERGED_NL_RESIDUAL_PINGPONG:
*reason = SNES_DIVERGED_LINE_SEARCH;
break;
}

return 0;
Expand Down
74 changes: 74 additions & 0 deletions test/tests/executioners/nl_pingpong/nonlinear_residual_pingpong.i
@@ -0,0 +1,74 @@
[Mesh]
type = GeneratedMesh
dim = 2
nx = 4
ny = 4
xmin = -1
xmax = 1
ymin = -1
ymax = 1
[]

[Variables]
[./u]
order = FIRST
family = LAGRANGE
initial_condition = 0.1
[../]
[]

[Kernels]
[./diff]
type = Diffusion
variable = u
[../]
[./power]
type = PReaction
variable = u
coefficient = 0.2
power = -5
# Comment out this will make fixed point iteration converged in one iteration.
# However, this makes the solving diverge and require a proper initial condition (>1.00625).
vector_tags = 'previous'
[../]
[]

[BCs]
[./left]
type = VacuumBC
variable = u
boundary = left
[../]

[./right]
type = NeumannBC
variable = u
boundary = right
value = 10
[../]
[]

[Postprocessors]
[./unorm]
type = ElementL2Norm
variable = u
[../]
[]

[Problem]
type = FixedPointProblem
fp_tag_name = 'previous'
[]

[Executioner]
type = FixedPointSteady
nl_rel_tol = 1e-50
nl_abs_tol = 1e-15
nl_max_its = 50
line_search = none
n_max_nonlinear_pinpong = 2
[]

[Outputs]
exodus = true
[]
10 changes: 10 additions & 0 deletions test/tests/executioners/nl_pingpong/tests
@@ -0,0 +1,10 @@
[Tests]
[./nl_pingpong]
type = RunApp
input = 'nonlinear_residual_pingpong.i'
expect_out = "Nonlinear solve did not converge due to DIVERGED_LINE_SEARCH"
requirement = 'MOOSE shall kill execution when non linear residual pinpong is detected.'
issues = '#16376'
design = 'FEProblemSolve.md'
[../]
[]

0 comments on commit 0cef780

Please sign in to comment.