LCOV - code coverage report
Current view: top level - src/systems - nonlinear_implicit_system.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 75 145 51.7 %
Date: 2025-08-19 19:27:09 Functions: 6 11 54.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : 
      20             : // Local includes
      21             : #include "libmesh/nonlinear_implicit_system.h"
      22             : #include "libmesh/diff_solver.h"
      23             : #include "libmesh/equation_systems.h"
      24             : #include "libmesh/libmesh_logging.h"
      25             : #include "libmesh/nonlinear_solver.h"
      26             : #include "libmesh/sparse_matrix.h"
      27             : #include "libmesh/static_condensation.h"
      28             : #include "libmesh/static_condensation_preconditioner.h"
      29             : 
      30             : namespace libMesh
      31             : {
      32             : 
      33        1470 : NonlinearImplicitSystem::NonlinearImplicitSystem (EquationSystems & es,
      34             :                                                   const std::string & name_in,
      35        1470 :                                                   const unsigned int number_in) :
      36             : 
      37             :   Parent                    (es, name_in, number_in),
      38        1386 :   nonlinear_solver          (NonlinearSolver<Number>::build(*this)),
      39        1386 :   diff_solver               (),
      40        1386 :   _n_nonlinear_iterations   (0),
      41        1470 :   _final_nonlinear_residual (1.e20)
      42             : {
      43             :   // Set default parameters
      44             :   // These were chosen to match the Petsc defaults
      45        1470 :   es.parameters.set<Real>        ("linear solver tolerance") = 1e-5;
      46        1470 :   es.parameters.set<Real>        ("linear solver minimum tolerance") = 1e-5;
      47        1470 :   es.parameters.set<unsigned int>("linear solver maximum iterations") = 10000;
      48             : 
      49        1470 :   es.parameters.set<unsigned int>("nonlinear solver maximum iterations") = 50;
      50        1470 :   es.parameters.set<unsigned int>("nonlinear solver maximum function evaluations") = 10000;
      51             : 
      52        1470 :   es.parameters.set<Real>("nonlinear solver absolute residual tolerance") = 1e-35;
      53        1470 :   es.parameters.set<Real>("nonlinear solver relative residual tolerance") = 1e-8;
      54        1470 :   es.parameters.set<Real>("nonlinear solver divergence tolerance") = 1e+4;
      55        1470 :   es.parameters.set<Real>("nonlinear solver absolute step tolerance") = 1e-8;
      56        1470 :   es.parameters.set<Real>("nonlinear solver relative step tolerance") = 1e-8;
      57             : 
      58        1470 :   es.parameters.set<bool>("reuse preconditioner") = false;
      59        1470 :   es.parameters.set<unsigned int>("reuse preconditioner maximum linear iterations") = 1;
      60             : 
      61        1470 :   if (this->has_static_condensation())
      62         280 :     this->setup_static_condensation_preconditioner(*nonlinear_solver);
      63        1470 : }
      64             : 
      65             : 
      66             : 
      67        2508 : NonlinearImplicitSystem::~NonlinearImplicitSystem () = default;
      68             : 
      69             : 
      70             : 
      71           0 : void NonlinearImplicitSystem::create_static_condensation()
      72             : {
      73           0 :   Parent::create_static_condensation();
      74           0 :   this->setup_static_condensation_preconditioner(*nonlinear_solver);
      75           0 : }
      76             : 
      77             : 
      78             : 
      79         280 : void NonlinearImplicitSystem::clear ()
      80             : {
      81             :   // clear the nonlinear solver
      82         280 :   nonlinear_solver->clear();
      83             : 
      84             :   // FIXME - this is necessary for petsc_auto_fieldsplit
      85             :   // nonlinear_solver->init_names(*this);
      86             : 
      87             :   // clear the parent data
      88         280 :   Parent::clear();
      89         280 : }
      90             : 
      91             : 
      92             : 
      93           0 : void NonlinearImplicitSystem::reinit ()
      94             : {
      95             :   // re-initialize the nonlinear solver interface
      96           0 :   nonlinear_solver->clear();
      97             : 
      98             :   // force the solver to get a new preconditioner, in
      99             :   // case reuse was set
     100           0 :   nonlinear_solver->force_new_preconditioner();
     101             : 
     102             :   // FIXME - this is necessary for petsc_auto_fieldsplit
     103             :   // nonlinear_solver->init_names(*this);
     104             : 
     105           0 :   if (diff_solver.get())
     106           0 :     diff_solver->reinit();
     107             : 
     108             :   // initialize parent data
     109           0 :   Parent::reinit();
     110           0 : }
     111             : 
     112             : 
     113             : 
     114       29400 : void NonlinearImplicitSystem::set_solver_parameters ()
     115             : {
     116             :   // Get a reference to the EquationSystems
     117             :   const EquationSystems & es =
     118        1680 :     this->get_equation_systems();
     119             : 
     120             :   // Get the user-specified nonlinear solver tolerances
     121       57960 :   const unsigned int maxits = parameters.have_parameter<unsigned int>("nonlinear solver maximum iterations") ?
     122           0 :     parameters.get<unsigned int>("nonlinear solver maximum iterations") :
     123       57960 :     es.parameters.get<unsigned int>("nonlinear solver maximum iterations");
     124             : 
     125       57960 :   const unsigned int maxfuncs = parameters.have_parameter<unsigned int>("nonlinear solver maximum function evaluations") ?
     126           0 :     parameters.get<unsigned int>("nonlinear solver maximum function evaluations") :
     127       57960 :     es.parameters.get<unsigned int>("nonlinear solver maximum function evaluations");
     128             : 
     129       57960 :   const double abs_resid_tol = parameters.have_parameter<Real>("nonlinear solver absolute residual tolerance") ?
     130           0 :     double(parameters.get<Real>("nonlinear solver absolute residual tolerance")) :
     131       57960 :     double(es.parameters.get<Real>("nonlinear solver absolute residual tolerance"));
     132             : 
     133       57960 :   const double rel_resid_tol = parameters.have_parameter<Real>("nonlinear solver relative residual tolerance") ?
     134           0 :     double(parameters.get<Real>("nonlinear solver relative residual tolerance")) :
     135       57960 :     double(es.parameters.get<Real>("nonlinear solver relative residual tolerance"));
     136             : 
     137       57960 :   const double div_tol = parameters.have_parameter<Real>("nonlinear solver divergence tolerance") ?
     138           0 :     double(parameters.get<Real>("nonlinear solver divergence tolerance")) :
     139       57960 :     double(es.parameters.get<Real>("nonlinear solver divergence tolerance"));
     140             : 
     141       57960 :   const double abs_step_tol = parameters.have_parameter<Real>("nonlinear solver absolute step tolerance") ?
     142           0 :     double(parameters.get<Real>("nonlinear solver absolute step tolerance")) :
     143       57960 :     double(es.parameters.get<Real>("nonlinear solver absolute step tolerance"));
     144             : 
     145       57960 :   const double rel_step_tol = parameters.have_parameter<Real>("nonlinear solver relative step tolerance")?
     146           0 :     double(parameters.get<Real>("nonlinear solver relative step tolerance")) :
     147       29400 :     double(es.parameters.get<Real>("nonlinear solver relative step tolerance"));
     148             : 
     149             :   // Get the user-specified linear solver tolerances
     150       29400 :   const auto [maxlinearits, linear_tol] = this->Parent::get_linear_solve_parameters();
     151             : 
     152       57960 :   const double linear_min_tol = parameters.have_parameter<Real>("linear solver minimum tolerance") ?
     153           0 :     double(parameters.get<Real>("linear solver minimum tolerance")) :
     154       57960 :     double(es.parameters.get<Real>("linear solver minimum tolerance"));
     155             : 
     156       29400 :   const bool reuse_preconditioner = parameters.have_parameter<unsigned int>("reuse preconditioner") ?
     157           0 :     parameters.get<unsigned int>("reuse preconditioner") :
     158       29400 :       es.parameters.get<bool>("reuse preconditioner");
     159             :   const unsigned int reuse_preconditioner_max_linear_its =
     160       57960 :     parameters.have_parameter<unsigned int>("reuse preconditioner maximum linear iterations") ?
     161           0 :     parameters.get<unsigned int>("reuse preconditioner maximum linear iterations") :
     162       57960 :       es.parameters.get<unsigned int>("reuse preconditioner maximum linear iterations");
     163             : 
     164             :   // Set all the parameters on the NonlinearSolver
     165       29400 :   nonlinear_solver->max_nonlinear_iterations = maxits;
     166       29400 :   nonlinear_solver->max_function_evaluations = maxfuncs;
     167       29400 :   nonlinear_solver->absolute_residual_tolerance = abs_resid_tol;
     168       29400 :   nonlinear_solver->relative_residual_tolerance = rel_resid_tol;
     169       29400 :   nonlinear_solver->divergence_tolerance = div_tol;
     170       29400 :   nonlinear_solver->absolute_step_tolerance = abs_step_tol;
     171       29400 :   nonlinear_solver->relative_step_tolerance = rel_step_tol;
     172       29400 :   nonlinear_solver->max_linear_iterations = maxlinearits;
     173       29400 :   nonlinear_solver->initial_linear_tolerance = linear_tol;
     174       29400 :   nonlinear_solver->minimum_linear_tolerance = linear_min_tol;
     175       29400 :   nonlinear_solver->set_reuse_preconditioner(reuse_preconditioner);
     176       29400 :   nonlinear_solver->set_reuse_preconditioner_max_linear_its(reuse_preconditioner_max_linear_its);
     177             : 
     178       29400 :   if (diff_solver.get())
     179             :     {
     180           0 :       diff_solver->max_nonlinear_iterations = maxits;
     181           0 :       diff_solver->absolute_residual_tolerance = abs_resid_tol;
     182           0 :       diff_solver->relative_residual_tolerance = rel_resid_tol;
     183           0 :       diff_solver->absolute_step_tolerance = abs_step_tol;
     184           0 :       diff_solver->relative_step_tolerance = rel_step_tol;
     185           0 :       diff_solver->max_linear_iterations = maxlinearits;
     186           0 :       diff_solver->initial_linear_tolerance = linear_tol;
     187           0 :       diff_solver->minimum_linear_tolerance = linear_min_tol;
     188             :     }
     189       29400 : }
     190             : 
     191             : 
     192             : 
     193       29400 : void NonlinearImplicitSystem::solve ()
     194             : {
     195             :   // Log how long the nonlinear solve takes.
     196        1680 :   LOG_SCOPE("solve()", "System");
     197             : 
     198       29400 :   this->set_solver_parameters();
     199             : 
     200       29400 :   if (diff_solver.get())
     201             :     {
     202           0 :       diff_solver->solve();
     203             : 
     204             :       // Store the number of nonlinear iterations required to
     205             :       // solve and the final residual.
     206           0 :       _n_nonlinear_iterations   = diff_solver->total_outer_iterations();
     207           0 :       _final_nonlinear_residual = 0.; // FIXME - support this!
     208             :     }
     209             :   else
     210             :     {
     211       29400 :       if (this->prefix_with_name())
     212           0 :         nonlinear_solver->init(this->prefix().c_str());
     213             :       else
     214       29400 :         nonlinear_solver->init();
     215             : 
     216             :       // FIXME - this is necessary for petsc_auto_fieldsplit
     217             :       // nonlinear_solver->init_names(*this);
     218             : 
     219             :       // Solve the nonlinear system.
     220             :       // Store the number of nonlinear iterations required to
     221             :       // solve and the final residual.
     222       29400 :       std::tie(_n_nonlinear_iterations, _final_nonlinear_residual) =
     223       30240 :         nonlinear_solver->solve (*matrix, *solution, *rhs,
     224         840 :                                  nonlinear_solver->relative_residual_tolerance,
     225        3360 :                                  nonlinear_solver->max_linear_iterations);
     226             :     }
     227             : 
     228             :   // Update the system after the solve
     229       29400 :   this->update();
     230       29400 : }
     231             : 
     232             : 
     233             : 
     234           0 : std::pair<unsigned int, Real> NonlinearImplicitSystem::get_linear_solve_parameters() const
     235             : {
     236           0 :   if (diff_solver.get())
     237           0 :     return std::make_pair(this->diff_solver->max_linear_iterations,
     238           0 :                           this->diff_solver->relative_residual_tolerance);
     239           0 :   return std::make_pair(this->nonlinear_solver->max_linear_iterations,
     240           0 :                         this->nonlinear_solver->relative_residual_tolerance);
     241             : }
     242             : 
     243             : 
     244             : 
     245           0 : void NonlinearImplicitSystem::assembly(bool get_residual,
     246             :                                        bool get_jacobian,
     247             :                                        bool /*apply_heterogeneous_constraints*/,
     248             :                                        bool /*apply_no_constraints*/)
     249             : {
     250             :   // Get current_local_solution in sync
     251           0 :   this->update();
     252             : 
     253             :   //-----------------------------------------------------------------------------
     254             :   // if the user has provided both function pointers and objects only the pointer
     255             :   // will be used, so catch that as an error
     256           0 :   libmesh_error_msg_if(nonlinear_solver->jacobian && nonlinear_solver->jacobian_object,
     257             :                        "ERROR: cannot specify both a function and object to compute the Jacobian!");
     258             : 
     259           0 :   libmesh_error_msg_if(nonlinear_solver->residual && nonlinear_solver->residual_object,
     260             :                        "ERROR: cannot specify both a function and object to compute the Residual!");
     261             : 
     262           0 :   libmesh_error_msg_if(nonlinear_solver->matvec && nonlinear_solver->residual_and_jacobian_object,
     263             :                        "ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!");
     264             : 
     265             : 
     266           0 :   if (get_jacobian)
     267             :     {
     268           0 :       if (nonlinear_solver->jacobian != nullptr)
     269           0 :         nonlinear_solver->jacobian (*current_local_solution.get(), *matrix, *this);
     270             : 
     271           0 :       else if (nonlinear_solver->jacobian_object != nullptr)
     272           0 :         nonlinear_solver->jacobian_object->jacobian (*current_local_solution.get(), *matrix, *this);
     273             : 
     274           0 :       else if (nonlinear_solver->matvec != nullptr)
     275           0 :         nonlinear_solver->matvec (*current_local_solution.get(), get_residual ? rhs : nullptr, matrix, *this);
     276             : 
     277           0 :       else if (nonlinear_solver->residual_and_jacobian_object != nullptr)
     278           0 :         nonlinear_solver->residual_and_jacobian_object->residual_and_jacobian (*current_local_solution.get(), get_residual ? rhs : nullptr, matrix, *this);
     279             : 
     280             :       else
     281           0 :         libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
     282             :     }
     283             : 
     284           0 :   if (get_residual)
     285             :     {
     286           0 :       if (nonlinear_solver->residual != nullptr)
     287           0 :         nonlinear_solver->residual (*current_local_solution.get(), *rhs, *this);
     288             : 
     289           0 :       else if (nonlinear_solver->residual_object != nullptr)
     290           0 :         nonlinear_solver->residual_object->residual (*current_local_solution.get(), *rhs, *this);
     291             : 
     292           0 :       else if (nonlinear_solver->matvec != nullptr)
     293             :         {
     294             :           // we might have already grabbed the residual and jacobian together
     295           0 :           if (!get_jacobian)
     296           0 :             nonlinear_solver->matvec (*current_local_solution.get(), rhs, nullptr, *this);
     297             :         }
     298             : 
     299           0 :       else if (nonlinear_solver->residual_and_jacobian_object != nullptr)
     300             :         {
     301             :           // we might have already grabbed the residual and jacobian together
     302           0 :           if (!get_jacobian)
     303           0 :             nonlinear_solver->residual_and_jacobian_object->residual_and_jacobian (*current_local_solution.get(), rhs, nullptr, *this);
     304             :         }
     305             : 
     306             :       else
     307           0 :         libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");
     308             :     }
     309             :   else
     310           0 :     libmesh_assert(get_jacobian);  // I can't believe you really wanted to assemble *nothing*
     311           0 : }
     312             : 
     313             : 
     314             : 
     315             : 
     316           0 : unsigned NonlinearImplicitSystem::get_current_nonlinear_iteration_number() const
     317             : {
     318           0 :   return nonlinear_solver->get_current_nonlinear_iteration_number();
     319             : }
     320             : 
     321             : 
     322             : 
     323             : } // namespace libMesh

Generated by: LCOV version 1.14