Loading [MathJax]/extensions/tex2jax.js
libMesh
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
linear_implicit_system.C
Go to the documentation of this file.
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 // C++ includes
21 
22 // Local includes
23 #include "libmesh/linear_implicit_system.h"
24 #include "libmesh/linear_solver.h"
25 #include "libmesh/equation_systems.h"
26 #include "libmesh/numeric_vector.h" // for parameter sensitivity calcs
27 //#include "libmesh/parameter_vector.h"
28 #include "libmesh/sparse_matrix.h" // for get_transpose
29 #include "libmesh/system_subset.h"
30 #include "libmesh/static_condensation.h"
31 #include "libmesh/static_condensation_preconditioner.h"
32 
33 namespace libMesh
34 {
35 
36 
38  const std::string & name_in,
39  const unsigned int number_in) :
40 
41  Parent (es, name_in, number_in),
42  _n_linear_iterations (0),
43  _final_linear_residual (1.e20),
44  _shell_matrix(nullptr),
45  _subset(nullptr),
46  _subset_solve_mode(SUBSET_ZERO)
47 {
48  // linear_solver is now in the ImplicitSystem base class, but we are
49  // going to keep using it basically the way we did before it was
50  // moved.
52 
53  if (this->has_static_condensation())
55 }
56 
57 
58 
60 
61 
62 
64 {
67 }
68 
69 
70 
72 {
73  // clear the linear solver
74  linear_solver->clear();
75 
76  this->restrict_solve_to(nullptr);
77 
78  // clear the parent data
79  Parent::clear();
80 }
81 
82 
83 
85 {
86  // initialize parent data
88 
89  // re-initialize the linear solver interface
90  linear_solver->clear();
91 }
92 
93 
94 
96 {
97  // re-initialize the linear solver interface
98  linear_solver->clear();
99 
100  // initialize parent data
101  Parent::reinit();
102 }
103 
104 
105 
107  const SubsetSolveMode subset_solve_mode)
108 {
109  _subset = subset;
110  _subset_solve_mode = subset_solve_mode;
111 
112  if (subset != nullptr)
113  libmesh_assert_equal_to (&subset->get_system(), this);
114 }
115 
116 
117 
119 {
120  if (this->assemble_before_solve)
121  // Assemble the linear system
122  this->assemble ();
123 
124  // If the linear solver hasn't been initialized, we do so here.
125  if (this->prefix_with_name())
126  linear_solver->init(this->prefix().c_str());
127  else
128  linear_solver->init();
129 
130  linear_solver->init_names(*this);
131 
132  // Get the user-specified linear solver tolerance
133  const auto [maxits, tol] = this->get_linear_solve_parameters();
134 
135  if (_subset != nullptr)
136  linear_solver->restrict_solve_to(&_subset->dof_ids(),_subset_solve_mode);
137 
138  // Solve the linear system. Several cases:
139  std::pair<unsigned int, Real> rval = std::make_pair(0,0.0);
140  if (_shell_matrix)
141  // 1.) Shell matrix with or without user-supplied preconditioner.
142  rval = linear_solver->solve(*_shell_matrix, this->request_matrix("Preconditioner"), *solution, *rhs, tol, maxits);
143  else
144  // 2.) No shell matrix, with or without user-supplied preconditioner
145  rval = linear_solver->solve (*matrix, this->request_matrix("Preconditioner"), *solution, *rhs, tol, maxits);
146 
147  if (_subset != nullptr)
148  linear_solver->restrict_solve_to(nullptr);
149 
150  // Store the number of linear iterations required to
151  // solve and the final residual.
152  _n_linear_iterations = rval.first;
153  _final_linear_residual = rval.second;
154 
155  // Update the system after the solve
156  this->update();
157 }
158 
159 
160 
162 {
163  _shell_matrix = shell_matrix;
164 }
165 
166 
167 /*
168  void LinearImplicitSystem::sensitivity_solve (const ParameterVector & parameters)
169  {
170  if (this->assemble_before_solve)
171  {
172  // Assemble the linear system
173  this->assemble ();
174 
175  // But now assemble right hand sides with the residual's
176  // parameter derivatives
177  this->assemble_residual_derivatives(parameters);
178  }
179 
180  // Get a reference to the EquationSystems
181  const EquationSystems & es =
182  this->get_equation_systems();
183 
184  // Get the user-specified linear solver tolerance
185  const Real tol =
186  es.parameters.get<Real>("sensitivity solver tolerance");
187 
188  // Get the user-specified maximum # of linear solver iterations
189  const unsigned int maxits =
190  es.parameters.get<unsigned int>("sensitivity solver maximum iterations");
191 
192  // Our iteration counts and residuals will be sums of the individual
193  // results
194  _n_linear_iterations = 0;
195  _final_linear_residual = 0.0;
196  std::pair<unsigned int, Real> rval = std::make_pair(0,0.0);
197 
198  // Solve the linear system.
199  SparseMatrix<Number> * pc = this->request_matrix("Preconditioner");
200  for (std::size_t p=0; p != parameters.size(); ++p)
201  {
202  rval = linear_solver->solve (*matrix, pc,
203  this->get_sensitivity_solution(p),
204  this->get_sensitivity_rhs(p), tol, maxits);
205  _n_linear_iterations += rval.first;
206  _final_linear_residual += rval.second;
207  }
208 
209  // Our matrix is the *negative* of the Jacobian for b-A*u, so our
210  // solutions are all inverted
211  for (std::size_t p=0; p != parameters.size(); ++p)
212  {
213  this->get_sensitivity_solution(p) *= -1.0;
214  }
215  }
216 
217 
218 
219  void LinearImplicitSystem::adjoint_solve (const QoISet & qoi_indices)
220  {
221  const unsigned int Nq = this->n_qois();
222 
223  // We currently don't support adjoint solves of shell matrices
224  // FIXME - we should let shell matrices support
225  // vector_transpose_mult so that we can use them here.
226  if (_shell_matrix!=nullptr)
227  libmesh_not_implemented();
228 
229  if (this->assemble_before_solve)
230  {
231  // Assemble the linear system
232  this->assemble ();
233 
234  // And take the adjoint
235  matrix->get_transpose(*matrix);
236 
237  // Including of any separate preconditioner
238  SparseMatrix<Number> * pc = this->request_matrix("Preconditioner");
239  if (pc)
240  pc->get_transpose(*pc);
241 
242  // But now replace the right hand sides with the quantity of
243  // interest functional's derivative
244  this->assemble_qoi_derivative(qoi_indices);
245  }
246 
247  // Get a reference to the EquationSystems
248  const EquationSystems & es =
249  this->get_equation_systems();
250 
251  // Get the user-specified linear solver tolerance
252  const Real tol =
253  es.parameters.get<Real>("adjoint solver tolerance");
254 
255  // Get the user-specified maximum # of linear solver iterations
256  const unsigned int maxits =
257  es.parameters.get<unsigned int>("adjoint solver maximum iterations");
258 
259  // Our iteration counts and residuals will be sums of the individual
260  // results
261  _n_linear_iterations = 0;
262  _final_linear_residual = 0.0;
263  std::pair<unsigned int, Real> rval = std::make_pair(0,0.0);
264 
265  // Solve the linear system.
266  SparseMatrix<Number> * pc = this->request_matrix("Preconditioner");
267  for (unsigned int i=0; i != Nq; ++i)
268  if (qoi_indices.has_index(i))
269  {
270  rval = linear_solver->solve (*matrix, pc,
271  this->add_adjoint_solution(i),
272  this->get_adjoint_rhs(i), tol, maxits);
273  _n_linear_iterations += rval.first;
274  _final_linear_residual += rval.second;
275  }
276  }
277 
278 
279 
280  void LinearImplicitSystem::forward_qoi_parameter_sensitivity
281  (const QoISet & qoi_indices,
282  const ParameterVector & parameters,
283  SensitivityData & sensitivities)
284  {
285  const unsigned int Np = parameters.size();
286  const unsigned int Nq = this->n_qois();
287 
288  // An introduction to the problem:
289  //
290  // A(p)*u(p) = b(p), where x is determined implicitly.
291  // Residual R(u(p),p) := b(p) - A(p)*u(p)
292  // partial R / partial u = -A
293  //
294  // This implies that:
295  // d/dp(R) = 0
296  // (partial b / partial p) -
297  // (partial A / partial p) * u -
298  // A * (partial u / partial p) = 0
299  // A * (partial u / partial p) = (partial R / partial p)
300  // = (partial b / partial p) - (partial A / partial p) * u
301 
302  // We first solve for (partial u / partial p) for each parameter:
303  // -A * (partial u / partial p) = - (partial R / partial p)
304 
305  this->sensitivity_solve(parameters);
306 
307  // Get ready to fill in sensitivities:
308  sensitivities.allocate_data(qoi_indices, *this, parameters);
309 
310  // We use the identity:
311  // dq/dp = (partial q / partial p) + (partial q / partial u) *
312  // (partial u / partial p)
313 
314  // We get (partial q / partial u) from the user
315  this->assemble_qoi_derivative(qoi_indices);
316 
317  for (unsigned int j=0; j != Np; ++j)
318  {
319  // We currently get partial derivatives via central differencing
320  Number delta_p = 1e-6;
321 
322  // (partial q / partial p) ~= (q(p+dp)-q(p-dp))/(2*dp)
323 
324  Number old_parameter = *parameters[j];
325 
326  *parameters[j] = old_parameter - delta_p;
327  this->assemble_qoi(qoi_indices);
328  std::vector<Number> qoi_minus = this->qoi;
329 
330  *parameters[j] = old_parameter + delta_p;
331  this->assemble_qoi(qoi_indices);
332  std::vector<Number> & qoi_plus = this->qoi;
333  std::vector<Number> partialq_partialp(Nq, 0);
334  for (unsigned int i=0; i != Nq; ++i)
335  if (qoi_indices.has_index(i))
336  partialq_partialp[i] = (qoi_plus[i] - qoi_minus[i]) / (2.*delta_p);
337 
338  for (unsigned int i=0; i != Nq; ++i)
339  if (qoi_indices.has_index(i))
340  sensitivities[i][j] = partialq_partialp[i] +
341  this->get_adjoint_rhs(i).dot(this->get_sensitivity_solution(i));
342  }
343 
344  // All parameters have been reset.
345  // Don't leave the qoi or system changed - principle of least
346  // surprise.
347  this->assemble();
348  this->rhs->close();
349  this->matrix->close();
350  this->assemble_qoi(qoi_indices);
351  }
352 */
353 
354 
355 
357 {
358  return linear_solver.get();
359 }
360 
361 
362 
364  bool,
365  bool,
366  bool)
367 {
368  // Residual R(u(p),p) := A(p)*u(p) - b(p)
369  // partial R / partial u = A
370 
371  this->assemble();
372  this->rhs->close();
373  this->matrix->close();
374 
375  *(this->rhs) *= -1.0;
376  this->rhs->add_vector(*this->solution, *this->matrix);
377 }
378 
379 } // namespace libMesh
virtual void restrict_solve_to(const SystemSubset *subset, const SubsetSolveMode subset_solve_mode=SUBSET_ZERO) override
After calling this method, any solve will be limited to the given subset.
void attach_shell_matrix(ShellMatrix< Number > *shell_matrix)
This function enables the user to provide a shell matrix, i.e.
virtual void assemble() override
Prepares matrix and _dof_map for matrix assembly.
virtual void create_static_condensation() override
Request that static condensation be performed for this system.
This is the EquationSystems class.
ShellMatrix< Number > * _shell_matrix
User supplies shell matrix or nullptr if no shell matrix is used.
static std::unique_ptr< LinearSolver< T > > build(const libMesh::Parallel::Communicator &comm_in, const SolverPackage solver_package=libMesh::default_solver_package())
Builds a LinearSolver using the linear solver package specified by solver_package.
Definition: linear_solver.C:59
unsigned int _n_linear_iterations
The number of linear iterations required to solve the linear system Ax=b.
virtual void create_static_condensation() override
Request that static condensation be performed for this system.
virtual std::pair< unsigned int, Real > get_linear_solve_parameters() const
virtual void reinit()
Reinitializes degrees of freedom and other required data on the current mesh.
Definition: system.C:454
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices)
Computes , where v is a pointer and each dof_indices[i] specifies where to add value v[i]...
virtual void clear() override
Clear all the data structures associated with the system.
virtual void init_data()
Initializes the data for the system.
Definition: system.C:208
LinearImplicitSystem(EquationSystems &es, const std::string &name, const unsigned int number)
Constructor.
NumericVector< Number > * rhs
The system matrix.
const Parallel::Communicator & comm() const
virtual void reinit() override
Reinitializes the member data fields associated with the system, so that, e.g., assemble() may be use...
SubsetSolveMode _subset_solve_mode
If restrict-solve-to-subset mode is active, this member decides what happens with the dofs outside th...
virtual LinearSolver< Number > * get_linear_solver() const override
bool has_static_condensation() const
Definition: system.C:2871
The libMesh namespace provides an interface to certain functionality in the library.
virtual void solve() override
Assembles & solves the linear system A*x=b.
const SparseMatrix< Number > * request_matrix(std::string_view mat_name) const
Definition: system.C:1100
void setup_static_condensation_preconditioner(T &solver)
Sets up the static condensation preconditioner for the supplied solver.
virtual void init_data() override
Initializes new data members of the system.
virtual void assembly(bool get_residual, bool get_jacobian, bool apply_heterogeneous_constraints=false, bool apply_no_constraints=false) override
Assembles a residual in rhs and/or a jacobian in matrix, as requested.
std::string prefix() const
Definition: system.h:1938
This is a base class for classes which represent subsets of the dofs of a System. ...
Definition: system_subset.h:42
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:96
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1593
virtual const std::vector< unsigned int > & dof_ids() const =0
virtual void close()=0
Calls the NumericVector&#39;s internal assembly routines, ensuring that the values are consistent across ...
Real _final_linear_residual
The final residual for the linear system Ax=b.
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition: system.C:510
virtual void close()=0
Calls the SparseMatrix&#39;s internal assembly routines, ensuring that the values are consistent across p...
SparseMatrix< Number > * matrix
The system matrix.
const System & get_system() const
Definition: system_subset.C:38
virtual void clear() override
Clear all the data structures associated with the system.
const SystemSubset * _subset
The current subset on which to solve (or nullptr if none).
bool assemble_before_solve
Flag which tells the system to whether or not to call the user assembly function during each call to ...
Definition: system.h:1547
std::unique_ptr< LinearSolver< Number > > linear_solver
This class handles all the details of interfacing with various linear algebra packages like PETSc or ...
SubsetSolveMode
defines an enum for the question what happens to the dofs outside the given subset when a system is s...
bool prefix_with_name() const
Definition: system.h:1932