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 bool rejected_trial = false;
105 while (ls_its < _allowed_lambda_cuts)
106 {
107 _contact_lambda *= 0.5;
108 /* update */
109 LibmeshPetscCall(VecWAXPY(W1, -_contact_lambda, Y, X));
110
111 LibmeshPetscCall(SNESComputeFunction(snes, W1, G));
112#if PETSC_VERSION_LESS_THAN(3, 25, 0)
113 LibmeshPetscCall(SNESGetFunctionDomainError(snes, &domainerror));
114 if (domainerror)
115 LibmeshPetscCall(SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_DOMAIN));
116#else
117 LibmeshPetscCall(SNESGetConvergedReason(snes, &reason));
118 if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
119 LibmeshPetscCall(
120 SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN));
121#endif
122
123 LibmeshPetscCall(VecNorm(G, NORM_2, &gnorm));
124 if (gnorm < fnorm)
125 {
126 LibmeshPetscCall(VecCopy(G, F));
127 LibmeshPetscCall(VecCopy(W1, W));
128 fnorm = gnorm;
129 contact_state_stored.swap(_current_contact_state);
131 printContactInfo(contact_state_stored);
132 ++ls_its;
133 }
134 else
135 {
136 rejected_trial = true;
138 break;
139 }
140 }
141
142 LibmeshPetscCall(VecScale(Y, _contact_lambda));
143 /* postcheck */
144 LibmeshPetscCall(SNESLineSearchPostCheck(line_search, X, Y, W, &changed_y, &changed_w));
145
146 if (changed_y)
147 LibmeshPetscCall(VecWAXPY(W, -1., Y, X));
148
149 if (rejected_trial || changed_w || changed_y)
150 {
151 LibmeshPetscCall(SNESComputeFunction(snes, W, F));
152#if PETSC_VERSION_LESS_THAN(3, 25, 0)
153 LibmeshPetscCall(SNESGetFunctionDomainError(snes, &domainerror));
154 if (domainerror)
155 LibmeshPetscCall(SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_DOMAIN));
156#else
157 LibmeshPetscCall(SNESGetConvergedReason(snes, &reason));
158 if (reason == SNES_DIVERGED_FUNCTION_DOMAIN)
159 LibmeshPetscCall(
160 SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN));
161#endif
162 contact_state_stored.swap(_current_contact_state);
164 printContactInfo(contact_state_stored);
165 }
166
167 /* copy the solution over */
168 LibmeshPetscCall(VecCopy(W, X));
169
170 LibmeshPetscCall(SNESLineSearchComputeNorms(line_search));
171
172 LibmeshPetscCall(VecDestroy(&W1));
173
174 _old_contact_state = std::move(contact_state_stored);
175}
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)