Amandus: Simulations based on multilevel Schwarz methods
tests.h
Go to the documentation of this file.
1 /**********************************************************************
2  * Copyright (C) 2011 - 2014 by the authors
3  * Distributed under the MIT License
4  *
5  * See the files AUTHORS and LICENSE in the project root directory
6  *
7  **********************************************************************/
8 
9 #ifndef __tests_h
10 #define __tests_h
11 
12 #include <deal.II/algorithms/any_data.h>
13 #include <deal.II/base/logstream.h>
14 #include <deal.II/base/utilities.h>
15 #include <deal.II/lac/vector.h>
16 
17 #include <amandus/amandus.h>
18 
22 DeclException1(ExcErrorTooLarge, double, << "error " << arg1 << " is too large");
23 
35 template <int dim>
36 void
37 solve_and_error(dealii::BlockVector<double>& errors, AmandusApplicationSparse<dim>& app,
38  dealii::Algorithms::OperatorBase& solver,
39  dealii::Algorithms::OperatorBase& residual, const AmandusIntegrator<dim>& error)
40 {
41  dealii::Vector<double> res;
42  dealii::Vector<double> sol;
43 
44  solver.notify(dealii::Algorithms::Events::remesh);
45  app.setup_system();
46  app.setup_vector(res);
47  app.setup_vector(sol);
48 
49  dealii::AnyData solution_data;
50  dealii::Vector<double>* p = &sol;
51  solution_data.add(p, "solution");
52 
53  dealii::AnyData data;
54  dealii::Vector<double>* rhs = &res;
55  data.add(rhs, "RHS");
56  dealii::AnyData residual_data;
57  residual(data, residual_data);
58  dealii::deallog << "Residual " << res.l2_norm() << std::endl;
59  solver(solution_data, data);
60  app.output_results(0, &solution_data);
61 
62  app.error(errors, solution_data, error);
63 }
64 
76 template <int dim>
77 void
78 iterative_solve_and_error(dealii::BlockVector<double>& errors, AmandusApplicationSparse<dim>& app,
79  dealii::Algorithms::OperatorBase& solver,
80  const ErrorIntegrator<dim>& error,
81  const dealii::Function<dim>* initial_function = 0,
82  unsigned int n_qpoints = 0)
83 {
84  dealii::Vector<double> solution;
85 
86  app.setup_system();
87  app.setup_vector(solution);
88  if (n_qpoints == 0)
89  {
90  n_qpoints = app.dofs().get_fe().tensor_degree() + 1;
91  }
92  dealii::QGauss<dim> quadrature(n_qpoints);
93  if (initial_function != 0)
94  {
95  dealii::VectorTools::project(
96  app.dofs(), app.hanging_nodes(), quadrature, *initial_function, solution);
97  }
98 
99  solver.notify(dealii::Algorithms::Events::remesh);
100 
101  dealii::AnyData solution_data;
102  dealii::Vector<double>* p = &solution;
103  solution_data.add(p, "solution");
104 
105  dealii::AnyData data;
106  solver(solution_data, data);
107  app.error(errors, solution_data, error);
108 }
109 
131 template <int dim>
132 class ExactResidual : public AmandusResidual<dim>
133 {
134 public:
136  AmandusIntegrator<dim>& integrator, const dealii::Function<dim>& exact_solution,
137  unsigned int n_qpoints)
138  : AmandusResidual<dim>(application, integrator)
139  , exact_solution(&exact_solution)
140  , quadrature(n_qpoints)
141  {
142  }
143 
144  virtual void operator()(dealii::AnyData& out, const dealii::AnyData& in)
145  {
146  dealii::LogStream::Prefix p("ExactResidual");
147 
148  if (this->notifications.test(dealii::Algorithms::Events::initial) ||
149  this->notifications.test(dealii::Algorithms::Events::remesh))
150  {
151  dealii::deallog << "Projecting exact solution." << std::endl;
152  this->application->setup_vector(projection);
153  dealii::VectorTools::project(this->application->dofs(),
154  this->application->hanging_nodes(),
155  quadrature,
157  projection);
158  this->notifications.clear();
159  }
160 
162 
163  dealii::AnyData exact_residual_out;
164  dealii::AnyData exact_residual_in;
165 
166  dealii::Vector<double> exact_residual;
167  this->application->setup_vector(exact_residual);
168 
169  // calculate again a residual, but this time with the exact solution
170  // as input. Notice that this works only because AnyData uses the
171  // _first_ entry it finds for a given name.
172  exact_residual_in.add<const dealii::Vector<double>*>(&projection, "Newton iterate");
173  exact_residual_in.merge(in);
174  exact_residual_out.add<dealii::Vector<double>*>(&exact_residual, "Residual");
175  AmandusResidual<dim>::operator()(exact_residual_out, exact_residual_in);
176 
177  // subtract the residual of the exact solution
178  out.entry<dealii::Vector<double>*>("Residual")->add(-1.0, exact_residual);
179  }
180 
181 private:
182  const dealii::Function<dim>* exact_solution;
183  const dealii::QGauss<dim> quadrature;
184  dealii::Vector<double> projection;
185 };
186 
195 template <int dim>
196 class TensorProductPolynomial : public dealii::Function<dim>
197 {
198 public:
199  TensorProductPolynomial(const dealii::Polynomials::Polynomial<double>& pol,
200  unsigned int n_components = 1)
201  : dealii::Function<dim>(n_components)
202  , polynomial(&pol)
203  , derivative(pol.derivative())
204  , derivative2(derivative.derivative())
205  , derivative3(derivative2.derivative())
206  {
207  }
208 
209  virtual double
210  value(const dealii::Point<dim>& p, const unsigned int /*component = 0*/) const
211  {
212  double value = 1;
213  for (std::size_t d = 0; d < dim; ++d)
214  {
215  value *= polynomial->value(p(d));
216  }
217  return value;
218  }
219 
220  virtual dealii::Tensor<1, dim>
221  gradient(const dealii::Point<dim>& p, const unsigned int /*component = 0*/) const
222  {
223  dealii::Tensor<1, dim> grad;
224  for (std::size_t d = 0; d < dim; ++d)
225  {
226  grad[d] = 1.0;
227  for (std::size_t i = 0; i < dim; ++i)
228  {
229  grad[d] *= (i != d) ? polynomial->value(p(i)) : derivative.value(p(d));
230  }
231  }
232 
233  return grad;
234  }
235 
236  virtual double
237  laplacian(const dealii::Point<dim>& p, const unsigned int /*component = 0*/) const
238  {
239  double laplace = 0.0;
240  for (std::size_t d = 0; d < dim; ++d)
241  {
242  double factor = 1.0;
243  for (std::size_t i = 0; i < dim; ++i)
244  {
245  factor *= (i != d) ? polynomial->value(p(i)) : derivative2.value(p(d));
246  }
247  laplace += factor;
248  }
249  return laplace;
250  }
251 
252  dealii::Tensor<1, dim>
253  gradient_laplacian(const dealii::Point<dim>& p, const unsigned int /*component = 0*/) const
254  {
255  dealii::Tensor<1, dim> grad;
256  for (std::size_t d = 0; d < dim; ++d)
257  {
258  double grad1 = 1.0;
259  double grad2 = 0.0;
260  for (std::size_t i = 0; i < dim; ++i)
261  {
262  grad1 *= (i != d) ? polynomial->value(p(i)) : derivative3.value(p(d));
263  }
264  for (std::size_t j = 0; j < dim; ++j)
265  {
266  if (j != d)
267  {
268  double grad2factor = 1.0;
269  for (std::size_t i = 0; i < dim; ++i)
270  {
271  if (i != j && i != d)
272  {
273  grad2factor *= polynomial->value(p(i));
274  }
275  else if (i == d)
276  {
277  grad2factor *= derivative.value(p(i));
278  }
279  else
280  {
281  grad2factor *= derivative2.value(p(i));
282  }
283  }
284  grad2 += grad2factor;
285  }
286  }
287  grad[d] = grad1 + grad2;
288  }
289 
290  return grad;
291  }
292 
293 private:
294  const dealii::Polynomials::Polynomial<double>* polynomial;
295  const dealii::Polynomials::Polynomial<double> derivative;
296  const dealii::Polynomials::Polynomial<double> derivative2;
297  const dealii::Polynomials::Polynomial<double> derivative3;
298 };
299 
303 template <int dim>
304 void
305 verify_residual(unsigned int n_refinements, AmandusApplicationSparse<dim>& app,
306  AmandusIntegrator<dim>& matrix_integrator,
307  AmandusIntegrator<dim>& residual_integrator)
308 {
309  dealii::Vector<double> seed;
310  dealii::Vector<double> diff;
311 
312  for (unsigned int s = 0; s < n_refinements; ++s)
313  {
314  app.refine_mesh(true);
315 
316  app.setup_system();
317  app.setup_vector(seed);
318  app.setup_vector(diff);
319 
320  for (unsigned int i = 0; i < seed.size(); ++i)
321  seed(i) = dealii::Utilities::generate_normal_random_number(0., 1.);
322 
323  dealii::AnyData diff_data;
324  dealii::Vector<double>* p = &diff;
325  diff_data.add(p, "diff");
326 
327  dealii::AnyData data;
328  dealii::Vector<double>* rhs = &seed;
329  data.add(rhs, "Newton iterate");
330 
331  app.assemble_matrix(data, matrix_integrator);
332  app.verify_residual(diff_data, data, residual_integrator);
333  app.output_results(s, &diff_data);
334 
335  dealii::deallog << "Difference " << diff.l2_norm() << std::endl;
336  }
337 }
338 
342 template <int dim>
343 void
344 verify_theta_residual(unsigned int n_refinements, AmandusApplicationSparse<dim>& app,
345  AmandusIntegrator<dim>& matrix_integrator,
346  AmandusIntegrator<dim>& residual_integrator)
347 {
348  dealii::Vector<double> seed;
349  dealii::Vector<double> prev;
350  dealii::Vector<double> diff;
351 
352  for (unsigned int s = 0; s < n_refinements; ++s)
353  {
354  app.refine_mesh(true);
355 
356  app.setup_system();
357  app.setup_vector(seed);
358  app.setup_vector(prev);
359  app.setup_vector(diff);
360 
361  for (unsigned int i = 0; i < seed.size(); ++i)
362  seed(i) = dealii::Utilities::generate_normal_random_number(0., 1.);
363  for (unsigned int i = 0; i < prev.size(); ++i)
364  prev(i) = dealii::Utilities::generate_normal_random_number(0., 1.);
365 
366  double dt = .73;
367 
368  dealii::AnyData diff_data;
369  diff_data.add(&diff, "diff");
370 
371  dealii::AnyData data;
372  data.add(&dt, "Timestep");
373  data.add(&seed, "Newton iterate");
374 
375  matrix_integrator.extract_data(data);
376  residual_integrator.extract_data(data);
377 
378  app.assemble_matrix(data, matrix_integrator);
379  app.verify_residual(diff_data, data, residual_integrator);
380  app.output_results(s, &diff_data);
381 
382  dealii::deallog << "Difference " << diff.l2_norm() << std::endl;
383  }
384 }
385 
386 #endif
const dealii::ConstraintMatrix & hanging_nodes() const
The object describing the constraints for hanging nodes, not for the boundary.
Definition: amandus.h:592
Definition: integrator.h:137
dealii::SmartPointer< AmandusIntegrator< dim >, AmandusResidual< dim > > integrator
Pointer to the local integrator defining the model.
Definition: amandus.h:539
const dealii::DoFHandler< dim > & dofs() const
The object describing the finite element space.
Definition: amandus.h:578
virtual void operator()(dealii::AnyData &out, const dealii::AnyData &in)
Definition: amandus.cc:40
void verify_residual(unsigned int n_refinements, AmandusApplicationSparse< dim > &app, AmandusIntegrator< dim > &matrix_integrator, AmandusIntegrator< dim > &residual_integrator)
Definition: tests.h:305
dealii::SmartPointer< const AmandusApplicationSparse< dim >, AmandusResidual< dim > > application
Pointer to the application computing the residual.
Definition: amandus.h:537
const dealii::Polynomials::Polynomial< double > * polynomial
Definition: tests.h:294
void verify_theta_residual(unsigned int n_refinements, AmandusApplicationSparse< dim > &app, AmandusIntegrator< dim > &matrix_integrator, AmandusIntegrator< dim > &residual_integrator)
Definition: tests.h:344
virtual void setup_vector(dealii::Vector< double > &v) const
Definition: amandus_sparse.cc:148
virtual void operator()(dealii::AnyData &out, const dealii::AnyData &in)
Definition: tests.h:144
void assemble_matrix(const dealii::AnyData &in, const AmandusIntegrator< dim > &integrator)
Definition: amandus_sparse.cc:245
void refine_mesh(const bool global=false)
Definition: amandus_sparse.cc:598
virtual dealii::Tensor< 1, dim > gradient(const dealii::Point< dim > &p, const unsigned int) const
Definition: tests.h:221
const dealii::Polynomials::Polynomial< double > derivative
Definition: tests.h:295
DeclException1(ExcErrorTooLarge, double,<< "error "<< arg1<< " is too large")
void output_results(unsigned int refinement_cycle, const dealii::AnyData *data=0) const
Definition: amandus_sparse.cc:697
virtual double value(const dealii::Point< dim > &p, const unsigned int) const
Definition: tests.h:210
ExactResidual(const AmandusApplicationSparse< dim > &application, AmandusIntegrator< dim > &integrator, const dealii::Function< dim > &exact_solution, unsigned int n_qpoints)
Definition: tests.h:135
Definition: amandus.h:115
virtual void setup_system()
Definition: amandus_sparse.cc:182
dealii::Vector< double > projection
Definition: tests.h:184
const dealii::Function< dim > * exact_solution
Definition: tests.h:182
const dealii::QGauss< dim > quadrature
Definition: tests.h:183
Definition: tests.h:196
dealii::Tensor< 1, dim > gradient_laplacian(const dealii::Point< dim > &p, const unsigned int) const
Definition: tests.h:253
Definition: tests.h:132
const dealii::Polynomials::Polynomial< double > derivative2
Definition: tests.h:296
void iterative_solve_and_error(dealii::BlockVector< double > &errors, AmandusApplicationSparse< dim > &app, dealii::Algorithms::OperatorBase &solver, const ErrorIntegrator< dim > &error, const dealii::Function< dim > *initial_function=0, unsigned int n_qpoints=0)
Definition: tests.h:78
void error(dealii::BlockVector< double > &out, const dealii::AnyData &in, const AmandusIntegrator< dim > &integrator)
const dealii::Polynomials::Polynomial< double > derivative3
Definition: tests.h:297
virtual double laplacian(const dealii::Point< dim > &p, const unsigned int) const
Definition: tests.h:237
virtual void extract_data(const dealii::AnyData &data)
Extract data independent of the cell.
Definition: integrator.h:468
TensorProductPolynomial(const dealii::Polynomials::Polynomial< double > &pol, unsigned int n_components=1)
Definition: tests.h:199
Definition: amandus.h:513
void verify_residual(dealii::AnyData &out, const dealii::AnyData &in, const AmandusIntegrator< dim > &integrator) const
Definition: amandus_sparse.cc:374
void solve_and_error(dealii::BlockVector< double > &errors, AmandusApplicationSparse< dim > &app, dealii::Algorithms::OperatorBase &solver, dealii::Algorithms::OperatorBase &residual, const AmandusIntegrator< dim > &error)
Definition: tests.h:37
Definition: integrator.h:29