deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
fe_series_legendre.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2018 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13
14
17
19
20#include <iostream>
21
22
24
25namespace
26{
27 DeclException2(ExcLegendre,
28 int,
29 double,
30 << "x[" << arg1 << "] = " << arg2 << " is not in [0,1]");
31
32 /*
33 * dim dimensional Legendre function with indices @p indices
34 * evaluated at @p x_q in [0,1]^dim.
35 */
36 template <int dim>
37 double
38 Lh(const Point<dim> &x_q, const TableIndices<dim> &indices)
39 {
40 double res = 1.0;
41 for (unsigned int d = 0; d < dim; ++d)
42 {
43 const double x = 2.0 * (x_q[d] - 0.5);
44 Assert((x_q[d] <= 1.0) && (x_q[d] >= 0.), ExcLegendre(d, x_q[d]));
45 const unsigned int ind = indices[d];
46 res *= std::sqrt(2.0) * std_cxx17::legendre(ind, x);
47 }
48 return res;
49 }
50
51
52
53 /*
54 * Multiplier in Legendre coefficients
55 */
56 template <int dim>
57 double
58 multiplier(const TableIndices<dim> &indices)
59 {
60 double res = 1.0;
61 for (unsigned int d = 0; d < dim; ++d)
62 res *= (0.5 + indices[d]);
63
64 return res;
65 }
66
67
68
69 template <int dim, int spacedim>
70 double
71 integrate(const FiniteElement<dim, spacedim> &fe,
72 const Quadrature<dim> &quadrature,
73 const TableIndices<dim> &indices,
74 const unsigned int dof,
75 const unsigned int component)
76 {
77 double sum = 0;
78 for (unsigned int q = 0; q < quadrature.size(); ++q)
79 {
80 const Point<dim> &x_q = quadrature.point(q);
81 sum += Lh(x_q, indices) *
82 fe.shape_value_component(dof, x_q, component) *
83 quadrature.weight(q);
84 }
85 return sum * multiplier(indices);
86 }
87
88
89
94 template <int spacedim>
95 void
96 ensure_existence(
97 const std::vector<unsigned int> &n_coefficients_per_direction,
98 const hp::FECollection<1, spacedim> &fe_collection,
99 const hp::QCollection<1> &q_collection,
100 const unsigned int fe,
101 const unsigned int component,
102 std::vector<FullMatrix<double>> &legendre_transform_matrices)
103 {
104 AssertIndexRange(fe, fe_collection.size());
105
106 if (legendre_transform_matrices[fe].m() == 0)
107 {
108 legendre_transform_matrices[fe].reinit(
109 n_coefficients_per_direction[fe],
110 fe_collection[fe].n_dofs_per_cell());
111
112 for (unsigned int k = 0; k < n_coefficients_per_direction[fe]; ++k)
113 for (unsigned int j = 0; j < fe_collection[fe].n_dofs_per_cell(); ++j)
114 legendre_transform_matrices[fe](k, j) =
115 integrate(fe_collection[fe],
116 q_collection[fe],
118 j,
119 component);
120 }
121 }
122
123 template <int spacedim>
124 void
125 ensure_existence(
126 const std::vector<unsigned int> &n_coefficients_per_direction,
127 const hp::FECollection<2, spacedim> &fe_collection,
128 const hp::QCollection<2> &q_collection,
129 const unsigned int fe,
130 const unsigned int component,
131 std::vector<FullMatrix<double>> &legendre_transform_matrices)
132 {
133 AssertIndexRange(fe, fe_collection.size());
134
135 if (legendre_transform_matrices[fe].m() == 0)
136 {
137 legendre_transform_matrices[fe].reinit(
138 Utilities::fixed_power<2>(n_coefficients_per_direction[fe]),
139 fe_collection[fe].n_dofs_per_cell());
140
141 unsigned int k = 0;
142 for (unsigned int k1 = 0; k1 < n_coefficients_per_direction[fe]; ++k1)
143 for (unsigned int k2 = 0; k2 < n_coefficients_per_direction[fe];
144 ++k2, k++)
145 for (unsigned int j = 0; j < fe_collection[fe].n_dofs_per_cell();
146 ++j)
147 legendre_transform_matrices[fe](k, j) =
148 integrate(fe_collection[fe],
149 q_collection[fe],
150 TableIndices<2>(k1, k2),
151 j,
152 component);
153 }
154 }
155
156 template <int spacedim>
157 void
158 ensure_existence(
159 const std::vector<unsigned int> &n_coefficients_per_direction,
160 const hp::FECollection<3, spacedim> &fe_collection,
161 const hp::QCollection<3> &q_collection,
162 const unsigned int fe,
163 const unsigned int component,
164 std::vector<FullMatrix<double>> &legendre_transform_matrices)
165 {
166 AssertIndexRange(fe, fe_collection.size());
167
168 if (legendre_transform_matrices[fe].m() == 0)
169 {
170 legendre_transform_matrices[fe].reinit(
171 Utilities::fixed_power<3>(n_coefficients_per_direction[fe]),
172 fe_collection[fe].n_dofs_per_cell());
173
174 unsigned int k = 0;
175 for (unsigned int k1 = 0; k1 < n_coefficients_per_direction[fe]; ++k1)
176 for (unsigned int k2 = 0; k2 < n_coefficients_per_direction[fe]; ++k2)
177 for (unsigned int k3 = 0; k3 < n_coefficients_per_direction[fe];
178 ++k3, k++)
179 for (unsigned int j = 0; j < fe_collection[fe].n_dofs_per_cell();
180 ++j)
181 legendre_transform_matrices[fe](k, j) =
182 integrate(fe_collection[fe],
183 q_collection[fe],
184 TableIndices<3>(k1, k2, k3),
185 j,
186 component);
187 }
188 }
189} // namespace
190
191
192
193namespace FESeries
194{
195 template <int dim, int spacedim>
197 const std::vector<unsigned int> &n_coefficients_per_direction,
198 const hp::FECollection<dim, spacedim> &fe_collection,
199 const hp::QCollection<dim> &q_collection,
200 const unsigned int component_)
201 : n_coefficients_per_direction(n_coefficients_per_direction)
202 , fe_collection(&fe_collection)
203 , q_collection(q_collection)
204 , legendre_transform_matrices(fe_collection.size())
205 , component(component_ != numbers::invalid_unsigned_int ? component_ : 0)
206 {
209 ExcMessage("All parameters are supposed to have the same size."));
210
211 if (fe_collection[0].n_components() > 1)
212 Assert(
213 component_ != numbers::invalid_unsigned_int,
215 "For vector-valued problems, you need to explicitly specify for "
216 "which vector component you will want to do a Legendre decomposition "
217 "by setting the 'component' argument of this constructor."));
218
219 AssertIndexRange(component, fe_collection[0].n_components());
220
221 // reserve sufficient memory
222 const unsigned int max_n_coefficients_per_direction =
223 *std::max_element(n_coefficients_per_direction.cbegin(),
225 unrolled_coefficients.reserve(
226 Utilities::fixed_power<dim>(max_n_coefficients_per_direction));
227 }
228
229
230
231 template <int dim, int spacedim>
232 bool
234 const Legendre<dim, spacedim> &legendre) const
235 {
236 return (
237 (n_coefficients_per_direction == legendre.n_coefficients_per_direction) &&
238 (*fe_collection == *(legendre.fe_collection)) &&
239 (q_collection == legendre.q_collection) &&
240 (legendre_transform_matrices == legendre.legendre_transform_matrices) &&
241 (component == legendre.component));
242 }
243
244
245
246 template <int dim, int spacedim>
247 void
249 {
250 Threads::TaskGroup<> task_group;
251 for (unsigned int fe = 0; fe < fe_collection->size(); ++fe)
252 task_group += Threads::new_task([&, fe]() {
253 ensure_existence(n_coefficients_per_direction,
254 *fe_collection,
255 q_collection,
256 fe,
257 component,
258 legendre_transform_matrices);
259 });
260
261 task_group.join_all();
262 }
263
264
265
266 template <int dim, int spacedim>
267 unsigned int
269 const unsigned int index) const
270 {
271 return n_coefficients_per_direction[index];
272 }
273
274
275
276 template <int dim, int spacedim>
277 template <typename Number>
278 void
280 const ::Vector<Number> &local_dof_values,
281 const unsigned int cell_active_fe_index,
282 Table<dim, CoefficientType> &legendre_coefficients)
283 {
284 for (unsigned int d = 0; d < dim; ++d)
285 AssertDimension(legendre_coefficients.size(d),
286 n_coefficients_per_direction[cell_active_fe_index]);
287
288 ensure_existence(n_coefficients_per_direction,
289 *fe_collection,
290 q_collection,
291 cell_active_fe_index,
292 component,
293 legendre_transform_matrices);
294
295 const FullMatrix<CoefficientType> &matrix =
296 legendre_transform_matrices[cell_active_fe_index];
297
298 unrolled_coefficients.resize(Utilities::fixed_power<dim>(
299 n_coefficients_per_direction[cell_active_fe_index]));
300 std::fill(unrolled_coefficients.begin(),
301 unrolled_coefficients.end(),
302 CoefficientType(0.));
303
304 Assert(unrolled_coefficients.size() == matrix.m(), ExcInternalError());
305
306 Assert(local_dof_values.size() == matrix.n(),
307 ExcDimensionMismatch(local_dof_values.size(), matrix.n()));
308
309 for (unsigned int i = 0; i < unrolled_coefficients.size(); ++i)
310 for (unsigned int j = 0; j < local_dof_values.size(); ++j)
311 unrolled_coefficients[i] += matrix[i][j] * local_dof_values[j];
312
313 legendre_coefficients.fill(unrolled_coefficients.begin());
314 }
315} // namespace FESeries
316
317
318// explicit instantiations
319#include "fe/fe_series_legendre.inst"
320
const std::vector< unsigned int > n_coefficients_per_direction
Definition fe_series.h:349
ObserverPointer< const hp::FECollection< dim, spacedim > > fe_collection
Definition fe_series.h:354
bool operator==(const Legendre< dim, spacedim > &legendre) const
const unsigned int component
Definition fe_series.h:375
const hp::QCollection< dim > q_collection
Definition fe_series.h:359
Legendre(const std::vector< unsigned int > &n_coefficients_per_direction, const hp::FECollection< dim, spacedim > &fe_collection, const hp::QCollection< dim > &q_collection, const unsigned int component=numbers::invalid_unsigned_int)
void precalculate_all_transformation_matrices()
unsigned int get_n_coefficients_per_direction(const unsigned int index) const
std::vector< CoefficientType > unrolled_coefficients
Definition fe_series.h:369
void calculate(const ::Vector< Number > &local_dof_values, const unsigned int cell_active_fe_index, Table< dim, CoefficientType > &legendre_coefficients)
virtual double shape_value_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const
Definition point.h:111
const Point< dim > & point(const unsigned int i) const
double weight(const unsigned int i) const
unsigned int size() const
unsigned int size() const
Definition collection.h:314
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
#define DeclException2(Exception2, type1, type2, outsequence)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
Task< RT > new_task(const std::function< RT()> &function)
std::size_t size
Definition mpi.cc:733
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
T sum(const T &t, const MPI_Comm mpi_communicator)
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
double legendre(unsigned int l, double x)
Definition cmath.h:63
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)