libMesh
Loading...
Searching...
No Matches
time_solver_test_common.h
Go to the documentation of this file.
1#include <libmesh/dof_map.h>
2#include <libmesh/enum_solver_type.h>
3#include <libmesh/enum_preconditioner_type.h>
4#include <libmesh/fem_system.h>
5#include <libmesh/newton_solver.h>
6#include <libmesh/numeric_vector.h>
7#include <libmesh/parallel.h>
8
9#include "test_comm.h"
10#include "libmesh_cppunit.h"
11
12#include <memory>
13
14using namespace libMesh;
15
16template<typename TimeSolverType>
18{
19protected:
20
21 // Any specialized initialization that's needed for the test
22 virtual void aux_time_solver_init( TimeSolverType & /*time_solver*/ ){}
23
24 // Implementation for solving ODE of SystemType
25 // Note this test assumes that the time integrator gets the *exact* solution
26 // to within floating point tolerance.
27 template<typename SystemType>
28 void run_test_with_exact_soln(Real deltat, unsigned int n_timesteps)
29 {
33 SystemType & system = es.add_system<SystemType>("ScalarSystem");
34
35 system.time_solver = std::make_unique<TimeSolverType>(system);
36
37 es.init();
38
39 DiffSolver & solver = *(system.time_solver->diff_solver().get());
40 solver.relative_step_tolerance = std::numeric_limits<Real>::epsilon()*10;
41 solver.relative_residual_tolerance = std::numeric_limits<Real>::epsilon()*10;
42 solver.absolute_residual_tolerance = std::numeric_limits<Real>::epsilon()*10;
43
44 NewtonSolver & newton = cast_ref<NewtonSolver &>(solver);
45
46 // LASPACK GMRES + ILU defaults don't like these problems, so
47 // we'll use a sophisticated "just divide the scalars" solver instead.
50
51 system.deltat = deltat;
52
53 TimeSolverType * time_solver = cast_ptr<TimeSolverType *>(system.time_solver.get());
54 this->aux_time_solver_init(*time_solver);
55
56 // We're going to want to check our solution, and when we run
57 // "make check" with LIBMESH_RUN='mpirun -np N" for N>1 then we'll
58 // need to keep that check in sync with the processors that are just
59 // twiddling their thumbs, not owning our mesh point.
60 std::vector<dof_id_type> solution_index;
61 solution_index.push_back(0);
62 const bool has_solution = system.get_dof_map().all_semilocal_indices(solution_index);
63
64 for (unsigned int t_step=0; t_step != n_timesteps; ++t_step)
65 {
66 system.solve();
67 system.time_solver->advance_timestep();
68
69 Real rel_error = 0;
70
71 if (has_solution)
72 {
73 Number exact_soln = system.u(system.time);
74 rel_error = std::abs((exact_soln - (*system.solution)(0))/exact_soln);
75 }
76 system.comm().max(rel_error);
77
78 // Using relative error for comparison, so "exact" is 0
79 LIBMESH_ASSERT_FP_EQUAL( rel_error,
80 0.0,
81 std::numeric_limits<Real>::epsilon()*10 );
82 }
83 }
84
85};
86
88
93{
94public:
96 const std::string & name_in,
97 const unsigned int number_in)
98 : FEMSystem(es, name_in, number_in)
99 {}
100
101
103 virtual Number F( FEMContext & context, unsigned int qp ) =0;
104
106 virtual Number M( FEMContext & context, unsigned int qp ) =0;
107
109 virtual Number u( Real t ) =0;
110
111 virtual void init_data () override
112 {
113 _u_var = this->add_variable ("u", FIRST, LAGRANGE);
114 this->time_evolving(_u_var,1);
115 FEMSystem::init_data();
116 }
117
119 virtual bool element_time_derivative (bool request_jacobian,
120 DiffContext & context) override
121 {
122 FEMContext & c = cast_ref<FEMContext &>(context);
124
125 const unsigned int n_u_dofs =
126 cast_int<unsigned int>(c.get_dof_indices(_u_var).size());
127 unsigned int n_qpoints = c.get_element_qrule().n_points();
128
129 for (unsigned int qp=0; qp != n_qpoints; qp++)
130 {
131 Number Fval = this->F(c,qp);
132
133 for (unsigned int i=0; i != n_u_dofs; i++)
134 Fu(i) += Fval;
135 }
136
137 return request_jacobian;
138 }
139
141 virtual bool mass_residual (bool request_jacobian,
142 DiffContext & context) override
143 {
144 FEMContext & c = cast_ref<FEMContext &>(context);
147
148 const unsigned int n_u_dofs =
149 cast_int<unsigned int>(c.get_dof_indices(_u_var).size());
150 unsigned int n_qpoints = c.get_element_qrule().n_points();
151
152 for (unsigned int qp=0; qp != n_qpoints; qp++)
153 {
154 libMesh::Number udot;
155 c.interior_rate(_u_var,qp,udot);
156
157 Number Mval = this->M(c,qp);
158
159 for (unsigned int i=0; i != n_u_dofs; i++)
160 {
161 Fu(i) -= Mval*udot;
162
163 if (request_jacobian)
164 for (unsigned int j=0; j != n_u_dofs; j++)
165 Kuu(i,j) -= Mval*context.get_elem_solution_rate_derivative();
166 }
167 }
168
169 return request_jacobian;
170 }
171
172protected:
173 unsigned int _u_var;
174};
175
177
183{
184public:
186 const std::string & name_in,
187 const unsigned int number_in)
188 : FirstOrderScalarSystemBase(es, name_in, number_in)
189 {}
190
191 virtual void init_data () override
192 {
193 _u_var = this->add_variable ("u", FIRST, LAGRANGE);
194 this->time_evolving(_u_var,2);
195 FEMSystem::init_data();
196 }
197
199 virtual Number C( FEMContext & context, unsigned int qp ) =0;
200
202 virtual bool damping_residual (bool request_jacobian,
203 DiffContext & context) override
204 {
205 FEMContext & c = cast_ref<FEMContext &>(context);
208
209 const unsigned int n_u_dofs =
210 cast_int<unsigned int>(c.get_dof_indices(_u_var).size());
211 unsigned int n_qpoints = c.get_element_qrule().n_points();
212
213 for (unsigned int qp=0; qp != n_qpoints; qp++)
214 {
215 libMesh::Number udot;
216 c.interior_rate(_u_var,qp,udot);
217
218 Number Cval = this->C(c,qp);
219
220 for (unsigned int i=0; i != n_u_dofs; i++)
221 {
222 Fu(i) += Cval*udot;
223
224 if (request_jacobian)
225 for (unsigned int j=0; j != n_u_dofs; j++)
226 Kuu(i,j) += Cval*context.get_elem_solution_rate_derivative();
227 }
228 }
229
230 return request_jacobian;
231 }
232
233 virtual bool mass_residual (bool request_jacobian,
234 DiffContext & context) override
235 {
236 FEMContext & c = cast_ref<FEMContext &>(context);
239
240 const unsigned int n_u_dofs =
241 cast_int<unsigned int>(c.get_dof_indices(_u_var).size());
242 unsigned int n_qpoints = c.get_element_qrule().n_points();
243
244 for (unsigned int qp=0; qp != n_qpoints; qp++)
245 {
246 libMesh::Number uddot;
247 c.interior_accel(_u_var,qp,uddot);
248
249 Number Mval = this->M(c,qp);
250
251 for (unsigned int i=0; i != n_u_dofs; i++)
252 {
253 Fu(i) += Mval*uddot;
254
255 if (request_jacobian)
256 for (unsigned int j=0; j != n_u_dofs; j++)
257 Kuu(i,j) += Mval*context.get_elem_solution_accel_derivative();
258 }
259 }
260
261 return request_jacobian;
262 }
263};
264
265
267
273{
274public:
276 const std::string & name_in,
277 const unsigned int number_in)
279 {}
280
282 virtual bool element_time_derivative (bool request_jacobian,
283 DiffContext & context) override
284 {
285 FEMContext & c = cast_ref<FEMContext &>(context);
286
287 unsigned int v_var = this->get_second_order_dot_var(_u_var);
288
290
291 const unsigned int n_u_dofs =
292 cast_int<unsigned int>(c.get_dof_indices(_u_var).size());
293 unsigned int n_qpoints = c.get_element_qrule().n_points();
294
295 for (unsigned int qp=0; qp != n_qpoints; qp++)
296 {
297 Number Fval = this->F(c,qp);
298
299 for (unsigned int i=0; i != n_u_dofs; i++)
300 Fv(i) += Fval;
301 }
302
303 return request_jacobian;
304 }
305
307 virtual bool damping_residual (bool request_jacobian,
308 DiffContext & context) override
309 {
310 FEMContext & c = cast_ref<FEMContext &>(context);
311
312 unsigned int v_var = this->get_second_order_dot_var(_u_var);
313
315
316 DenseSubMatrix<Number> & Kvv = c.get_elem_jacobian(v_var, v_var);
317
318 const unsigned int n_u_dofs =
319 cast_int<unsigned int>(c.get_dof_indices(_u_var).size());
320 unsigned int n_qpoints = c.get_element_qrule().n_points();
321
322 for (unsigned int qp=0; qp != n_qpoints; qp++)
323 {
324 libMesh::Number udot;
325 c.interior_rate(v_var,qp,udot);
326
327 Number Cval = this->C(c,qp);
328
329 for (unsigned int i=0; i != n_u_dofs; i++)
330 {
331 Fv(i) += Cval*udot;
332
333 if (request_jacobian)
334 for (unsigned int j=0; j != n_u_dofs; j++)
335 Kvv(i,j) += Cval*context.get_elem_solution_rate_derivative();
336 }
337 }
338
339 return request_jacobian;
340 }
341
342 virtual bool mass_residual (bool request_jacobian,
343 DiffContext & context) override
344 {
345 FEMContext & c = cast_ref<FEMContext &>(context);
346
347 unsigned int v_var = this->get_second_order_dot_var(_u_var);
348
350 DenseSubMatrix<Number> & Kvv = c.get_elem_jacobian(v_var, v_var);
351
352 const unsigned int n_u_dofs =
353 cast_int<unsigned int>(c.get_dof_indices(_u_var).size());
354 unsigned int n_qpoints = c.get_element_qrule().n_points();
355
356 for (unsigned int qp=0; qp != n_qpoints; qp++)
357 {
358 libMesh::Number uddot;
359 c.interior_accel(v_var,qp,uddot);
360
361 Number Mval = this->M(c,qp);
362
363 for (unsigned int i=0; i != n_u_dofs; i++)
364 {
365 Fv(i) += Mval*uddot;
366
367 if (request_jacobian)
368 for (unsigned int j=0; j != n_u_dofs; j++)
369 Kvv(i,j) += Mval*context.get_elem_solution_accel_derivative();
370 }
371 }
372
373 return request_jacobian;
374 }
375};
FEMSystem-based class for testing of TimeSolvers using first order SCALARs.
FirstOrderScalarSystemBase(EquationSystems &es, const std::string &name_in, const unsigned int number_in)
virtual Number u(Real t)=0
Exact solution as a function of time t.
virtual bool element_time_derivative(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is F(u)-M(u)
virtual void init_data() override
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used.
virtual Number F(FEMContext &context, unsigned int qp)=0
Value of F(u)
virtual Number M(FEMContext &context, unsigned int qp)=0
Value of M(u).
virtual bool mass_residual(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is F(u)-M(u)
FEMSystem-based class for testing of TimeSolvers using second order SCALARs.
virtual bool mass_residual(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is F(u)-M(u)
virtual bool element_time_derivative(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is M(u)
SecondOrderScalarSystemFirstOrderTimeSolverBase(EquationSystems &es, const std::string &name_in, const unsigned int number_in)
virtual bool damping_residual(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is M(u)
FEMSystem-based class for testing of TimeSolvers using second order SCALARs.
virtual bool mass_residual(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is F(u)-M(u)
virtual Number C(FEMContext &context, unsigned int qp)=0
Value of C(u).
virtual void init_data() override
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used.
SecondOrderScalarSystemSecondOrderTimeSolverBase(EquationSystems &es, const std::string &name_in, const unsigned int number_in)
virtual bool damping_residual(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is M(u)\ddot{u} + C(u)
virtual void aux_time_solver_init(TimeSolverType &)
void run_test_with_exact_soln(Real deltat, unsigned int n_timesteps)
Defines a dense submatrix for use in Finite Element-type computations.
Defines a dense subvector for use in finite element computations.
This class provides all data required for a physics package (e.g.
const std::vector< dof_id_type > & get_dof_indices() const
Accessor for element dof indices.
Real get_elem_solution_accel_derivative() const
The derivative of the current elem_solution_accel w.r.t.
Real get_elem_solution_rate_derivative() const
The derivative of the current elem_solution_rate w.r.t.
const DenseVector< Number > & get_elem_residual() const
Const accessor for element residual.
const DenseMatrix< Number > & get_elem_jacobian() const
Const accessor for element Jacobian.
This is a generic class that defines a solver to handle ImplicitSystem classes, including NonlinearIm...
Definition diff_solver.h:70
Real absolute_residual_tolerance
The DiffSolver should exit after the residual is reduced to either less than absolute_residual_tolera...
virtual void time_evolving(unsigned int var, unsigned int order)
Tells the DiffSystem that variable var is evolving with respect to time.
unsigned int get_second_order_dot_var(unsigned int var) const
For a given second order (in time) variable var, this method will return the index to the correspondi...
This is the EquationSystems class.
virtual void init()
Initialize all the systems.
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
This class provides all data required for a physics package (e.g.
Definition fem_context.h:63
void interior_rate(unsigned int var, unsigned int qp, OutputType &u) const
const QBase & get_element_qrule() const
Accessor for element interior quadrature rule for the dimension of the current _elem.
void interior_accel(unsigned int var, unsigned int qp, OutputType &u) const
This class provides a specific system class.
Definition fem_system.h:55
void set_preconditioner_type(const PreconditionerType pct)
Sets the type of preconditioner to use.
void set_solver_type(const SolverType st)
Sets the type of solver to use.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
This class defines a solver which uses the default libMesh linear solver in a quasiNewton method to h...
LinearSolver< Number > & get_linear_solver()
unsigned int n_points() const
Definition quadrature.h:131
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition system.C:1344
Communicator * TestCommWorld
MeshBase & mesh
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.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real