www.mooseframework.org
PetscContactLineSearch.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 
18 
21 {
23 }
24 
26  : ContactLineSearchBase(parameters)
27 {
28  _solver = dynamic_cast<PetscNonlinearSolver<Real> *>(
29  _fe_problem.getNonlinearSystem(/*nl_sys_num=*/0).nonlinearSolver());
30  if (!_solver)
31  mooseError(
32  "This line search operates only with Petsc, so Petsc must be your nonlinear solver.");
33 }
34 
35 void
37 {
38  PetscBool changed_y = PETSC_FALSE, changed_w = PETSC_FALSE;
39  PetscErrorCode ierr;
40  Vec X, F, Y, W, G, W1;
41  SNESLineSearch line_search;
42  PetscReal fnorm, xnorm, ynorm, gnorm;
43  PetscBool domainerror;
44  PetscReal ksp_rtol, ksp_abstol, ksp_dtol;
45  PetscInt ksp_maxits;
46  KSP ksp;
47  SNES snes = _solver->snes();
48 
49  ierr = SNESGetLineSearch(snes, &line_search);
50  LIBMESH_CHKERR(ierr);
51  ierr = SNESLineSearchGetVecs(line_search, &X, &F, &Y, &W, &G);
52  LIBMESH_CHKERR(ierr);
53  ierr = SNESLineSearchGetNorms(line_search, &xnorm, &fnorm, &ynorm);
54  LIBMESH_CHKERR(ierr);
55  ierr = SNESLineSearchGetSNES(line_search, &snes);
56  LIBMESH_CHKERR(ierr);
57  ierr = SNESLineSearchSetReason(line_search, SNES_LINESEARCH_SUCCEEDED);
58  LIBMESH_CHKERR(ierr);
59  ierr = SNESGetKSP(snes, &ksp);
60  LIBMESH_CHKERR(ierr);
61  ierr = KSPGetTolerances(ksp, &ksp_rtol, &ksp_abstol, &ksp_dtol, &ksp_maxits);
62  LIBMESH_CHKERR(ierr);
63  ierr = VecDuplicate(W, &W1);
64  LIBMESH_CHKERR(ierr);
65 
66  if (!_user_ksp_rtol_set)
67  {
68  _user_ksp_rtol = ksp_rtol;
69  _user_ksp_rtol_set = true;
70  }
71 
72  ++_nl_its;
73 
74  /* precheck */
75  ierr = SNESLineSearchPreCheck(line_search, X, Y, &changed_y);
76  LIBMESH_CHKERR(ierr);
77 
78  /* temporary update */
79  _contact_lambda = 1.;
80  ierr = VecWAXPY(W, -_contact_lambda, Y, X);
81  LIBMESH_CHKERR(ierr);
82 
83  /* compute residual to determine whether contact state has changed since the last non-linear
84  * residual evaluation */
85  _current_contact_state.clear();
86  ierr = SNESComputeFunction(snes, W, F);
87  LIBMESH_CHKERR(ierr);
88  ierr = SNESGetFunctionDomainError(snes, &domainerror);
89  LIBMESH_CHKERR(ierr);
90  if (domainerror)
91  {
92  ierr = SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_DOMAIN);
93  LIBMESH_CHKERR(ierr);
94  }
95  ierr = VecNorm(F, NORM_2, &fnorm);
96  LIBMESH_CHKERR(ierr);
97  std::set<dof_id_type> contact_state_stored = _current_contact_state;
98  _current_contact_state.clear();
99  printContactInfo(contact_state_stored);
100 
101  if (_affect_ltol)
102  {
103  if (contact_state_stored != _old_contact_state)
104  {
105  KSPSetTolerances(ksp, _contact_ltol, ksp_abstol, ksp_dtol, ksp_maxits);
106  _console << "Contact set changed since previous non-linear iteration!" << std::endl;
107  }
108  else
109  KSPSetTolerances(ksp, _user_ksp_rtol, ksp_abstol, ksp_dtol, ksp_maxits);
110  }
111 
112  size_t ls_its = 0;
113  while (ls_its < _allowed_lambda_cuts)
114  {
115  _contact_lambda *= 0.5;
116  /* update */
117  ierr = VecWAXPY(W1, -_contact_lambda, Y, X);
118  LIBMESH_CHKERR(ierr);
119 
120  ierr = SNESComputeFunction(snes, W1, G);
121  LIBMESH_CHKERR(ierr);
122  ierr = SNESGetFunctionDomainError(snes, &domainerror);
123  LIBMESH_CHKERR(ierr);
124  if (domainerror)
125  {
126  ierr = SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_DOMAIN);
127  LIBMESH_CHKERR(ierr);
128  }
129  ierr = VecNorm(G, NORM_2, &gnorm);
130  LIBMESH_CHKERR(ierr);
131  if (gnorm < fnorm)
132  {
133  VecCopy(G, F);
134  LIBMESH_CHKERR(ierr);
135  VecCopy(W1, W);
136  LIBMESH_CHKERR(ierr);
137  fnorm = gnorm;
138  contact_state_stored.swap(_current_contact_state);
139  _current_contact_state.clear();
140  printContactInfo(contact_state_stored);
141  ++ls_its;
142  }
143  else
144  break;
145  }
146 
147  ierr = VecScale(Y, _contact_lambda);
148  LIBMESH_CHKERR(ierr);
149  /* postcheck */
150  ierr = SNESLineSearchPostCheck(line_search, X, Y, W, &changed_y, &changed_w);
151  LIBMESH_CHKERR(ierr);
152 
153  if (changed_y)
154  {
155  ierr = VecWAXPY(W, -1., Y, X);
156  LIBMESH_CHKERR(ierr);
157  }
158 
159  if (changed_w || changed_y)
160  {
161  ierr = SNESComputeFunction(snes, W, F);
162  LIBMESH_CHKERR(ierr);
163  ierr = SNESGetFunctionDomainError(snes, &domainerror);
164  LIBMESH_CHKERR(ierr);
165  if (domainerror)
166  {
167  ierr = SNESLineSearchSetReason(line_search, SNES_LINESEARCH_FAILED_DOMAIN);
168  LIBMESH_CHKERR(ierr);
169  }
170  contact_state_stored.swap(_current_contact_state);
171  _current_contact_state.clear();
172  printContactInfo(contact_state_stored);
173  }
174 
175  /* copy the solution over */
176  ierr = VecCopy(W, X);
177  LIBMESH_CHKERR(ierr);
178 
179  ierr = SNESLineSearchComputeNorms(line_search);
180  LIBMESH_CHKERR(ierr);
181 
182  ierr = VecDestroy(&W1);
183  LIBMESH_CHKERR(ierr);
184 
185  _old_contact_state = std::move(contact_state_stored);
186 }
bool _affect_ltol
Whether to modify the linear tolerance.
std::set< dof_id_type > _old_contact_state
The old contact set.
Real _contact_ltol
What the linear tolerance should be while the contact state is changing.
std::set< dof_id_type > _current_contact_state
The current contact set.
virtual void lineSearch() override
FEProblem & _fe_problem
ierr
static const std::string F
Definition: NS.h:150
virtual NonlinearSolver< Number > * nonlinearSolver() override
static const std::string G
Definition: NS.h:151
registerMooseObject("ContactApp", PetscContactLineSearch)
This class implements a custom line search for use with mechanical contact.
Petsc implementation of the contact line search (based on the Petsc LineSearchShell) ...
Real _contact_lambda
The multiplier of the newton step.
static InputParameters validParams()
PetscContactLineSearch(const InputParameters &parameters)
unsigned _allowed_lambda_cuts
How many times the linsearch is allowed to cut lambda.
void printContactInfo(const std::set< dof_id_type > &contact_set)
Method for printing the contact information.
void mooseError(Args &&... args) const
const ConsoleStream _console
Real _user_ksp_rtol
the linear tolerance set by the user in the input file
PetscNonlinearSolver< Real > * _solver
size_t _nl_its
static InputParameters validParams()
virtual NonlinearSystem & getNonlinearSystem(const unsigned int nl_sys_num) override
bool _user_ksp_rtol_set
Whether the user linear tolerance has been set yet in this object.