libMesh
Loading...
Searching...
No Matches
nonlinear_implicit_system_test.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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#include <libmesh/libmesh_config.h>
19
20// NonlinearSolver<T>::build() only has a working implementation when built
21// against one of these packages; without either, constructing a
22// NonlinearImplicitSystem throws unconditionally.
23#if defined(LIBMESH_HAVE_PETSC) || defined(LIBMESH_TRILINOS_HAVE_NOX)
24
25#include <libmesh/nonlinear_implicit_system.h>
26#include <libmesh/nonlinear_solver.h>
27#include <libmesh/sparse_matrix.h>
28#include <libmesh/libmesh_exceptions.h>
29#include <libmesh/equation_systems.h>
30#include <libmesh/mesh.h>
31#include <libmesh/mesh_generation.h>
32
33#include "test_comm.h"
34#include "libmesh_cppunit.h"
35
36using namespace libMesh;
37
38namespace
39{
40// Only overrides the single-matrix solve(), like a backend that doesn't
41// distinguish the Jacobian operator matrix from the preconditioning matrix,
42// relying on NonlinearSolver's own default two-matrix forwarding.
43class SingleMatrixNonlinearSolver : public NonlinearSolver<Number>
44{
45public:
46 explicit SingleMatrixNonlinearSolver(NonlinearImplicitSystem & s) : NonlinearSolver<Number>(s) {}
47
48 // Un-hide the base class's two-matrix solve() overload, which we don't
49 // override here since it's exactly the default forwarding behavior we're
50 // testing.
52
53 virtual void init(const char * = nullptr) override {}
54
55 virtual std::pair<unsigned int, Real>
59 const double,
60 const unsigned int) override
61 {
62 solved_with = &jac_in;
63 ++single_matrix_calls;
64 return {0, 0.};
65 }
66
67 virtual int get_total_linear_iterations() override { return 0; }
68 virtual unsigned get_current_nonlinear_iteration_number() const override { return 0; }
69
70 SparseMatrix<Number> * solved_with = nullptr;
71 unsigned int single_matrix_calls = 0;
72};
73
74// Also records which matrix(es) NonlinearImplicitSystem::solve() actually
75// passes down to the NonlinearSolver, without performing any real solve. On
76// top of the inherited single-matrix override, this overrides the
77// two-matrix solve() overload too, like a backend that distinguishes the
78// Jacobian operator matrix from the preconditioning matrix.
79class TwoMatrixNonlinearSolver : public SingleMatrixNonlinearSolver
80{
81public:
82 explicit TwoMatrixNonlinearSolver(NonlinearImplicitSystem & s) : SingleMatrixNonlinearSolver(s) {}
83
84 // Un-hide the inherited single-matrix override alongside our own
85 // two-matrix override below.
86 using SingleMatrixNonlinearSolver::solve;
87
88 virtual std::pair<unsigned int, Real>
89 solve(SparseMatrix<Number> & jac_in,
90 SparseMatrix<Number> & pre_in,
93 const double,
94 const unsigned int) override
95 {
96 solved_with = &jac_in;
97 solved_with_pre = &pre_in;
98 ++two_matrix_calls;
99 return {0, 0.};
100 }
101
102 SparseMatrix<Number> * solved_with_pre = nullptr;
103 unsigned int two_matrix_calls = 0;
104};
105}
106
107class NonlinearImplicitSystemOperatorMatrixTest : public CppUnit::TestCase
108{
109public:
111
114#ifdef LIBMESH_ENABLE_EXCEPTIONS
116#endif // LIBMESH_ENABLE_EXCEPTIONS
117
119
120public:
121
122 std::unique_ptr<Mesh> mesh;
123 std::unique_ptr<EquationSystems> es;
125
126 void setUp()
127 {
128 mesh = std::make_unique<Mesh>(*TestCommWorld);
130 es = std::make_unique<EquationSystems>(*mesh);
131 sys = &es->add_system<NonlinearImplicitSystem>("test");
132 es->init();
133 }
134
135 void tearDown()
136 {
137 sys = nullptr;
138 es.reset();
139 mesh.reset();
140 }
141
142 // Without an operator matrix registered, solve() should use the ordinary
143 // single-matrix path with the system's own preconditioning matrix.
145 {
146 LOG_UNIT_TEST;
147
148 auto solver = std::make_unique<TwoMatrixNonlinearSolver>(*sys);
149 auto * solver_ptr = solver.get();
150 sys->nonlinear_solver = std::move(solver);
151
152 sys->solve();
153
154 CPPUNIT_ASSERT(solver_ptr->solved_with == sys->matrix);
155 CPPUNIT_ASSERT_EQUAL(solver_ptr->single_matrix_calls, 1u);
156 CPPUNIT_ASSERT_EQUAL(solver_ptr->two_matrix_calls, 0u);
157 }
158
159 // set_operator_matrix() should make solve() use the two-matrix path, with
160 // the registered matrix as the Jacobian operator and the system's own
161 // matrix as the preconditioning matrix.
163 {
164 LOG_UNIT_TEST;
165
167 sys->set_operator_matrix(amat.get());
168
169 auto solver = std::make_unique<TwoMatrixNonlinearSolver>(*sys);
170 auto * solver_ptr = solver.get();
171 sys->nonlinear_solver = std::move(solver);
172
173 sys->solve();
174
175 CPPUNIT_ASSERT(solver_ptr->solved_with == amat.get());
176 CPPUNIT_ASSERT(solver_ptr->solved_with_pre == sys->matrix);
177 CPPUNIT_ASSERT_EQUAL(solver_ptr->two_matrix_calls, 1u);
178 CPPUNIT_ASSERT_EQUAL(solver_ptr->single_matrix_calls, 0u);
179 }
180
181#ifdef LIBMESH_ENABLE_EXCEPTIONS
182 // NonlinearSolver's own two-matrix solve() overload has no fallback
183 // implementation -- a backend (like this test's mock) that doesn't
184 // override it can't honor a distinct Jacobian operator matrix, so it must
185 // refuse rather than silently solving with the preconditioning matrix
186 // instead of the one the caller explicitly asked to use.
188 {
189 LOG_UNIT_TEST;
190
192 sys->set_operator_matrix(amat.get());
193
194 auto solver = std::make_unique<SingleMatrixNonlinearSolver>(*sys);
195 sys->nonlinear_solver = std::move(solver);
196
197 CPPUNIT_ASSERT_THROW(sys->solve(), libMesh::NotImplemented);
198 }
199#endif // LIBMESH_ENABLE_EXCEPTIONS
200};
201
203
204#endif // LIBMESH_HAVE_PETSC || LIBMESH_TRILINOS_HAVE_NOX
CPPUNIT_TEST(testTwoMatrixSolveWithoutOverrideThrows)
CPPUNIT_TEST(testOperatorMatrixUsesTwoMatrixSolve)
LIBMESH_CPPUNIT_TEST_SUITE(NonlinearImplicitSystemOperatorMatrixTest)
CPPUNIT_TEST(testDefaultUsesSingleMatrixSolve)
SparseMatrix< Number > * matrix
The system matrix.
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and non-linear solv...
virtual void solve() override
Assembles & solves the nonlinear system R(x) = 0.
std::unique_ptr< NonlinearSolver< Number > > nonlinear_solver
The NonlinearSolver defines the default interface used to solve the nonlinear_implicit system.
void set_operator_matrix(SparseMatrix< Number > *mat)
Set a matrix to use as the actual Jacobian operator (Amat) on the next solve(), distinct from matrix,...
This base class can be inherited from to provide interfaces to nonlinear solvers from different packa...
virtual unsigned get_current_nonlinear_iteration_number() const =0
virtual std::pair< unsigned int, Real > solve(SparseMatrix< T > &, NumericVector< T > &, NumericVector< T > &, const double, const unsigned int)=0
Solves the nonlinear system.
virtual void init(const char *name=nullptr)=0
Initialize data structures if not done so already.
virtual int get_total_linear_iterations()=0
Get the total number of linear iterations done in the last solve.
A class to stub for features that should be in libMesh, but haven't been written yet,...
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
Generic sparse matrix.
static std::unique_ptr< SparseMatrix< T > > build(const Parallel::Communicator &comm, const SolverPackage solver_package=libMesh::default_solver_package(), const MatrixBuildType matrix_build_type=MatrixBuildType::AUTOMATIC)
Builds a SparseMatrix<T> using the linear solver package specified by solver_package.
void init()
Initializes degrees of freedom on the current mesh.
Definition system.C:196
Communicator * TestCommWorld
void build_point(UnstructuredMesh &mesh, const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 0D meshes.
The libMesh namespace provides an interface to certain functionality in the library.
CPPUNIT_TEST_SUITE_REGISTRATION(NonlinearImplicitSystemOperatorMatrixTest)