LCOV - code coverage report
Current view: top level - src/linesearches - PetscContactLineSearch.C (source / functions) Hit Total Coverage
Test: idaholab/moose contact: #32971 (54bef8) with base c6cf66 Lines: 57 66 86.4 %
Date: 2026-05-29 20:36:03 Functions: 3 3 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             : #include "PetscContactLineSearch.h"
      11             : #include "FEProblem.h"
      12             : #include "NonlinearSystem.h"
      13             : #include "libmesh/petsc_nonlinear_solver.h"
      14             : #include "libmesh/petsc_solver_exception.h"
      15             : #include <petscdm.h>
      16             : 
      17             : registerMooseObject("ContactApp", PetscContactLineSearch);
      18             : 
      19             : InputParameters
      20          86 : PetscContactLineSearch::validParams()
      21             : {
      22          86 :   return ContactLineSearchBase::validParams();
      23             : }
      24             : 
      25          43 : PetscContactLineSearch::PetscContactLineSearch(const InputParameters & parameters)
      26          43 :   : ContactLineSearchBase(parameters)
      27             : {
      28          43 :   _solver = dynamic_cast<PetscNonlinearSolver<Real> *>(
      29          43 :       _fe_problem.getNonlinearSystem(/*nl_sys_num=*/0).nonlinearSolver());
      30          43 :   if (!_solver)
      31           0 :     mooseError(
      32             :         "This line search operates only with Petsc, so Petsc must be your nonlinear solver.");
      33          43 : }
      34             : 
      35             : void
      36        1182 : PetscContactLineSearch::lineSearch()
      37             : {
      38        1182 :   PetscBool changed_y = PETSC_FALSE, changed_w = PETSC_FALSE;
      39             :   Vec X, F, Y, W, G, W1;
      40             :   SNESLineSearch line_search;
      41             :   PetscReal fnorm, xnorm, ynorm, gnorm;
      42             :   PetscReal ksp_rtol, ksp_abstol, ksp_dtol;
      43             :   PetscInt ksp_maxits;
      44             :   KSP ksp;
      45        1182 :   SNES snes = _solver->snes();
      46             : 
      47        1182 :   LibmeshPetscCall(SNESGetLineSearch(snes, &line_search));
      48        1182 :   LibmeshPetscCall(SNESLineSearchGetVecs(line_search, &X, &F, &Y, &W, &G));
      49        1182 :   LibmeshPetscCall(SNESLineSearchGetNorms(line_search, &xnorm, &fnorm, &ynorm));
      50        1182 :   LibmeshPetscCall(SNESLineSearchGetSNES(line_search, &snes));
      51        1182 :   LibmeshPetscCall(SNESLineSearchSetReason(line_search, SNES_LINESEARCH_SUCCEEDED));
      52        1182 :   LibmeshPetscCall(SNESGetKSP(snes, &ksp));
      53        1182 :   LibmeshPetscCall(KSPGetTolerances(ksp, &ksp_rtol, &ksp_abstol, &ksp_dtol, &ksp_maxits));
      54        1182 :   LibmeshPetscCall(VecDuplicate(W, &W1));
      55             : 
      56        1182 :   if (!_user_ksp_rtol_set)
      57             :   {
      58          43 :     _user_ksp_rtol = ksp_rtol;
      59          43 :     _user_ksp_rtol_set = true;
      60             :   }
      61             : 
      62        1182 :   ++_nl_its;
      63             : 
      64             :   /* precheck */
      65        1182 :   LibmeshPetscCall(SNESLineSearchPreCheck(line_search, X, Y, &changed_y));
      66             : 
      67             :   /* temporary update */
      68        1182 :   _contact_lambda = 1.;
      69        1182 :   LibmeshPetscCall(VecWAXPY(W, -_contact_lambda, Y, X));
      70             : 
      71             :   /* compute residual to determine whether contact state has changed since the last non-linear
      72             :    * residual evaluation */
      73             :   _current_contact_state.clear();
      74        1182 :   LibmeshPetscCall(SNESComputeFunction(snes, W, F));
      75             : #if PETSC_VERSION_LESS_THAN(3, 25, 0)
      76             :   PetscBool domainerror;
      77             :   LibmeshPetscCall(SNESGetFunctionDomainError(snes, &domainerror));
      78             :   if (domainerror)
      79             :     LibmeshPetscCall(SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_DOMAIN));
      80             : #else
      81             :   SNESConvergedReason reason;
      82        1182 :   LibmeshPetscCall(SNESGetConvergedReason(snes, &reason));
      83        1182 :   if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
      84           0 :     LibmeshPetscCall(SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN));
      85             : #endif
      86             : 
      87        1182 :   LibmeshPetscCall(VecNorm(F, NORM_2, &fnorm));
      88             :   std::set<dof_id_type> contact_state_stored = _current_contact_state;
      89             :   _current_contact_state.clear();
      90        1182 :   printContactInfo(contact_state_stored);
      91             : 
      92        1182 :   if (_affect_ltol)
      93             :   {
      94          53 :     if (contact_state_stored != _old_contact_state)
      95             :     {
      96          19 :       LibmeshPetscCall(KSPSetTolerances(ksp, _contact_ltol, ksp_abstol, ksp_dtol, ksp_maxits));
      97          19 :       _console << "Contact set changed since previous non-linear iteration!" << std::endl;
      98             :     }
      99             :     else
     100          34 :       LibmeshPetscCall(KSPSetTolerances(ksp, _user_ksp_rtol, ksp_abstol, ksp_dtol, ksp_maxits));
     101             :   }
     102             : 
     103             :   size_t ls_its = 0;
     104        1739 :   while (ls_its < _allowed_lambda_cuts)
     105             :   {
     106        1470 :     _contact_lambda *= 0.5;
     107             :     /* update */
     108        1470 :     LibmeshPetscCall(VecWAXPY(W1, -_contact_lambda, Y, X));
     109             : 
     110        1470 :     LibmeshPetscCall(SNESComputeFunction(snes, W1, G));
     111             : #if PETSC_VERSION_LESS_THAN(3, 25, 0)
     112             :     LibmeshPetscCall(SNESGetFunctionDomainError(snes, &domainerror));
     113             :     if (domainerror)
     114             :       LibmeshPetscCall(SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_DOMAIN));
     115             : #else
     116        1470 :     LibmeshPetscCall(SNESGetConvergedReason(snes, &reason));
     117        1470 :     if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
     118           0 :       LibmeshPetscCall(
     119             :           SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN));
     120             : #endif
     121             : 
     122        1470 :     LibmeshPetscCall(VecNorm(G, NORM_2, &gnorm));
     123        1470 :     if (gnorm < fnorm)
     124             :     {
     125         557 :       LibmeshPetscCall(VecCopy(G, F));
     126         557 :       LibmeshPetscCall(VecCopy(W1, W));
     127         557 :       fnorm = gnorm;
     128             :       contact_state_stored.swap(_current_contact_state);
     129             :       _current_contact_state.clear();
     130         557 :       printContactInfo(contact_state_stored);
     131         557 :       ++ls_its;
     132             :     }
     133             :     else
     134             :       break;
     135             :   }
     136             : 
     137        1182 :   LibmeshPetscCall(VecScale(Y, _contact_lambda));
     138             :   /* postcheck */
     139        1182 :   LibmeshPetscCall(SNESLineSearchPostCheck(line_search, X, Y, W, &changed_y, &changed_w));
     140             : 
     141        1182 :   if (changed_y)
     142           0 :     LibmeshPetscCall(VecWAXPY(W, -1., Y, X));
     143             : 
     144        1182 :   if (changed_w || changed_y)
     145             :   {
     146           0 :     LibmeshPetscCall(SNESComputeFunction(snes, W, F));
     147             : #if PETSC_VERSION_LESS_THAN(3, 25, 0)
     148             :     LibmeshPetscCall(SNESGetFunctionDomainError(snes, &domainerror));
     149             :     if (domainerror)
     150             :       LibmeshPetscCall(SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_DOMAIN));
     151             : #else
     152           0 :     LibmeshPetscCall(SNESGetConvergedReason(snes, &reason));
     153           0 :     if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
     154           0 :       LibmeshPetscCall(
     155             :           SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN));
     156             : #endif
     157             :     contact_state_stored.swap(_current_contact_state);
     158             :     _current_contact_state.clear();
     159           0 :     printContactInfo(contact_state_stored);
     160             :   }
     161             : 
     162             :   /* copy the solution over */
     163        1182 :   LibmeshPetscCall(VecCopy(W, X));
     164             : 
     165        1182 :   LibmeshPetscCall(SNESLineSearchComputeNorms(line_search));
     166             : 
     167        1182 :   LibmeshPetscCall(VecDestroy(&W1));
     168             : 
     169             :   _old_contact_state = std::move(contact_state_stored);
     170        1182 : }

Generated by: LCOV version 1.14