LCOV - code coverage report
Current view: top level - src/convergence - ReferenceResidualConvergence.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 214 271 79.0 %
Date: 2025-07-17 01:28:37 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : // MOOSE includes
      11             : #include "ReferenceResidualConvergence.h"
      12             : #include "ReferenceResidualProblem.h"
      13             : #include "FEProblemBase.h"
      14             : #include "PetscSupport.h"
      15             : #include "Executioner.h"
      16             : #include "NonlinearSystemBase.h"
      17             : #include "TaggingInterface.h"
      18             : #include "AuxiliarySystem.h"
      19             : #include "MooseVariableScalar.h"
      20             : #include "NonlinearSystem.h"
      21             : 
      22             : // PETSc includes
      23             : #include <petscsnes.h>
      24             : 
      25             : registerMooseObject("MooseApp", ReferenceResidualConvergence);
      26             : 
      27             : InputParameters
      28       15080 : ReferenceResidualConvergence::validParams()
      29             : {
      30       15080 :   InputParameters params = DefaultNonlinearConvergence::validParams();
      31       15080 :   params += ReferenceResidualInterface::validParams();
      32             : 
      33       15080 :   params.addClassDescription(
      34             :       "Check the convergence of a problem with respect to a user-supplied reference solution."
      35             :       " Replaces ReferenceResidualProblem, currently still used in conjunction with it.");
      36             : 
      37       15080 :   return params;
      38           0 : }
      39             : 
      40         435 : ReferenceResidualConvergence::ReferenceResidualConvergence(const InputParameters & parameters)
      41             :   : DefaultNonlinearConvergence(parameters),
      42             :     ReferenceResidualInterface(this),
      43         435 :     _reference_vector(nullptr),
      44         435 :     _converge_on(getParam<std::vector<NonlinearVariableName>>("converge_on")),
      45         435 :     _zero_ref_type(
      46         435 :         getParam<MooseEnum>("zero_reference_residual_treatment").getEnum<ZeroReferenceType>()),
      47         435 :     _reference_vector_tag_id(Moose::INVALID_TAG_ID),
      48         870 :     _initialized(false)
      49             : {
      50         435 :   if (parameters.isParamValid("solution_variables"))
      51             :   {
      52          13 :     if (parameters.isParamValid("reference_vector"))
      53          13 :       mooseDeprecated("The `solution_variables` parameter is deprecated, has no effect when "
      54             :                       "the tagging system is used, and will be removed on January 1, 2020. "
      55             :                       "Please simply delete this parameter from your input file.");
      56          13 :     _soln_var_names = parameters.get<std::vector<NonlinearVariableName>>("solution_variables");
      57             :   }
      58             : 
      59         870 :   if (parameters.isParamValid("reference_residual_variables") &&
      60         435 :       parameters.isParamValid("reference_vector"))
      61           0 :     mooseError(
      62             :         "You may specify either the `reference_residual_variables` "
      63             :         "or `reference_vector` parameter, not both. `reference_residual_variables` is deprecated "
      64             :         "so we recommend using `reference_vector`");
      65             : 
      66         435 :   if (parameters.isParamValid("reference_residual_variables"))
      67             :   {
      68           0 :     mooseDeprecated(
      69             :         "The save-in method for composing reference residual quantities is deprecated "
      70             :         "and will be removed on January 1, 2020. Please use the tagging system instead; "
      71             :         "specifically, please assign a TagName to the `reference_vector` parameter");
      72             : 
      73             :     _ref_resid_var_names =
      74           0 :         parameters.get<std::vector<AuxVariableName>>("reference_residual_variables");
      75             : 
      76           0 :     if (_soln_var_names.size() != _ref_resid_var_names.size())
      77           0 :       mooseError("Size of solution_variables (",
      78           0 :                  _soln_var_names.size(),
      79             :                  ") != size of reference_residual_variables (",
      80           0 :                  _ref_resid_var_names.size(),
      81             :                  ")");
      82             :   }
      83         435 :   else if (parameters.isParamValid("reference_vector"))
      84             :   {
      85         391 :     if (_fe_problem.numNonlinearSystems() > 1)
      86           0 :       paramError(
      87             :           "nl_sys_names",
      88             :           "reference residual problem does not currently support multiple nonlinear systems");
      89         391 :     _reference_vector_tag_id = _fe_problem.getVectorTagID(getParam<TagName>("reference_vector"));
      90         383 :     _reference_vector = &_fe_problem.getNonlinearSystemBase(0).getVector(_reference_vector_tag_id);
      91             :   }
      92             :   else
      93          44 :     mooseInfo("Neither the `reference_residual_variables` nor `reference_vector` parameter is "
      94             :               "specified, which means that no reference "
      95             :               "quantites are set. Because of this, the standard technique of comparing the "
      96             :               "norm of the full residual vector with its initial value will be used.");
      97             : 
      98         427 :   _accept_mult = parameters.get<Real>("acceptable_multiplier");
      99         427 :   _accept_iters = parameters.get<unsigned int>("acceptable_iterations");
     100             : 
     101             :   const auto norm_type_enum =
     102         427 :       parameters.get<MooseEnum>("normalization_type").getEnum<NormalizationType>();
     103         427 :   if (norm_type_enum == NormalizationType::LOCAL_L2)
     104             :   {
     105          34 :     _norm_type = libMesh::DISCRETE_L2;
     106          34 :     _local_norm = true;
     107             :   }
     108         393 :   else if (norm_type_enum == NormalizationType::GLOBAL_L2)
     109             :   {
     110         341 :     _norm_type = libMesh::DISCRETE_L2;
     111         341 :     _local_norm = false;
     112             :   }
     113          52 :   else if (norm_type_enum == NormalizationType::LOCAL_LINF)
     114             :   {
     115          26 :     _norm_type = libMesh::DISCRETE_L_INF;
     116          26 :     _local_norm = true;
     117             :   }
     118          26 :   else if (norm_type_enum == NormalizationType::GLOBAL_LINF)
     119             :   {
     120          26 :     _norm_type = libMesh::DISCRETE_L_INF;
     121          26 :     _local_norm = false;
     122             :   }
     123             :   else
     124             :   {
     125             :     mooseAssert(false, "This point should not be reached.");
     126             :   }
     127             : 
     128         427 :   if (_local_norm && !parameters.isParamValid("reference_vector"))
     129           8 :     paramError("reference_vector", "If local norm is used, a reference_vector must be provided.");
     130         419 : }
     131             : 
     132             : void
     133         397 : ReferenceResidualConvergence::initialSetup()
     134             : {
     135         397 :   DefaultNonlinearConvergence::initialSetup();
     136             : 
     137         397 :   NonlinearSystemBase & nonlinear_sys = _fe_problem.getNonlinearSystemBase(/*nl_sys=*/0);
     138         397 :   AuxiliarySystem & aux_sys = _fe_problem.getAuxiliarySystem();
     139         397 :   System & s = nonlinear_sys.system();
     140         397 :   auto & as = aux_sys.sys();
     141             : 
     142         397 :   if (_soln_var_names.empty())
     143             :   {
     144             :     // If the user provides reference_vector, that implies that they want the
     145             :     // individual variables compared against their reference quantities in the
     146             :     // tag vector. The code depends on having _soln_var_names populated,
     147             :     // so fill that out if they didn't specify solution_variables.
     148         384 :     if (_reference_vector)
     149        1052 :       for (unsigned int var_num = 0; var_num < s.n_vars(); var_num++)
     150         694 :         _soln_var_names.push_back(s.variable_name(var_num));
     151             : 
     152             :     // If they didn't provide reference_vector, that implies that they
     153             :     // want to skip the individual variable comparison, so leave it alone.
     154             :   }
     155          13 :   else if (_soln_var_names.size() != s.n_vars())
     156           0 :     mooseError("Size of solution_variables (",
     157           0 :                _soln_var_names.size(),
     158             :                ") != number of variables in system (",
     159           0 :                s.n_vars(),
     160             :                ")");
     161             : 
     162         397 :   const auto n_soln_vars = _soln_var_names.size();
     163         397 :   _variable_group_num_index.resize(n_soln_vars);
     164             : 
     165         397 :   if (!_converge_on.empty())
     166             :   {
     167          52 :     _converge_on_var.assign(n_soln_vars, false);
     168         156 :     for (std::size_t i = 0; i < n_soln_vars; ++i)
     169         134 :       for (const auto & c : _converge_on)
     170         104 :         if (MooseUtils::globCompare(_soln_var_names[i], c))
     171             :         {
     172          74 :           _converge_on_var[i] = true;
     173          74 :           break;
     174             :         }
     175             :   }
     176             :   else
     177         345 :     _converge_on_var.assign(n_soln_vars, true);
     178             : 
     179         397 :   unsigned int group_variable_num = 0;
     180         397 :   if (_use_group_variables)
     181             :   {
     182          16 :     for (unsigned int i = 0; i < _group_variables.size(); ++i)
     183             :     {
     184           8 :       group_variable_num += _group_variables[i].size();
     185           8 :       if (_group_variables[i].size() == 1)
     186           0 :         mooseError(" In the 'group_variables' parameter, variable ",
     187           0 :                    _group_variables[i][0],
     188             :                    " is not grouped with other variables.");
     189             :     }
     190             : 
     191           8 :     unsigned int size = n_soln_vars - group_variable_num + _group_variables.size();
     192           8 :     _group_ref_resid.resize(size);
     193           8 :     _group_resid.resize(size);
     194           8 :     _group_output_resid.resize(size);
     195           8 :     _group_soln_var_names.resize(size);
     196           8 :     _group_ref_resid_var_names.resize(size);
     197             :   }
     198             :   // If not using groups, use one group for each variable
     199             :   else
     200             :   {
     201         389 :     _group_ref_resid.resize(n_soln_vars);
     202         389 :     _group_resid.resize(n_soln_vars);
     203         389 :     _group_output_resid.resize(n_soln_vars);
     204         389 :     _group_soln_var_names.resize(n_soln_vars);
     205         389 :     _group_ref_resid_var_names.resize(n_soln_vars);
     206             :   }
     207             : 
     208         397 :   std::set<std::string> check_duplicate;
     209         397 :   if (_use_group_variables)
     210             :   {
     211          16 :     for (unsigned int i = 0; i < _group_variables.size(); ++i)
     212          24 :       for (unsigned int j = 0; j < _group_variables[i].size(); ++j)
     213          16 :         check_duplicate.insert(_group_variables[i][j]);
     214             : 
     215           8 :     if (check_duplicate.size() != group_variable_num)
     216           0 :       mooseError(
     217             :           "A variable cannot be included in multiple groups in the 'group_variables' parameter.");
     218             :   }
     219             : 
     220         397 :   _soln_vars.clear();
     221        1104 :   for (unsigned int i = 0; i < n_soln_vars; ++i)
     222             :   {
     223         707 :     bool found_match = false;
     224        1043 :     for (unsigned int var_num = 0; var_num < s.n_vars(); var_num++)
     225        1043 :       if (_soln_var_names[i] == s.variable_name(var_num))
     226             :       {
     227         707 :         _soln_vars.push_back(var_num);
     228         707 :         found_match = true;
     229         707 :         break;
     230             :       }
     231             : 
     232         707 :     if (!found_match)
     233           0 :       mooseError("Could not find solution variable '",
     234           0 :                  _soln_var_names[i],
     235             :                  "' in system '",
     236           0 :                  s.name(),
     237             :                  "'.");
     238             :   }
     239             : 
     240         397 :   if (!_reference_vector)
     241             :   {
     242          26 :     _ref_resid_vars.clear();
     243          26 :     for (unsigned int i = 0; i < _ref_resid_var_names.size(); ++i)
     244             :     {
     245           0 :       bool foundMatch = false;
     246           0 :       for (unsigned int var_num = 0; var_num < as.n_vars(); var_num++)
     247           0 :         if (_ref_resid_var_names[i] == as.variable_name(var_num))
     248             :         {
     249           0 :           _ref_resid_vars.push_back(var_num);
     250           0 :           foundMatch = true;
     251           0 :           break;
     252             :         }
     253             : 
     254           0 :       if (!foundMatch)
     255           0 :         mooseError("Could not find variable '", _ref_resid_var_names[i], "' in auxiliary system");
     256             :     }
     257             :   }
     258             : 
     259         397 :   unsigned int ungroup_index = 0;
     260         397 :   if (_use_group_variables)
     261           8 :     ungroup_index = _group_variables.size();
     262             : 
     263        1088 :   for (const auto i : index_range(_soln_vars))
     264             :   {
     265         699 :     bool find_group = false;
     266         699 :     if (_use_group_variables)
     267             :     {
     268           8 :       for (unsigned int j = 0; j < _group_variables.size(); ++j)
     269           8 :         if (std::find(_group_variables[j].begin(),
     270           8 :                       _group_variables[j].end(),
     271          16 :                       s.variable_name(_soln_vars[i])) != _group_variables[j].end())
     272             :         {
     273           8 :           if (!_converge_on_var[i])
     274           8 :             paramError("converge_on",
     275             :                        "You added variable '",
     276           8 :                        _soln_var_names[i],
     277             :                        "' to a group but excluded it from the convergence check. This is not "
     278             :                        "permitted.");
     279             : 
     280           0 :           _variable_group_num_index[i] = j;
     281           0 :           find_group = true;
     282           0 :           break;
     283             :         }
     284             : 
     285           0 :       if (!find_group)
     286             :       {
     287           0 :         _variable_group_num_index[i] = ungroup_index;
     288           0 :         ungroup_index++;
     289             :       }
     290             :     }
     291             :     else
     292         691 :       _variable_group_num_index[i] = i;
     293             :   }
     294             : 
     295         389 :   if (_use_group_variables)
     296             :   {
     297             :     // Check for variable groups containing both field and scalar variables
     298           0 :     for (unsigned int i = 0; i < _group_variables.size(); ++i)
     299             :     {
     300           0 :       unsigned int num_scalar_vars = 0;
     301           0 :       unsigned int num_field_vars = 0;
     302           0 :       if (_group_variables[i].size() > 1)
     303             :       {
     304           0 :         for (unsigned int j = 0; j < _group_variables[i].size(); ++j)
     305           0 :           for (unsigned int var_num = 0; var_num < s.n_vars(); var_num++)
     306           0 :             if (_group_variables[i][j] == s.variable_name(var_num))
     307             :             {
     308           0 :               if (nonlinear_sys.isScalarVariable(_soln_vars[var_num]))
     309           0 :                 ++num_scalar_vars;
     310             :               else
     311           0 :                 ++num_field_vars;
     312           0 :               break;
     313             :             }
     314             :       }
     315           0 :       if (num_scalar_vars > 0 && num_field_vars > 0)
     316           0 :         mooseWarning("In the 'group_variables' parameter, standard variables and scalar variables "
     317             :                      "are grouped together in group ",
     318             :                      i);
     319             :     }
     320             :   }
     321             : 
     322             :   // Keep track of the names of the variables in each group (of 1 variable if not using groups)
     323        1080 :   for (unsigned int i = 0; i < n_soln_vars; ++i)
     324             :   {
     325         691 :     if (_group_soln_var_names[_variable_group_num_index[i]].empty())
     326             :     {
     327         691 :       _group_soln_var_names[_variable_group_num_index[i]] = _soln_var_names[i];
     328         691 :       if (_use_group_variables && _variable_group_num_index[i] < _group_variables.size())
     329           0 :         _group_soln_var_names[_variable_group_num_index[i]] += " (grouped) ";
     330             :     }
     331             : 
     332         691 :     if (!_reference_vector && _group_ref_resid_var_names[_variable_group_num_index[i]].empty())
     333             :     {
     334           0 :       _group_ref_resid_var_names[_variable_group_num_index[i]] = _ref_resid_var_names[i];
     335           0 :       if (_use_group_variables && _variable_group_num_index[i] < _group_variables.size())
     336           0 :         _group_ref_resid_var_names[_variable_group_num_index[i]] += " (grouped) ";
     337             :     }
     338             :   }
     339             : 
     340         389 :   if (!_reference_vector)
     341             :   {
     342          26 :     const unsigned int size_soln_vars = _soln_vars.size();
     343          26 :     _scaling_factors.resize(size_soln_vars);
     344          26 :     for (unsigned int i = 0; i < size_soln_vars; ++i)
     345           0 :       if (nonlinear_sys.isScalarVariable(_soln_vars[i]))
     346           0 :         _scaling_factors[i] = nonlinear_sys.getScalarVariable(0, _soln_vars[i]).scalingFactor();
     347             :       else
     348           0 :         _scaling_factors[i] = nonlinear_sys.getVariable(/*tid*/ 0, _soln_vars[i]).scalingFactor();
     349             :   }
     350         389 :   _initialized = true;
     351         389 : }
     352             : 
     353             : void
     354       22201 : ReferenceResidualConvergence::updateReferenceResidual()
     355             : {
     356       22201 :   NonlinearSystemBase & _current_nl_sys = _fe_problem.currentNonlinearSystem();
     357       22201 :   AuxiliarySystem & aux_sys = _fe_problem.getAuxiliarySystem();
     358       22201 :   System & s = _current_nl_sys.system();
     359       22201 :   auto & as = aux_sys.sys();
     360             : 
     361       22201 :   std::fill(_group_resid.begin(), _group_resid.end(), 0.0);
     362       22201 :   std::fill(_group_output_resid.begin(), _group_output_resid.end(), 0.0);
     363       22201 :   if (_local_norm)
     364        1144 :     std::fill(_group_ref_resid.begin(), _group_ref_resid.end(), 1.0);
     365             :   else
     366       21057 :     std::fill(_group_ref_resid.begin(), _group_ref_resid.end(), 0.0);
     367             : 
     368       65302 :   for (const auto i : index_range(_soln_vars))
     369             :   {
     370       43101 :     Real resid = 0.0;
     371       43101 :     const auto group = _variable_group_num_index[i];
     372       43101 :     if (_local_norm)
     373             :     {
     374             :       mooseAssert(_current_nl_sys.RHS().size() == (*_reference_vector).size(),
     375             :                   "Sizes of nonlinear RHS and reference vector should be the same.");
     376             :       mooseAssert((*_reference_vector).size(), "Reference vector must be provided.");
     377             :       // Add a tiny number to the reference to prevent a divide by zero.
     378        2288 :       auto ref = _reference_vector->clone();
     379        2288 :       ref->add(std::numeric_limits<Number>::min());
     380        2288 :       auto div = _current_nl_sys.RHS().clone();
     381        2288 :       *div /= *ref;
     382        2288 :       resid = Utility::pow<2>(s.calculate_norm(*div, _soln_vars[i], _norm_type));
     383        2288 :     }
     384             :     else
     385             :     {
     386       40813 :       resid = Utility::pow<2>(s.calculate_norm(_current_nl_sys.RHS(), _soln_vars[i], _norm_type));
     387       40813 :       if (_reference_vector)
     388             :       {
     389       40813 :         const auto ref_resid = s.calculate_norm(*_reference_vector, _soln_vars[i], _norm_type);
     390       40813 :         _group_ref_resid[group] += Utility::pow<2>(ref_resid);
     391             :       }
     392             :     }
     393             : 
     394       43101 :     _group_resid[group] += _converge_on_var[i] ? resid : 0;
     395       43101 :     _group_output_resid[group] += resid;
     396             :   }
     397             : 
     398       22201 :   if (!_reference_vector)
     399             :   {
     400         484 :     for (unsigned int i = 0; i < _ref_resid_vars.size(); ++i)
     401             :     {
     402             :       const auto ref_resid =
     403           0 :           as.calculate_norm(*as.current_local_solution, _ref_resid_vars[i], _norm_type) *
     404           0 :           _scaling_factors[i];
     405           0 :       _group_ref_resid[_variable_group_num_index[i]] += Utility::pow<2>(ref_resid);
     406             :     }
     407             :   }
     408             : 
     409       65302 :   for (unsigned int i = 0; i < _group_resid.size(); ++i)
     410             :   {
     411       43101 :     _group_resid[i] = std::sqrt(_group_resid[i]);
     412       43101 :     _group_output_resid[i] = std::sqrt(_group_output_resid[i]);
     413       43101 :     _group_ref_resid[i] = std::sqrt(_group_ref_resid[i]);
     414             :   }
     415       22201 : }
     416             : 
     417             : void
     418       22201 : ReferenceResidualConvergence::nonlinearConvergenceSetup()
     419             : {
     420       22201 :   if (!_initialized)
     421           0 :     initialSetup();
     422             : 
     423       22201 :   updateReferenceResidual();
     424             : 
     425       22201 :   std::ostringstream out;
     426             : 
     427       22201 :   if (_group_soln_var_names.size() > 0)
     428             :   {
     429       21717 :     out << std::setprecision(2) << std::scientific
     430       21717 :         << "   Solution, reference convergence variable norms:\n";
     431       21717 :     unsigned int maxwsv = 0;
     432       21717 :     unsigned int maxwrv = 0;
     433       64818 :     for (unsigned int i = 0; i < _group_soln_var_names.size(); ++i)
     434             :     {
     435       43101 :       if (_group_soln_var_names[i].size() > maxwsv)
     436       21717 :         maxwsv = _group_soln_var_names[i].size();
     437       43101 :       if (!_reference_vector && _group_ref_resid_var_names[i].size() > maxwrv)
     438           0 :         maxwrv = _group_ref_resid_var_names[i].size();
     439             :     }
     440       21717 :     if (_reference_vector)
     441             :       // maxwrv is the width of maxwsv plus the length of "_ref" (e.g. 4)
     442       21717 :       maxwrv = maxwsv + 4;
     443             : 
     444       64818 :     for (unsigned int i = 0; i < _group_soln_var_names.size(); ++i)
     445             :     {
     446       43101 :       out << "   " << std::setw(maxwsv + (_local_norm ? 5 : 2)) << std::left
     447       43101 :           << (_local_norm ? "norm " : "") + _group_soln_var_names[i] + ": ";
     448             : 
     449       43101 :       if (_group_output_resid[i] == _group_resid[i])
     450       43001 :         out << std::setw(8) << _group_output_resid[i];
     451             :       else
     452         100 :         out << std::setw(8) << _group_resid[i] << " (" << _group_output_resid[i] << ')';
     453             : 
     454       43101 :       if (!_local_norm)
     455             :       {
     456             :         const auto ref_var_name =
     457       40813 :             _reference_vector ? _group_soln_var_names[i] + "_ref" : _group_ref_resid_var_names[i];
     458       81626 :         out << "  " << std::setw(maxwrv + 2) << ref_var_name + ":" << std::setw(8)
     459       40813 :             << _group_ref_resid[i] << "  (" << std::setw(8)
     460       40813 :             << (_group_ref_resid[i] ? _group_resid[i] / _group_ref_resid[i] : _group_resid[i])
     461       40813 :             << ")";
     462       40813 :       }
     463       43101 :       out << '\n';
     464             :     }
     465       21717 :     _console << out.str() << std::flush;
     466             :   }
     467       22201 : }
     468             : 
     469             : bool
     470       38108 : ReferenceResidualConvergence::checkConvergenceIndividVars(
     471             :     const Real fnorm,
     472             :     const Real abstol,
     473             :     const Real rtol,
     474             :     const Real initial_residual_before_preset_bcs)
     475             : {
     476             :   // Convergence is checked via:
     477             :   // 1) if group residual is less than group reference residual by relative tolerance
     478             :   // 2) if group residual is less than absolute tolerance
     479             :   // 3) if group reference residual is zero and:
     480             :   //   3.1) Convergence type is ZERO_TOLERANCE and group residual is zero (rare, but possible, and
     481             :   //        historically implemented that way)
     482             :   //   3.2) Convergence type is RELATIVE_TOLERANCE and group residual
     483             :   //        is less than relative tolerance. (i.e., using the relative tolerance to check group
     484             :   //        convergence in an absolute way)
     485             : 
     486       38108 :   bool convergedRelative = true;
     487       38108 :   if (_group_resid.size() > 0)
     488             :   {
     489      113212 :     for (unsigned int i = 0; i < _group_resid.size(); ++i)
     490       75412 :       convergedRelative &=
     491      144138 :           (_group_resid[i] < _group_ref_resid[i] * rtol || _group_resid[i] < abstol ||
     492       68726 :            (_group_ref_resid[i] == 0.0 &&
     493       65368 :             ((_zero_ref_type == ZeroReferenceType::ZERO_TOLERANCE && _group_resid[i] == 0.0) ||
     494       65368 :              (_zero_ref_type == ZeroReferenceType::RELATIVE_TOLERANCE &&
     495         968 :               _group_resid[i] <= rtol))));
     496             :   }
     497             : 
     498         308 :   else if (fnorm > initial_residual_before_preset_bcs * rtol)
     499          88 :     convergedRelative = false;
     500             : 
     501       38108 :   return convergedRelative;
     502             : }
     503             : 
     504             : bool
     505       19929 : ReferenceResidualConvergence::checkRelativeConvergence(const unsigned int it,
     506             :                                                        const Real fnorm,
     507             :                                                        const Real the_residual,
     508             :                                                        const Real rtol,
     509             :                                                        const Real abstol,
     510             :                                                        std::ostringstream & oss)
     511             : {
     512       19929 :   if (checkConvergenceIndividVars(fnorm, abstol, rtol, the_residual))
     513             :   {
     514        1750 :     oss << "Converged due to function norm " << fnorm << " < relative tolerance (" << rtol
     515        1750 :         << ") or absolute tolerance (" << abstol << ") for all solution variables\n";
     516        1750 :     return true;
     517             :   }
     518       36358 :   else if (it >= _accept_iters &&
     519       18179 :            checkConvergenceIndividVars(
     520       18179 :                fnorm, abstol * _accept_mult, rtol * _accept_mult, the_residual))
     521             :   {
     522          40 :     oss << "Converged due to function norm " << fnorm << " < acceptable relative tolerance ("
     523          40 :         << rtol * _accept_mult << ") or acceptable absolute tolerance (" << abstol * _accept_mult
     524          40 :         << ") for all solution variables\n";
     525          40 :     _console << "Converged due to ACCEPTABLE tolerances" << std::endl;
     526          40 :     return true;
     527             :   }
     528             : 
     529       18139 :   return false;
     530             : }

Generated by: LCOV version 1.14