https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PetscContactLineSearch.C
Go to the documentation of this file.
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
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
18
24
26 : ContactLineSearchBase(parameters)
27{
28 _solver = dynamic_cast<PetscNonlinearSolver<Real> *>(
30 if (!_solver)
32 "This line search operates only with Petsc, so Petsc must be your nonlinear solver.");
33}
34
35void
37{
38 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 SNES snes = _solver->snes();
46
47 LibmeshPetscCall(SNESGetLineSearch(snes, &line_search));
48 LibmeshPetscCall(SNESLineSearchGetVecs(line_search, &X, &F, &Y, &W, &G));
49 LibmeshPetscCall(SNESLineSearchGetNorms(line_search, &xnorm, &fnorm, &ynorm));
50 LibmeshPetscCall(SNESLineSearchGetSNES(line_search, &snes));
51 LibmeshPetscCall(SNESLineSearchSetReason(line_search, SNES_LINESEARCH_SUCCEEDED));
52 LibmeshPetscCall(SNESGetKSP(snes, &ksp));
53 LibmeshPetscCall(KSPGetTolerances(ksp, &ksp_rtol, &ksp_abstol, &ksp_dtol, &ksp_maxits));
54 LibmeshPetscCall(VecDuplicate(W, &W1));
55
57 {
58 _user_ksp_rtol = ksp_rtol;
59 _user_ksp_rtol_set = true;
60 }
61
62 ++_nl_its;
63
64 /* precheck */
65 LibmeshPetscCall(SNESLineSearchPreCheck(line_search, X, Y, &changed_y));
66
67 /* temporary update */
68 _contact_lambda = 1.;
69 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 */
74 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 LibmeshPetscCall(SNESGetConvergedReason(snes, &reason));
83 if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
84 LibmeshPetscCall(SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN));
85#endif
86
87 LibmeshPetscCall(VecNorm(F, NORM_2, &fnorm));
88 std::set<dof_id_type> contact_state_stored = _current_contact_state;
90 printContactInfo(contact_state_stored);
91
92 if (_affect_ltol)
93 {
94 if (contact_state_stored != _old_contact_state)
95 {
96 LibmeshPetscCall(KSPSetTolerances(ksp, _contact_ltol, ksp_abstol, ksp_dtol, ksp_maxits));
97 _console << "Contact set changed since previous non-linear iteration!" << std::endl;
98 }
99 else
100 LibmeshPetscCall(KSPSetTolerances(ksp, _user_ksp_rtol, ksp_abstol, ksp_dtol, ksp_maxits));
101 }
102
103 size_t ls_its = 0;
104 while (ls_its < _allowed_lambda_cuts)
105 {
106 _contact_lambda *= 0.5;
107 /* update */
108 LibmeshPetscCall(VecWAXPY(W1, -_contact_lambda, Y, X));
109
110 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 LibmeshPetscCall(SNESGetConvergedReason(snes, &reason));
117 if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
118 LibmeshPetscCall(
119 SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN));
120#endif
121
122 LibmeshPetscCall(VecNorm(G, NORM_2, &gnorm));
123 if (gnorm < fnorm)
124 {
125 LibmeshPetscCall(VecCopy(G, F));
126 LibmeshPetscCall(VecCopy(W1, W));
127 fnorm = gnorm;
128 contact_state_stored.swap(_current_contact_state);
130 printContactInfo(contact_state_stored);
131 ++ls_its;
132 }
133 else
134 break;
135 }
136
137 LibmeshPetscCall(VecScale(Y, _contact_lambda));
138 /* postcheck */
139 LibmeshPetscCall(SNESLineSearchPostCheck(line_search, X, Y, W, &changed_y, &changed_w));
140
141 if (changed_y)
142 LibmeshPetscCall(VecWAXPY(W, -1., Y, X));
143
144 if (changed_w || changed_y)
145 {
146 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 LibmeshPetscCall(SNESGetConvergedReason(snes, &reason));
153 if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
154 LibmeshPetscCall(
155 SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN));
156#endif
157 contact_state_stored.swap(_current_contact_state);
159 printContactInfo(contact_state_stored);
160 }
161
162 /* copy the solution over */
163 LibmeshPetscCall(VecCopy(W, X));
164
165 LibmeshPetscCall(SNESLineSearchComputeNorms(line_search));
166
167 LibmeshPetscCall(VecDestroy(&W1));
168
169 _old_contact_state = std::move(contact_state_stored);
170}
registerMooseObject("ContactApp", PetscContactLineSearch)
const ConsoleStream _console
This class implements a custom line search for use with mechanical contact.
Real _contact_lambda
The multiplier of the newton step.
std::set< dof_id_type > _current_contact_state
The current contact set.
static InputParameters validParams()
void printContactInfo(const std::set< dof_id_type > &contact_set)
Method for printing the contact information.
std::set< dof_id_type > _old_contact_state
The old contact set.
bool _affect_ltol
Whether to modify the linear tolerance.
bool _user_ksp_rtol_set
Whether the user linear tolerance has been set yet in this object.
Real _user_ksp_rtol
the linear tolerance set by the user in the input file
unsigned _allowed_lambda_cuts
How many times the linsearch is allowed to cut lambda.
Real _contact_ltol
What the linear tolerance should be while the contact state is changing.
virtual NonlinearSystem & getNonlinearSystem(const unsigned int nl_sys_num) override
FEProblem & _fe_problem
size_t _nl_its
void mooseError(Args &&... args) const
virtual libMesh::NonlinearSolver< Number > * nonlinearSolver() override
Petsc implementation of the contact line search (based on the Petsc LineSearchShell)
PetscContactLineSearch(const InputParameters &parameters)
virtual void lineSearch() override
static InputParameters validParams()
PetscNonlinearSolver< Real > * _solver
SNES snes(const char *name=nullptr)