Reference documentation for deal.II version 9.1.0-pre
fe_series.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2016 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 
18 #include <deal.II/base/config.h>
19 
20 #include <deal.II/base/numbers.h>
21 
22 #include <deal.II/fe/fe_series.h>
23 
24 #include <cctype>
25 #include <iostream>
26 #ifdef DEAL_II_WITH_GSL
27 # include <gsl/gsl_sf_legendre.h>
28 #endif
29 
30 
31 DEAL_II_NAMESPACE_OPEN
32 
33 namespace FESeries
34 {
35  /*-------------- Fourier -------------------------------*/
36 
37  void set_k_vectors(Table<1, Tensor<1, 1>> &k_vectors, const unsigned int N)
38  {
39  k_vectors.reinit(TableIndices<1>(N));
40  for (unsigned int i = 0; i < N; ++i)
41  k_vectors(i)[0] = 2. * numbers::PI * i;
42  }
43 
44  void set_k_vectors(Table<2, Tensor<1, 2>> &k_vectors, const unsigned int N)
45  {
46  k_vectors.reinit(TableIndices<2>(N, N));
47  for (unsigned int i = 0; i < N; ++i)
48  for (unsigned int j = 0; j < N; ++j)
49  {
50  k_vectors(i, j)[0] = 2. * numbers::PI * i;
51  k_vectors(i, j)[1] = 2. * numbers::PI * j;
52  }
53  }
54 
55  void set_k_vectors(Table<3, Tensor<1, 3>> &k_vectors, const unsigned int N)
56  {
57  k_vectors.reinit(TableIndices<3>(N, N, N));
58  for (unsigned int i = 0; i < N; ++i)
59  for (unsigned int j = 0; j < N; ++j)
60  for (unsigned int k = 0; k < N; ++k)
61  {
62  k_vectors(i, j, k)[0] = 2. * numbers::PI * i;
63  k_vectors(i, j, k)[0] = 2. * numbers::PI * j;
64  k_vectors(i, j, k)[0] = 2. * numbers::PI * k;
65  }
66  }
67 
68 
69  template <int dim>
70  Fourier<dim>::Fourier(const unsigned int N,
71  const hp::FECollection<dim> &fe_collection,
72  const hp::QCollection<dim> & q_collection)
73  : fe_collection(&fe_collection)
74  , q_collection(&q_collection)
75  , fourier_transform_matrices(fe_collection.size())
76  {
77  set_k_vectors(k_vectors, N);
79  }
80 
81  template <int dim>
82  void
84  const Vector<double> & local_dof_values,
85  const unsigned int cell_active_fe_index,
86  Table<dim, std::complex<double>> &fourier_coefficients)
87  {
88  ensure_existence(cell_active_fe_index);
89  const FullMatrix<std::complex<double>> &matrix =
90  fourier_transform_matrices[cell_active_fe_index];
91 
92  std::fill(unrolled_coefficients.begin(),
94  std::complex<double>(0.));
95 
96  Assert(unrolled_coefficients.size() == matrix.m(), ExcInternalError());
97 
98  Assert(local_dof_values.size() == matrix.n(),
99  ExcDimensionMismatch(local_dof_values.size(), matrix.n()));
100 
101  for (unsigned int i = 0; i < unrolled_coefficients.size(); i++)
102  for (unsigned int j = 0; j < local_dof_values.size(); j++)
103  unrolled_coefficients[i] += matrix[i][j] * local_dof_values[j];
104 
105  fourier_coefficients.fill(unrolled_coefficients.begin());
106  }
107 
108  template <int dim>
109  std::complex<double>
110  integrate(const FiniteElement<dim> &fe,
111  const Quadrature<dim> & quadrature,
112  const Tensor<1, dim> & k_vector,
113  const unsigned int j)
114  {
115  std::complex<double> sum = 0;
116  for (unsigned int q = 0; q < quadrature.size(); ++q)
117  {
118  const Point<dim> &x_q = quadrature.point(q);
119  sum += std::exp(std::complex<double>(0, 1) * (k_vector * x_q)) *
120  fe.shape_value(j, x_q) * quadrature.weight(q);
121  }
122  return sum;
123  }
124 
125 
126  template <>
127  void
128  Fourier<2>::ensure_existence(const unsigned int fe)
129  {
130  Assert(fe < fe_collection->size(),
131  ExcIndexRange(fe, 0, fe_collection->size()))
132 
133  if (fourier_transform_matrices[fe].m() == 0)
134  {
136  (*fe_collection)[fe].dofs_per_cell);
137 
138  unsigned int k = 0;
139  for (unsigned int k1 = 0; k1 < k_vectors.size(0); ++k1)
140  for (unsigned int k2 = 0; k2 < k_vectors.size(1); ++k2, k++)
141  for (unsigned int j = 0; j < (*fe_collection)[fe].dofs_per_cell; ++j)
142  fourier_transform_matrices[fe](k, j) = integrate(
143  (*fe_collection)[fe], (*q_collection)[fe], k_vectors(k1, k2), j);
144  }
145  }
146 
147  template <>
148  void
149  Fourier<3>::ensure_existence(const unsigned int fe)
150  {
151  Assert(fe < fe_collection->size(),
152  ExcIndexRange(fe, 0, fe_collection->size()))
153 
154  if (fourier_transform_matrices[fe].m() == 0)
155  {
157  (*fe_collection)[fe].dofs_per_cell);
158 
159  unsigned int k = 0;
160  for (unsigned int k1 = 0; k1 < k_vectors.size(0); ++k1)
161  for (unsigned int k2 = 0; k2 < k_vectors.size(1); ++k2)
162  for (unsigned int k3 = 0; k3 < k_vectors.size(2); ++k3, k++)
163  for (unsigned int j = 0; j < (*fe_collection)[fe].dofs_per_cell;
164  ++j)
165  fourier_transform_matrices[fe](k, j) =
166  integrate((*fe_collection)[fe],
167  (*q_collection)[fe],
168  k_vectors(k1, k2, k3),
169  j);
170  }
171  }
172 
173  template <>
174  void
175  Fourier<1>::ensure_existence(const unsigned int fe)
176  {
177  Assert(fe < fe_collection->size(),
178  ExcIndexRange(fe, 0, fe_collection->size()))
179 
180  if (fourier_transform_matrices[fe].m() == 0)
181  {
183  (*fe_collection)[fe].dofs_per_cell);
184 
185  for (unsigned int k = 0; k < k_vectors.size(0); ++k)
186  for (unsigned int j = 0; j < (*fe_collection)[fe].dofs_per_cell; ++j)
187  fourier_transform_matrices[fe](k, j) = integrate((*fe_collection)[fe],
188  (*q_collection)[fe],
189  k_vectors(k),
190  j);
191  }
192  }
193 
194 
195  /*-------------- Legendre -------------------------------*/
197  int,
198  double,
199  << "x[" << arg1 << "] = " << arg2 << " is not in [0,1]");
200 
201  /* dim dimensional Legendre function with indices @p indices
202  * evaluated at @p x_q in [0,1]^dim.
203  */
204  template <int dim>
205  double
206  Lh(const Point<dim> &x_q, const TableIndices<dim> &indices)
207  {
208 #ifdef DEAL_II_WITH_GSL
209  double res = 1.0;
210  for (unsigned int d = 0; d < dim; d++)
211  {
212  const double x = 2.0 * (x_q[d] - 0.5);
213  Assert((x_q[d] <= 1.0) && (x_q[d] >= 0.), ExcLegendre(d, x_q[d]));
214  const int ind = indices[d];
215  res *= sqrt(2.0) * gsl_sf_legendre_Pl(ind, x);
216  }
217  return res;
218 
219 #else
220 
221  (void)x_q;
222  (void)indices;
223  AssertThrow(false,
224  ExcMessage("deal.II has to be configured with GSL"
225  "in order to use Legendre transformation."));
226  return 0;
227 #endif
228  }
229 
230  /*
231  * Multiplier in Legendre coefficients
232  */
233  template <int dim>
234  double
235  multiplier(const TableIndices<dim> &indices)
236  {
237  double res = 1.0;
238  for (unsigned int d = 0; d < dim; d++)
239  res *= (0.5 + indices[d]);
240 
241  return res;
242  }
243 
244 
245  template <int dim>
246  Legendre<dim>::Legendre(const unsigned int size_in_each_direction,
249  : N(size_in_each_direction)
250  , fe_collection(&fe_collection)
251  , q_collection(&q_collection)
252  , legendre_transform_matrices(fe_collection.size())
253  , unrolled_coefficients(Utilities::fixed_power<dim>(N), 0.)
254  {}
255 
256  template <int dim>
257  void
258  Legendre<dim>::calculate(const ::Vector<double> &local_dof_values,
259  const unsigned int cell_active_fe_index,
260  Table<dim, double> & legendre_coefficients)
261  {
262  ensure_existence(cell_active_fe_index);
263  const FullMatrix<double> &matrix =
264  legendre_transform_matrices[cell_active_fe_index];
265 
266  std::fill(unrolled_coefficients.begin(), unrolled_coefficients.end(), 0.);
267 
268  Assert(unrolled_coefficients.size() == matrix.m(), ExcInternalError());
269 
270  Assert(local_dof_values.size() == matrix.n(),
271  ExcDimensionMismatch(local_dof_values.size(), matrix.n()));
272 
273  for (unsigned int i = 0; i < unrolled_coefficients.size(); i++)
274  for (unsigned int j = 0; j < local_dof_values.size(); j++)
275  unrolled_coefficients[i] += matrix[i][j] * local_dof_values[j];
276 
277  legendre_coefficients.fill(unrolled_coefficients.begin());
278  }
279 
280 
281  template <int dim>
282  double
283  integrate_Legendre(const FiniteElement<dim> &fe,
284  const Quadrature<dim> & quadrature,
285  const TableIndices<dim> & indices,
286  const unsigned int dof)
287  {
288  double sum = 0;
289  for (unsigned int q = 0; q < quadrature.size(); ++q)
290  {
291  const Point<dim> &x_q = quadrature.point(q);
292  sum +=
293  Lh(x_q, indices) * fe.shape_value(dof, x_q) * quadrature.weight(q);
294  }
295  return sum * multiplier(indices);
296  }
297 
298  template <>
299  void
300  Legendre<1>::ensure_existence(const unsigned int fe)
301  {
302  Assert(fe < fe_collection->size(),
304  fe,
305  0,
307  0)
308  {
309  legendre_transform_matrices[fe].reinit(
310  N, (*fe_collection)[fe].dofs_per_cell);
311 
312  for (unsigned int k = 0; k < N; ++k)
313  for (unsigned int j = 0; j < (*fe_collection)[fe].dofs_per_cell; ++j)
314  legendre_transform_matrices[fe](k, j) = integrate_Legendre(
315  (*fe_collection)[fe], (*q_collection)[fe], TableIndices<1>(k), j);
316  }
317  }
318 
319 
320 
321  template <>
322  void
323  Legendre<2>::ensure_existence(const unsigned int fe)
324  {
325  Assert(fe < fe_collection->size(),
326  ExcIndexRange(fe, 0, fe_collection->size()))
327 
328  if (legendre_transform_matrices[fe].m() == 0)
329  {
330  legendre_transform_matrices[fe].reinit(
331  N * N, (*fe_collection)[fe].dofs_per_cell);
332 
333  unsigned int k = 0;
334  for (unsigned int k1 = 0; k1 < N; ++k1)
335  for (unsigned int k2 = 0; k2 < N; ++k2, k++)
336  for (unsigned int j = 0; j < (*fe_collection)[fe].dofs_per_cell; ++j)
337  legendre_transform_matrices[fe](k, j) =
338  integrate_Legendre((*fe_collection)[fe],
339  (*q_collection)[fe],
340  TableIndices<2>(k1, k2),
341  j);
342  }
343  }
344 
345  template <>
346  void
347  Legendre<3>::ensure_existence(const unsigned int fe)
348  {
349  Assert(fe < fe_collection->size(),
350  ExcIndexRange(fe, 0, fe_collection->size()))
351 
352  if (legendre_transform_matrices[fe].m() == 0)
353  {
354  legendre_transform_matrices[fe].reinit(
355  N * N * N, (*fe_collection)[fe].dofs_per_cell);
356 
357  unsigned int k = 0;
358  for (unsigned int k1 = 0; k1 < N; ++k1)
359  for (unsigned int k2 = 0; k2 < N; ++k2)
360  for (unsigned int k3 = 0; k3 < N; ++k3, k++)
361  for (unsigned int j = 0; j < (*fe_collection)[fe].dofs_per_cell;
362  ++j)
363  legendre_transform_matrices[fe](k, j) =
364  integrate_Legendre((*fe_collection)[fe],
365  (*q_collection)[fe],
366  TableIndices<3>(k1, k2, k3),
367  j);
368  }
369  }
370 
371  /*-------------- linear_regression -------------------------------*/
372  std::pair<double, double>
373  linear_regression(const std::vector<double> &x, const std::vector<double> &y)
374  {
375  FullMatrix<double> K(2, 2), invK(2, 2);
376  Vector<double> X(2), B(2);
377 
378  Assert(x.size() == y.size(),
379  ExcMessage("x and y are expected to have the same size"));
380 
381  Assert(x.size() >= 2,
382  ::ExcMessage(
383  "at least two points are required for linear regression fit"));
384 
385  double sum_1 = 0.0, sum_x = 0.0, sum_x2 = 0.0, sum_y = 0.0, sum_xy = 0.0;
386 
387  for (unsigned int i = 0; i < x.size(); i++)
388  {
389  sum_1 += 1.0;
390  sum_x += x[i];
391  sum_x2 += x[i] * x[i];
392  sum_y += y[i];
393  sum_xy += x[i] * y[i];
394  }
395 
396  K(0, 0) = sum_1;
397  K(0, 1) = sum_x;
398  K(1, 0) = sum_x;
399  K(1, 1) = sum_x2;
400 
401  B(0) = sum_y;
402  B(1) = sum_xy;
403 
404  invK.invert(K);
405  invK.vmult(X, B, false);
406 
407  return std::make_pair(X(1), X(0));
408  }
409 
410 
411 } // end of namespace FESeries
412 
413 
414 
415 /*-------------- Explicit Instantiations -------------------------------*/
416 template class FESeries::Fourier<1>;
417 template class FESeries::Fourier<2>;
418 template class FESeries::Fourier<3>;
419 template class FESeries::Legendre<1>;
420 template class FESeries::Legendre<2>;
421 template class FESeries::Legendre<3>;
422 
423 
424 
425 DEAL_II_NAMESPACE_CLOSE
virtual double shape_value(const unsigned int i, const Point< dim > &p) const
Definition: fe.cc:159
static::ExceptionBase & ExcLegendre(int arg1, double arg2)
#define DeclException2(Exception2, type1, type2, outsequence)
Definition: exceptions.h:420
void ensure_existence(const unsigned int fe_index)
Table< dim, Tensor< 1, dim > > k_vectors
Definition: fe_series.h:136
void calculate(const ::Vector< double > &local_dof_values, const unsigned int cell_active_fe_index, Table< dim, std::complex< double >> &fourier_coefficients)
Definition: fe_series.cc:83
size_type size() const
SmartPointer< const hp::FECollection< dim > > fe_collection
Definition: fe_series.h:119
Legendre(const unsigned int size_in_each_direction, const hp::FECollection< dim > &fe_collection, const hp::QCollection< dim > &q_collection)
Definition: fe_series.cc:246
std::pair< double, double > linear_regression(const std::vector< double > &x, const std::vector< double > &y)
Definition: fe_series.cc:373
SmartPointer< const hp::QCollection< dim > > q_collection
Definition: fe_series.h:124
unsigned int size() const
void vmult(Vector< number2 > &w, const Vector< number2 > &v, const bool adding=false) const
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
void calculate(const ::Vector< double > &local_dof_values, const unsigned int cell_active_fe_index, Table< dim, double > &legendre_coefficients)
Definition: fe_series.cc:258
Fourier(const unsigned int size_in_each_direction, const hp::FECollection< dim > &fe_collection, const hp::QCollection< dim > &q_collection)
Definition: fe_series.cc:70
static::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
const Point< dim > & point(const unsigned int i) const
std::vector< std::complex< double > > unrolled_coefficients
Definition: fe_series.h:146
SmartPointer< const hp::QCollection< dim > > q_collection
Definition: fe_series.h:231
static const double PI
Definition: numbers.h:143
unsigned int size() const
static::ExceptionBase & ExcMessage(std::string arg1)
size_type n() const
void invert(const FullMatrix< number2 > &M)
size_type size(const unsigned int i) const
#define Assert(cond, exc)
Definition: exceptions.h:1227
static::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
double weight(const unsigned int i) const
SmartPointer< const hp::FECollection< dim > > fe_collection
Definition: fe_series.h:226
size_type m() const
void ensure_existence(const unsigned int fe_index)
size_type n_elements() const
Definition: cuda.h:32
const unsigned int N
Definition: fe_series.h:221
std::vector< double > unrolled_coefficients
Definition: fe_series.h:248
Definition: mpi.h:55
Definition: table.h:37
std::vector< FullMatrix< std::complex< double > > > fourier_transform_matrices
Definition: fe_series.h:141
void fill(InputIterator entries, const bool C_style_indexing=true)
std::vector< FullMatrix< double > > legendre_transform_matrices
Definition: fe_series.h:243
static::ExceptionBase & ExcInternalError()