libMesh
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 
14 using namespace libMesh;
15 
16 template<typename TimeSolverType>
18 {
19 protected:
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 {
94 public:
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);
116  }
117 
119  virtual bool element_time_derivative (bool request_jacobian,
120  DiffContext & context) override
121  {
122  FEMContext & c = cast_ref<FEMContext &>(context);
123  DenseSubVector<Number> & Fu = c.get_elem_residual(_u_var);
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);
145  DenseSubVector<Number> & Fu = c.get_elem_residual(_u_var);
146  DenseSubMatrix<Number> & Kuu = c.get_elem_jacobian(_u_var, _u_var);
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 
172 protected:
173  unsigned int _u_var;
174 };
175 
177 
183 {
184 public:
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);
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);
206  DenseSubVector<Number> & Fu = c.get_elem_residual(_u_var);
207  DenseSubMatrix<Number> & Kuu = c.get_elem_jacobian(_u_var, _u_var);
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);
237  DenseSubVector<Number> & Fu = c.get_elem_residual(_u_var);
238  DenseSubMatrix<Number> & Kuu = c.get_elem_jacobian(_u_var, _u_var);
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 {
274 public:
276  const std::string & name_in,
277  const unsigned int number_in)
278  : SecondOrderScalarSystemSecondOrderTimeSolverBase(es, name_in, 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 };
void run_test_with_exact_soln(Real deltat, unsigned int n_timesteps)
LinearSolver< Number > & get_linear_solver()
Definition: newton_solver.h:81
This is the EquationSystems class.
const DenseMatrix< Number > & get_elem_jacobian() const
Const accessor for element Jacobian.
Definition: diff_context.h:274
void build_point(UnstructuredMesh &mesh, const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 0D meshes.
This class provides all data required for a physics package (e.g.
Definition: diff_context.h:55
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:159
virtual bool element_time_derivative(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is M(u)
void interior_accel(unsigned int var, unsigned int qp, OutputType &u) const
Definition: fem_context.C:1385
Real absolute_residual_tolerance
The DiffSolver should exit after the residual is reduced to either less than absolute_residual_tolera...
Definition: diff_solver.h:189
SecondOrderScalarSystemSecondOrderTimeSolverBase(EquationSystems &es, const std::string &name_in, const unsigned int number_in)
MeshBase & mesh
The libMesh namespace provides an interface to certain functionality in the library.
This class provides a specific system class.
Definition: fem_system.h:53
virtual bool mass_residual(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is F(u)-M(u)
This class defines a solver which uses the default libMesh linear solver in a quasiNewton method to h...
Definition: newton_solver.h:46
Defines a dense subvector for use in finite element computations.
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
Definition: type_vector.h:57
This is a generic class that defines a solver to handle ImplicitSystem classes, including NonlinearIm...
Definition: diff_solver.h:68
virtual bool element_time_derivative(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is F(u)-M(u)
Defines a dense submatrix for use in Finite Element-type computations.
void set_preconditioner_type(const PreconditionerType pct)
Sets the type of preconditioner to use.
virtual void init_data() override
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used...
Definition: fem_system.C:873
This class provides all data required for a physics package (e.g.
Definition: fem_context.h:62
const std::vector< dof_id_type > & get_dof_indices() const
Accessor for element dof indices.
Definition: diff_context.h:363
unsigned int n_points() const
Definition: quadrature.h:123
void set_solver_type(const SolverType st)
Sets the type of solver to use.
FEMSystem-based class for testing of TimeSolvers using first order SCALARs.
Real get_elem_solution_accel_derivative() const
The derivative of the current elem_solution_accel w.r.t.
Definition: diff_context.h:450
virtual bool mass_residual(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is F(u)-M(u)
const DenseVector< Number > & get_elem_residual() const
Const accessor for element residual.
Definition: diff_context.h:242
FirstOrderScalarSystemBase(EquationSystems &es, const std::string &name_in, const unsigned int number_in)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
FEMSystem-based class for testing of TimeSolvers using second order SCALARs.
Real get_elem_solution_rate_derivative() const
The derivative of the current elem_solution_rate w.r.t.
Definition: diff_context.h:441
SecondOrderScalarSystemFirstOrderTimeSolverBase(EquationSystems &es, const std::string &name_in, const unsigned int number_in)
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.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
virtual void init_data() override
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used...
virtual bool mass_residual(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is F(u)-M(u)
void interior_rate(unsigned int var, unsigned int qp, OutputType &u) const
Definition: fem_context.C:1354
FEMSystem-based class for testing of TimeSolvers using second order SCALARs.
const QBase & get_element_qrule() const
Accessor for element interior quadrature rule for the dimension of the current _elem.
Definition: fem_context.h:802
virtual bool damping_residual(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is M(u)
Real relative_residual_tolerance
Definition: diff_solver.h:190
virtual void init_data() override
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used...
virtual void aux_time_solver_init(TimeSolverType &)
virtual bool damping_residual(bool request_jacobian, DiffContext &context) override
Note the nonlinear residual is M(u){u} + C(u)