LCOV - code coverage report
Current view: top level - src/executioners - FEProblemSolve.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33416 (b10b36) with base 9fbd27 Lines: 236 251 94.0 %
Date: 2026-07-23 16:15:30 Functions: 13 14 92.9 %
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             : #include "FEProblemSolve.h"
      11             : 
      12             : #include "FEProblem.h"
      13             : #include "NonlinearSystemBase.h"
      14             : #include "LinearSystem.h"
      15             : #include "Convergence.h"
      16             : #include "Executioner.h"
      17             : #include "ConvergenceIterationTypes.h"
      18             : #include "MooseUtils.h"
      19             : 
      20             : std::set<std::string> const FEProblemSolve::_moose_line_searches = {"contact", "project"};
      21             : 
      22             : const std::set<std::string> &
      23      159132 : FEProblemSolve::mooseLineSearches()
      24             : {
      25      159132 :   return _moose_line_searches;
      26             : }
      27             : 
      28             : InputParameters
      29      292282 : FEProblemSolve::feProblemDefaultConvergenceParams()
      30             : {
      31      292282 :   InputParameters params = emptyInputParameters();
      32             : 
      33     1169128 :   params.addParam<unsigned int>("nl_max_its", 50, "Max Nonlinear Iterations");
      34     1169128 :   params.addParam<unsigned int>("nl_forced_its", 0, "The Number of Forced Nonlinear Iterations");
      35     1169128 :   params.addParam<unsigned int>("nl_max_funcs", 10000, "Max Nonlinear solver function evaluations");
      36     1169128 :   params.addParam<Real>("nl_abs_tol", 1.0e-50, "Nonlinear Absolute Tolerance");
      37     1169128 :   params.addParam<Real>("nl_rel_tol", 1.0e-8, "Nonlinear Relative Tolerance");
      38      876846 :   params.addParam<Real>(
      39             :       "nl_div_tol",
      40      584564 :       1.0e10,
      41             :       "Nonlinear Relative Divergence Tolerance. A negative value disables this check.");
      42      876846 :   params.addParam<Real>(
      43             :       "nl_abs_div_tol",
      44      584564 :       1.0e50,
      45             :       "Nonlinear Absolute Divergence Tolerance. A negative value disables this check.");
      46     1169128 :   params.addParam<Real>("nl_abs_step_tol", 0., "Nonlinear Absolute step Tolerance");
      47     1169128 :   params.addParam<Real>("nl_rel_step_tol", 0., "Nonlinear Relative step Tolerance");
      48      876846 :   params.addParam<unsigned int>("n_max_nonlinear_pingpong",
      49      584564 :                                 100,
      50             :                                 "The maximum number of times the nonlinear residual can ping pong "
      51             :                                 "before requesting halting the current evaluation and requesting "
      52             :                                 "timestep cut for transient simulations");
      53             : 
      54      876846 :   params.addParamNamesToGroup(
      55             :       "nl_max_its nl_forced_its nl_max_funcs nl_abs_tol nl_rel_tol "
      56             :       "nl_rel_step_tol nl_abs_step_tol nl_div_tol nl_abs_div_tol n_max_nonlinear_pingpong",
      57             :       "Nonlinear Solver");
      58             : 
      59      292282 :   return params;
      60           0 : }
      61             : 
      62             : InputParameters
      63      159132 : FEProblemSolve::validParams()
      64             : {
      65      159132 :   InputParameters params = MultiSystemSolveObject::validParams();
      66      159132 :   params += FEProblemSolve::feProblemDefaultConvergenceParams();
      67             : 
      68      159132 :   std::set<std::string> line_searches = mooseLineSearches();
      69             : 
      70      159132 :   std::set<std::string> alias_line_searches = {"default", "none", "basic"};
      71      159132 :   line_searches.insert(alias_line_searches.begin(), alias_line_searches.end());
      72      159132 :   std::set<std::string> petsc_line_searches = Moose::PetscSupport::getPetscValidLineSearches();
      73      159132 :   line_searches.insert(petsc_line_searches.begin(), petsc_line_searches.end());
      74      636528 :   std::string line_search_string = Moose::stringify(line_searches, " ");
      75      318264 :   MooseEnum line_search(line_search_string, "default");
      76      159132 :   std::string addtl_doc_str(" (Note: none = basic)");
      77      159132 :   params.addParam<MooseEnum>(
      78      318264 :       "line_search", line_search, "Specifies the line search type" + addtl_doc_str);
      79      636528 :   MooseEnum line_search_package("petsc moose", "petsc");
      80      636528 :   params.addParam<MooseEnum>("line_search_package",
      81             :                              line_search_package,
      82             :                              "The solver package to use to conduct the line-search");
      83             : 
      84      477396 :   params.addParam<unsigned>("contact_line_search_allowed_lambda_cuts",
      85      318264 :                             2,
      86             :                             "The number of times lambda is allowed to be cut in half in the "
      87             :                             "contact line search. We recommend this number be roughly bounded by 0 "
      88             :                             "<= allowed_lambda_cuts <= 3");
      89      477396 :   params.addParam<Real>("contact_line_search_ltol",
      90             :                         "The linear relative tolerance to be used while the contact state is "
      91             :                         "changing between non-linear iterations. We recommend that this tolerance "
      92             :                         "be looser than the standard linear tolerance");
      93             : 
      94      159132 :   params += Moose::PetscSupport::getPetscValidParams();
      95      636528 :   params.addParam<Real>("l_tol", 1.0e-5, "Linear Relative Tolerance");
      96      636528 :   params.addParam<Real>("l_abs_tol", 1.0e-50, "Linear Absolute Tolerance");
      97      636528 :   params.addParam<unsigned int>("l_max_its", 10000, "Max Linear Iterations");
      98      636528 :   params.addParam<std::vector<ConvergenceName>>(
      99             :       "nonlinear_convergence",
     100             :       "Name of the Convergence object(s) to use to assess convergence of the "
     101             :       "nonlinear system(s) solve. If not provided, the default Convergence "
     102             :       "associated with the Problem will be constructed internally.");
     103      636528 :   params.addParam<std::vector<ConvergenceName>>(
     104             :       "linear_convergence",
     105             :       "Name of the Convergence object(s) to use to assess convergence of the "
     106             :       "linear system(s) solve. If not provided, the linear solver tolerance parameters are used");
     107      477396 :   params.addParam<bool>(
     108             :       "snesmf_reuse_base",
     109      318264 :       true,
     110             :       "Specifies whether or not to reuse the base vector for matrix-free calculation");
     111      477396 :   params.addParam<bool>(
     112      318264 :       "skip_exception_check", false, "Specifies whether or not to skip exception check");
     113      477396 :   params.addParam<bool>(
     114             :       "use_pre_SMO_residual",
     115      318264 :       false,
     116             :       "Compute the pre-SMO residual norm and use it in the relative convergence check. The "
     117             :       "pre-SMO residual is computed at the begining of the time step before solution-modifying "
     118             :       "objects are executed. Solution-modifying objects include preset BCs, constraints, "
     119             :       "predictors, etc.");
     120      636528 :   params.addParam<bool>("automatic_scaling", "Whether to use automatic scaling for the variables.");
     121      636528 :   params.addParam<std::vector<bool>>(
     122             :       "compute_scaling_once",
     123             :       {true},
     124             :       "Whether the scaling factors should only be computed once at the beginning of the simulation "
     125             :       "through an extra Jacobian evaluation. If this is set to false, then the scaling factors "
     126             :       "will be computed during an extra Jacobian evaluation at the beginning of every time step. "
     127             :       "Vector entries correspond to each nonlinear system.");
     128      636528 :   params.addParam<std::vector<bool>>(
     129             :       "off_diagonals_in_auto_scaling",
     130             :       {false},
     131             :       "Whether to consider off-diagonals when determining automatic scaling factors. Vector "
     132             :       "entries correspond to each nonlinear system.");
     133     1273056 :   params.addRangeCheckedParam<std::vector<Real>>(
     134             :       "resid_vs_jac_scaling_param",
     135             :       {0},
     136             :       "0<=resid_vs_jac_scaling_param<=1",
     137             :       "A parameter that indicates the weighting of the residual vs the Jacobian in determining "
     138             :       "variable scaling parameters. A value of 1 indicates pure residual-based scaling. A value of "
     139             :       "0 indicates pure Jacobian-based scaling. Vector entries correspond to each nonlinear "
     140             :       "system.");
     141      636528 :   params.addParam<std::vector<std::vector<std::vector<std::string>>>>(
     142             :       "scaling_group_variables",
     143             :       "Name of variables that are grouped together for determining scale factors. (Multiple "
     144             :       "groups can be provided, separated by semicolon). Vector entries correspond to each "
     145             :       "nonlinear system.");
     146      636528 :   params.addParam<std::vector<std::vector<std::string>>>(
     147             :       "ignore_variables_for_autoscaling",
     148             :       "List of variables that do not participate in autoscaling. Vector entries correspond to each "
     149             :       "nonlinear system.");
     150      795660 :   params.addRangeCheckedParam<unsigned int>(
     151             :       "num_grids",
     152      318264 :       1,
     153             :       "num_grids>0",
     154             :       "The number of grids to use for a grid sequencing algorithm. This includes the final grid, "
     155             :       "so num_grids = 1 indicates just one solve in a time-step");
     156      636528 :   params.addParam<std::vector<bool>>("residual_and_jacobian_together",
     157             :                                      {false},
     158             :                                      "Whether to compute the residual and Jacobian together. "
     159             :                                      "Vector entries correspond to each nonlinear system.");
     160             : 
     161      477396 :   params.addParam<bool>("reuse_preconditioner",
     162      318264 :                         false,
     163             :                         "If true reuse the previously calculated "
     164             :                         "preconditioner for the linearized "
     165             :                         "system across multiple solves "
     166             :                         "spanning nonlinear iterations and time steps. "
     167             :                         "The preconditioner resets as controlled by "
     168             :                         "reuse_preconditioner_max_linear_its");
     169      477396 :   params.addParam<unsigned int>("reuse_preconditioner_max_linear_its",
     170      318264 :                                 25,
     171             :                                 "Reuse the previously calculated "
     172             :                                 "preconditioner for the linear system "
     173             :                                 "until the number of linear iterations "
     174             :                                 "exceeds this number");
     175             : 
     176      636528 :   params.addParamNamesToGroup("l_tol l_abs_tol l_max_its reuse_preconditioner "
     177             :                               "reuse_preconditioner_max_linear_its",
     178             :                               "Linear Solver");
     179      636528 :   params.addParamNamesToGroup(
     180             :       "solve_type snesmf_reuse_base use_pre_SMO_residual "
     181             :       "num_grids residual_and_jacobian_together nonlinear_convergence linear_convergence",
     182             :       "Nonlinear Solver");
     183      636528 :   params.addParamNamesToGroup(
     184             :       "automatic_scaling compute_scaling_once off_diagonals_in_auto_scaling "
     185             :       "scaling_group_variables resid_vs_jac_scaling_param ignore_variables_for_autoscaling",
     186             :       "Solver variable scaling");
     187      636528 :   params.addParamNamesToGroup("line_search line_search_package contact_line_search_ltol "
     188             :                               "contact_line_search_allowed_lambda_cuts",
     189             :                               "Solver line search");
     190      477396 :   params.addParamNamesToGroup("skip_exception_check", "Advanced");
     191             : 
     192      318264 :   return params;
     193      159132 : }
     194             : 
     195       60680 : FEProblemSolve::FEProblemSolve(Executioner & ex)
     196             :   : MultiSystemSolveObject(ex),
     197      121360 :     _num_grid_steps(cast_int<unsigned int>(getParam<unsigned int>("num_grids") - 1))
     198             : {
     199      121360 :   if (_moose_line_searches.find(getParam<MooseEnum>("line_search").operator std::string()) !=
     200      121360 :       _moose_line_searches.end())
     201           0 :     _problem.addLineSearch(_pars);
     202             : 
     203       61023 :   auto set_solver_params = [this, &ex](const SolverSystem & sys)
     204             :   {
     205       61023 :     const auto prefix = sys.prefix();
     206       61023 :     if (dynamic_cast<const LinearSystem *>(&sys))
     207        1228 :       Moose::PetscSupport::dontAddCommonSNESOptions(_problem, prefix);
     208       61023 :     Moose::PetscSupport::storePetscOptions(_problem, prefix, ex);
     209       61023 :     Moose::PetscSupport::setConvergedReasonFlags(_problem, prefix);
     210             : 
     211             :     // Set solver parameter prefix and system number
     212       61023 :     auto & solver_params = _problem.solverParams(sys.number());
     213       61023 :     solver_params._prefix = prefix;
     214       61023 :     solver_params._solver_sys_num = sys.number();
     215       61023 :   };
     216             : 
     217             :   // Extract and store PETSc related settings on FEProblemBase
     218      121703 :   for (const auto * const sys : _systems)
     219       61023 :     set_solver_params(*sys);
     220             : 
     221             :   // Set linear solve parameters in the equation system
     222             :   // Nonlinear solve parameters are added in the DefaultNonlinearConvergence
     223       60680 :   EquationSystems & es = _problem.es();
     224      242720 :   es.parameters.set<Real>("linear solver tolerance") = getParam<Real>("l_tol");
     225      242720 :   es.parameters.set<Real>("linear solver absolute tolerance") = getParam<Real>("l_abs_tol");
     226       60680 :   es.parameters.set<unsigned int>("linear solver maximum iterations") =
     227      182040 :       getParam<unsigned int>("l_max_its");
     228      242720 :   es.parameters.set<bool>("reuse preconditioner") = getParam<bool>("reuse_preconditioner");
     229       60680 :   es.parameters.set<unsigned int>("reuse preconditioner maximum linear iterations") =
     230      182040 :       getParam<unsigned int>("reuse_preconditioner_max_linear_its");
     231             : 
     232             :   // Transfer to the Problem misc nonlinear solve optimization parameters
     233       60680 :   _problem.setSNESMFReuseBase(getParam<bool>("snesmf_reuse_base"),
     234      182040 :                               _pars.isParamSetByUser("snesmf_reuse_base"));
     235      121360 :   _problem.skipExceptionCheck(getParam<bool>("skip_exception_check"));
     236             : 
     237      182040 :   if (isParamValid("nonlinear_convergence"))
     238             :   {
     239         396 :     if (_problem.onlyAllowDefaultNonlinearConvergence())
     240           0 :       mooseError("The selected problem does not allow 'nonlinear_convergence' to be set.");
     241        1188 :     _problem.setNonlinearConvergenceNames(
     242             :         getParam<std::vector<ConvergenceName>>("nonlinear_convergence"));
     243             :   }
     244             :   else
     245       60284 :     _problem.setNeedToAddDefaultNonlinearConvergence();
     246      182040 :   if (isParamValid("linear_convergence"))
     247             :   {
     248         134 :     if (_problem.numLinearSystems() == 0)
     249           0 :       paramError(
     250             :           "linear_convergence",
     251             :           "Setting 'linear_convergence' is currently only possible for solving linear systems");
     252         402 :     _problem.setLinearConvergenceNames(
     253             :         getParam<std::vector<ConvergenceName>>("linear_convergence"));
     254             :   }
     255             : 
     256             :   // Check whether the user has explicitly requested automatic scaling and is using a solve type
     257             :   // without a matrix. If so, then we warn them
     258      183663 :   if ((_pars.isParamSetByUser("automatic_scaling") && getParam<bool>("automatic_scaling")) &&
     259         485 :       std::all_of(_systems.begin(),
     260             :                   _systems.end(),
     261         485 :                   [this](const auto & solver_sys)
     262         485 :                   { return _problem.solverParams(solver_sys->number())._type == Moose::ST_JFNK; }))
     263             :   {
     264           0 :     paramWarning("automatic_scaling",
     265             :                  "Automatic scaling isn't implemented for the case where you do not have a "
     266             :                  "preconditioning matrix. No scaling will be applied");
     267           0 :     _problem.automaticScaling(false);
     268             :   }
     269             :   else
     270             :     // Check to see whether automatic_scaling has been specified anywhere, including at the
     271             :     // application level. No matter what: if we don't have a matrix, we don't do scaling
     272       60680 :     _problem.automaticScaling(
     273      182040 :         isParamValid("automatic_scaling")
     274       62387 :             ? getParam<bool>("automatic_scaling")
     275       60111 :             : (getMooseApp().defaultAutomaticScaling() &&
     276           0 :                std::any_of(_systems.begin(),
     277             :                            _systems.end(),
     278           0 :                            [this](const auto & solver_sys)
     279             :                            {
     280           0 :                              return _problem.solverParams(solver_sys->number())._type !=
     281           0 :                                     Moose::ST_JFNK;
     282             :                            })));
     283             : 
     284      180338 :   if (!_using_multi_sys_fp_iterations && isParamValid("multi_system_fixed_point_convergence"))
     285           6 :     paramError("multi_system_fixed_point_convergence",
     286             :                "Cannot set a convergence object for multi-system fixed point iterations if "
     287             :                "'multi_system_fixed_point' is set to false");
     288       62379 :   if (_using_multi_sys_fp_iterations && !isParamValid("multi_system_fixed_point_convergence"))
     289           6 :     paramError("multi_system_fixed_point_convergence",
     290             :                "Must set a convergence object for multi-system fixed point iterations if using "
     291             :                "multi-system fixed point iterations");
     292             : 
     293             :   // Set the same parameters to every nonlinear system by default
     294       60674 :   int i_nl_sys = -1;
     295      121670 :   for (const auto i_sys : index_range(_systems))
     296             :   {
     297       61005 :     auto nl_ptr = dynamic_cast<NonlinearSystemBase *>(_systems[i_sys]);
     298             :     // Linear systems have very different parameters at the moment
     299       61005 :     if (!nl_ptr)
     300        1228 :       continue;
     301       59777 :     auto & nl = *nl_ptr;
     302       59777 :     i_nl_sys++;
     303             : 
     304      119554 :     nl.setPreSMOResidual(getParam<bool>("use_pre_SMO_residual"));
     305             : 
     306             :     const auto res_and_jac =
     307      119554 :         getParamFromNonlinearSystemVectorParam<bool>("residual_and_jacobian_together", i_nl_sys);
     308       59771 :     if (res_and_jac)
     309         481 :       nl.residualAndJacobianTogether();
     310             : 
     311             :     // Automatic scaling parameters
     312       59771 :     nl.computeScalingOnce(
     313      119542 :         getParamFromNonlinearSystemVectorParam<bool>("compute_scaling_once", i_nl_sys));
     314      119542 :     nl.autoScalingParam(
     315             :         getParamFromNonlinearSystemVectorParam<Real>("resid_vs_jac_scaling_param", i_nl_sys));
     316       59771 :     nl.offDiagonalsInAutoScaling(
     317      119542 :         getParamFromNonlinearSystemVectorParam<bool>("off_diagonals_in_auto_scaling", i_nl_sys));
     318      179313 :     if (isParamValid("scaling_group_variables"))
     319          15 :       nl.scalingGroupVariables(
     320          60 :           getParamFromNonlinearSystemVectorParam<std::vector<std::vector<std::string>>>(
     321             :               "scaling_group_variables", i_nl_sys));
     322      179313 :     if (isParamValid("ignore_variables_for_autoscaling"))
     323             :     {
     324             :       // Before setting ignore_variables_for_autoscaling, check that they are not present in
     325             :       // scaling_group_variables
     326          36 :       if (isParamValid("scaling_group_variables"))
     327             :       {
     328             :         const auto & ignore_variables_for_autoscaling =
     329             :             getParamFromNonlinearSystemVectorParam<std::vector<std::string>>(
     330           6 :                 "ignore_variables_for_autoscaling", i_nl_sys);
     331             :         const auto & scaling_group_variables =
     332             :             getParamFromNonlinearSystemVectorParam<std::vector<std::vector<std::string>>>(
     333           6 :                 "scaling_group_variables", i_nl_sys);
     334           3 :         for (const auto & group : scaling_group_variables)
     335           6 :           for (const auto & var_name : group)
     336           6 :             if (std::find(ignore_variables_for_autoscaling.begin(),
     337             :                           ignore_variables_for_autoscaling.end(),
     338          12 :                           var_name) != ignore_variables_for_autoscaling.end())
     339           6 :               paramError("ignore_variables_for_autoscaling",
     340             :                          "Variables cannot be in a scaling grouping and also be ignored");
     341           0 :       }
     342           9 :       nl.ignoreVariablesForAutoscaling(
     343          36 :           getParamFromNonlinearSystemVectorParam<std::vector<std::string>>(
     344             :               "ignore_variables_for_autoscaling", i_nl_sys));
     345             :     }
     346             :   }
     347             : 
     348             :   // Multi-grid options
     349       60665 :   _problem.numGridSteps(_num_grid_steps);
     350       60665 : }
     351             : 
     352             : template <typename T>
     353             : T
     354      239120 : FEProblemSolve::getParamFromNonlinearSystemVectorParam(const std::string & param_name,
     355             :                                                        unsigned int index) const
     356             : {
     357      239120 :   const auto & param_vec = getParam<std::vector<T>>(param_name);
     358      239120 :   if (index > _num_nl_systems)
     359           0 :     paramError(param_name,
     360             :                "Vector parameter is requested at index (" + std::to_string(index) +
     361             :                    ") which is larger than number of nonlinear systems (" +
     362           0 :                    std::to_string(_num_nl_systems) + ").");
     363      239120 :   if (param_vec.size() == 0)
     364           3 :     paramError(
     365             :         param_name,
     366             :         "This parameter was passed to a routine which cannot handle empty vector parameters");
     367      239117 :   if (param_vec.size() != 1 && param_vec.size() != _num_nl_systems)
     368           3 :     paramError(param_name,
     369             :                "Vector parameter size (" + std::to_string(param_vec.size()) +
     370             :                    ") is different than the number of nonlinear systems (" +
     371           3 :                    std::to_string(_num_nl_systems) + ").");
     372             : 
     373             :   // User passed only one parameter, assume it applies to all nonlinear systems
     374      239114 :   if (param_vec.size() == 1)
     375      239114 :     return param_vec[0];
     376             :   else
     377           0 :     return param_vec[index];
     378             : }
     379             : 
     380             : void
     381       57723 : FEProblemSolve::initialSetup()
     382             : {
     383       57723 :   MultiSystemSolveObject::initialSetup();
     384       57723 :   convergenceSetup();
     385             :   // Keep track of the solution warnings from the setup
     386             :   // before a count reset at the beginning of the time step
     387       57717 :   if (!_app.isRecovering())
     388             :   {
     389       53737 :     _app.solutionInvalidity().syncIteration();
     390       53737 :     _app.solutionInvalidity().accumulateIterationIntoTimeStepOccurences();
     391       53737 :     _app.solutionInvalidity().accumulateTimeStepIntoTotalOccurences(0);
     392             :   }
     393       57717 : }
     394             : 
     395             : void
     396       57723 : FEProblemSolve::convergenceSetup()
     397             : {
     398             :   // nonlinear
     399       57723 :   const auto conv_names = _problem.getNonlinearConvergenceNames();
     400      114413 :   for (const auto & conv_name : conv_names)
     401             :   {
     402       56696 :     auto & conv = _problem.getConvergence(conv_name);
     403       56696 :     conv.checkIterationType(ConvergenceIterationTypes::NONLINEAR);
     404             :   }
     405             : 
     406             :   // linear
     407      173151 :   if (isParamValid("linear_convergence"))
     408             :   {
     409         268 :     const auto conv_names = getParam<std::vector<ConvergenceName>>("linear_convergence");
     410         268 :     for (const auto & conv_name : conv_names)
     411             :     {
     412         134 :       auto & conv = _problem.getConvergence(conv_name);
     413         134 :       conv.checkIterationType(ConvergenceIterationTypes::LINEAR);
     414             :     }
     415         134 :   }
     416             : 
     417             :   // multisystem fixed point
     418      173151 :   if (isParamValid("multi_system_fixed_point_convergence"))
     419             :   {
     420         842 :     _multi_sys_fp_convergence =
     421        1684 :         &_problem.getConvergence(getParam<ConvergenceName>("multi_system_fixed_point_convergence"));
     422         842 :     _multi_sys_fp_convergence->checkIterationType(
     423             :         ConvergenceIterationTypes::MULTISYSTEM_FIXED_POINT);
     424             :   }
     425       57717 : }
     426             : 
     427             : bool
     428      313086 : FEProblemSolve::solve()
     429             : {
     430             :   // Outer loop for multi-grid convergence
     431      313086 :   bool converged = false;
     432      313086 :   unsigned int fp_iter = 0;
     433             : 
     434      624261 :   for (MooseIndex(_num_grid_steps) grid_step = 0; grid_step <= _num_grid_steps; ++grid_step)
     435             :   {
     436             :     // Multi-system fixed point loop
     437      313136 :     fp_iter = 0;
     438      313136 :     converged = false;
     439      648999 :     while (!converged)
     440             :     {
     441      337833 :       if (_using_multi_sys_fp_iterations)
     442       25535 :         _console << COLOR_MAGENTA << "Multi-system fixed point iteration " << fp_iter << ":"
     443       25535 :                  << COLOR_DEFAULT << "\n"
     444       25535 :                  << std::endl;
     445             : 
     446             :       // Loop over each system
     447      677946 :       for (const auto sys_i : index_range(_systems))
     448             :       {
     449      342074 :         auto * const sys = _systems[sys_i];
     450      342074 :         const bool is_nonlinear = (dynamic_cast<NonlinearSystemBase *>(sys) != nullptr);
     451             :         const Real fp_relax =
     452      342074 :             _using_multi_sys_fp_iterations ? _multi_sys_fp_relax_factors[sys_i] : 1.0;
     453             :         const bool apply_fp_relax =
     454      342074 :             _using_multi_sys_fp_iterations && !MooseUtils::absoluteFuzzyEqual(fp_relax, 1.0);
     455      342074 :         if (apply_fp_relax)
     456             :         {
     457       20875 :           sys->setFixedPointRelaxationFactor(fp_relax);
     458       20875 :           sys->saveOldSolutionForFixedPointRelaxation();
     459             :         }
     460             : 
     461             :         // Call solve on the problem for that system
     462      342074 :         if (is_nonlinear)
     463      316356 :           _problem.solve(sys->number());
     464             :         else
     465             :         {
     466             :           const auto linear_sys_number =
     467       25718 :               cast_int<unsigned int>(sys->number() - _problem.numNonlinearSystems());
     468       25718 :           _problem.solveLinearSystem(linear_sys_number, &_problem.getPetscOptions());
     469             :         }
     470             : 
     471             :         // Check convergence
     472             :         const auto solve_name =
     473      675550 :             _systems.size() == 1 ? " Solve" : "System " + sys->name() + ": Solve";
     474      342016 :         if (_problem.shouldSolve())
     475             :         {
     476      308288 :           if (_problem.converged(sys->number()))
     477             :           {
     478      306385 :             if (apply_fp_relax)
     479       20875 :               sys->applyFixedPointRelaxation();
     480      306385 :             _console << COLOR_GREEN << solve_name << " Converged!" << COLOR_DEFAULT << "\n"
     481      306385 :                      << std::endl;
     482             :           }
     483             :           else
     484             :           {
     485        1900 :             _console << COLOR_RED << solve_name << " Did NOT Converge!" << COLOR_DEFAULT << "\n"
     486        1900 :                      << std::endl;
     487        1900 :             if (apply_fp_relax)
     488           0 :               sys->clearFixedPointRelaxation();
     489        1900 :             return false;
     490             :           }
     491             :         }
     492             :         else
     493       33728 :           _console << COLOR_GREEN << solve_name << " Skipped!" << COLOR_DEFAULT << "\n"
     494       33728 :                    << std::endl;
     495             : 
     496      340113 :         if (!is_nonlinear)
     497             :         {
     498             :           const auto linear_sys_number =
     499       25709 :               cast_int<unsigned int>(sys->number() - _problem.numNonlinearSystems());
     500       25709 :           auto & linear_sys = _problem.getLinearSystem(linear_sys_number);
     501             : 
     502             :           // This is for postprocessing purposes in case none of the objects request the gradients.
     503             :           // TODO: Somehow collect information if the postprocessors need gradients and if nothing
     504             :           // needs this, just skip it
     505       25709 :           linear_sys.computeGradients();
     506             :         }
     507             : 
     508      340113 :         if (apply_fp_relax)
     509       20875 :           sys->clearFixedPointRelaxation();
     510      342013 :       }
     511             : 
     512             :       // Assess convergence of the multi-system fixed point iteration
     513      335872 :       if (!_using_multi_sys_fp_iterations)
     514      310346 :         converged = true;
     515             :       else
     516             :       {
     517       25526 :         _problem.execute(EXEC_MULTISYSTEM_FIXED_POINT_CONVERGENCE);
     518             : 
     519             :         // checkConvergence expects the number of iterations performed, not the iteration index:
     520       25526 :         const auto n_fp_iter = fp_iter + 1;
     521       25526 :         const auto convergence_status = _multi_sys_fp_convergence->checkConvergence(n_fp_iter);
     522       25526 :         converged = convergence_status == Convergence::MooseConvergenceStatus::CONVERGED;
     523       25526 :         if (convergence_status == Convergence::MooseConvergenceStatus::DIVERGED)
     524           9 :           break;
     525             :       }
     526      335863 :       fp_iter++;
     527             :     }
     528             : 
     529      311175 :     if (grid_step != _num_grid_steps)
     530          50 :       _problem.uniformRefine();
     531             :   }
     532             : 
     533      311125 :   return converged;
     534             : }

Generated by: LCOV version 1.14