Reduced Lagrange Multipliers
 
Loading...
Searching...
No Matches
reference_cross_section.cc
Go to the documentation of this file.
1// ---------------------------------------------------------------------
2//
3// Copyright (C) 2024 by Luca Heltai
4//
5// This file is part of the reduced_lagrange_multipliers application, based on
6// the deal.II library.
7//
8// The reduced_lagrange_multipliers application is free software; you can use
9// it, redistribute it, and/or modify it under the terms of the Apache-2.0
10// License WITH LLVM-exception as published by the Free Software Foundation;
11// either version 3.0 of the License, or (at your option) any later version. The
12// full text of the license can be found in the file LICENSE.md at the top level
13// of the reduced_lagrange_multipliers distribution.
14//
15// ---------------------------------------------------------------------
16
18
20
22
23#include <deal.II/fe/fe_q.h>
25
28
31
34
37
38#include <string>
39
40template <int dim, int spacedim, int n_components>
43 : par(par)
44 , polynomials(par.inclusion_degree)
45 , quadrature_formula(2 * par.inclusion_degree + 1)
46 , fe(FE_Q<dim, spacedim>(std::max(par.inclusion_degree, 1u)), n_components)
47 , mapping(fe.degree)
49{
50 initialize();
51}
52
53
54template <int dim, int spacedim, int n_components>
55void
57
58{
59 if (par.inclusion_type == "hyper_ball")
60 {
61 if constexpr (dim == 1 && spacedim == 3)
62 {
63 // 1D inclusion in 3D space. A disk.
67 triangulation.set_all_manifold_ids(1);
69 }
70 else if constexpr (dim == spacedim - 1)
72 else
74 }
75 else if (par.inclusion_type == "hyper_cube")
77 else
78 {
79 AssertThrow(false,
80 ExcMessage("Unknown inclusion type. Please check the "
81 "parameter file."));
82 }
83 triangulation.refine_global(par.refinement_level);
84}
85
86
87template <int dim, int spacedim, int n_components>
88void
90{
91 dof_handler.distribute_dofs(fe);
92 DynamicSparsityPattern dsp(dof_handler.n_dofs(), dof_handler.n_dofs());
94 sparsity_pattern.copy_from(dsp);
95 sparsity_pattern.compress();
97 MatrixTools::create_mass_matrix(dof_handler, quadrature_formula, mass_matrix);
98
99 const auto n_global_q_points =
100 triangulation.n_active_cells() * quadrature_formula.size();
102 std::vector<Point<spacedim>> points;
103 std::vector<double> weights;
104 points.reserve(n_global_q_points);
105 weights.reserve(n_global_q_points);
106
108 fe,
113 for (const auto &cell : dof_handler.active_cell_iterators())
114 {
115 fe_values.reinit(cell);
116 points.insert(points.end(),
117 fe_values.get_quadrature_points().begin(),
118 fe_values.get_quadrature_points().end());
119 weights.insert(weights.end(),
120 fe_values.get_JxW_values().begin(),
121 fe_values.get_JxW_values().end());
122 for (const auto &w : fe_values.get_JxW_values())
125 global_quadrature = Quadrature<spacedim>(points, weights);
126}
128
129template <int dim, int spacedim, int n_components>
130void
133 basis_functions.resize(polynomials.n() * n_components,
134 Vector<double>(dof_handler.n_dofs()));
135 for (unsigned int i = 0; i < basis_functions.size(); ++i)
136 {
137 const auto comp_i = i % n_components;
138 const auto poly_i = i / n_components;
140 [&](const Point<spacedim> &p) {
141 return polynomials.compute_value(poly_i, p);
142 },
143 comp_i,
144 n_components);
145 VectorTools::interpolate(dof_handler, function, basis_functions[i]);
147 // Grahm-Schmidt orthogonalization
148 std::vector<bool> is_zero(basis_functions.size(), false);
149 for (unsigned int i = 0; i < basis_functions.size(); ++i)
150 {
151 for (unsigned int j = 0; j < i; ++j)
152 {
153 const auto coeff =
154 mass_matrix.matrix_scalar_product(basis_functions[i],
156 basis_functions[i].sadd(1,
157 -coeff / reference_measure,
158 basis_functions[j]);
160 const auto coeff = mass_matrix.matrix_scalar_product(basis_functions[i],
161 basis_functions[i]);
162
163 // If the basis functions are on a plane, and we are in 3d, they may be
164 // zero
165 if (coeff > 1e-10)
166 basis_functions[i] *= std::sqrt(reference_measure) / std::sqrt(coeff);
167 else
168 is_zero[i] = true;
169 }
170
171 // Remove the zero basis functions
172 for (int i = is_zero.size() - 1; i >= 0; --i)
173 if (is_zero[i] == true)
174 basis_functions.erase(basis_functions.begin() + i);
175
176 // functions
177 if (par.selected_coefficients.empty())
178 {
179 par.selected_coefficients.resize(basis_functions.size());
180 std::iota(par.selected_coefficients.begin(),
181 par.selected_coefficients.end(),
182 0);
183 }
184 else
185 {
186 for (const auto &index : par.selected_coefficients)
187 {
188 AssertThrow(index < basis_functions.size(),
189 ExcIndexRange(index, 0, basis_functions.size()));
190 }
191 }
192
193 selected_basis_functions.resize(par.selected_coefficients.size(),
194 Vector<double>(dof_handler.n_dofs()));
195 // Compute the selected basis functions as the rows of the inverse metric
196 // times the basis functions
197 for (unsigned int i = 0; i < par.selected_coefficients.size(); ++i)
198 {
199 selected_basis_functions[i] =
200 basis_functions[par.selected_coefficients[i]];
201 }
202
203 // Now compute the Matrix of the selected basis functions evaluated on the
204 // quadrature points
205 basis_functions_on_qpoints.reinit(global_quadrature.size(),
206 selected_basis_functions.size() *
207 n_components);
208
209 std::vector<Vector<double>> values(quadrature_formula.size(),
210 Vector<double>(fe.n_components()));
211
212 FEValues<dim, spacedim> fe_values(mapping,
213 fe,
214 quadrature_formula,
216
217 for (const auto &cell : dof_handler.active_cell_iterators())
218 {
219 fe_values.reinit(cell);
220 const unsigned int shift =
221 cell->global_active_cell_index() * quadrature_formula.size();
222
223 for (unsigned int i = 0; i < selected_basis_functions.size(); ++i)
224 {
225 fe_values.get_function_values(selected_basis_functions[i], values);
226 for (unsigned int q = 0; q < quadrature_formula.size(); ++q)
227 {
228 for (unsigned int comp = 0; comp < n_components; ++comp)
229 {
230 basis_functions_on_qpoints(q + shift,
231 i * n_components + comp) =
232 values[q][comp];
233 }
234 }
235 }
236 }
237}
238
239
240template <int dim, int spacedim, int n_components>
241double
247
248
249
250template <int dim, int spacedim, int n_components>
251auto
257
258
259
260template <int dim, int spacedim, int n_components>
261auto
267
268template <int dim, int spacedim, int n_components>
269const double &
271 const unsigned int i,
272 const unsigned int q,
273 const unsigned int comp) const
274{
277 AssertIndexRange(comp, n_components);
278
279 // Check that the matrix is not empty
281 ExcMessage(
282 "The basis functions on quadrature points are empty."));
283 return basis_functions_on_qpoints(q, i * n_components + comp);
284};
285
286
287
288template <int dim, int spacedim, int n_components>
289auto
295
296
297
298template <int dim, int spacedim, int n_components>
299auto
305
306
307
308template <int dim, int spacedim, int n_components>
309unsigned int
314
315template <int dim, int spacedim, int n_components>
318 : ParameterAcceptor("Cross section")
319{
320 add_parameter("Maximum inclusion degree", inclusion_degree);
322 "Selected indices",
324 "This allows one to select a subset of the components of the "
325 "basis functions used for the representation of the data "
326 "(boundary data or forcing data). Notice that these indices are "
327 "w.r.t. to the total number of components of the problem, that "
328 "is, dimension of the space P^{inclusion_degree} number of Fourier coefficients x number of vector "
329 "components. In particular any entry of this list must be in "
330 "the set [0,inclusion_degree*n_components). ");
331 add_parameter("Inclusion type", inclusion_type);
332 add_parameter("Refinement level", refinement_level);
333}
334
335template <int dim, int spacedim, int n_components>
338 const Point<spacedim> &new_origin,
339 const Tensor<1, spacedim> &new_vertical,
340 const double scale) const
341{
342 AssertThrow(new_vertical.norm() > 0,
343 ExcMessage("The new vertical direction must be non-zero."));
344
345 Tensor<2, spacedim> rotation;
346 Tensor<1, spacedim> vertical;
347 vertical[spacedim - 1] = 1;
348 if constexpr (spacedim == 3)
349 {
350 Tensor<1, spacedim> axis = cross_product_3d(vertical, new_vertical);
351 const double axis_norm = axis.norm();
352 if (axis_norm < 1e-10)
353 {
354 // The two vectors are parallel, no rotation needed
355 for (unsigned int i = 0; i < spacedim; ++i)
356 rotation[i][i] = 1;
357 }
358 else
359 {
360 axis /= axis_norm;
361 double angle = Physics::VectorRelations::signed_angle(vertical,
362 new_vertical,
363 axis);
364 rotation =
366 angle);
367 }
368 }
369 else if constexpr (spacedim == 2)
370 {
371 double angle = Physics::VectorRelations::angle(vertical, new_vertical);
373 }
374
375 // Create transformed quadrature by applying the mapping to points and weights
376 std::vector<Point<spacedim>> transformed_points(global_quadrature.size());
377 std::vector<double> transformed_weights(global_quadrature.size());
378
379 const auto &original_points = global_quadrature.get_points();
380 const auto &original_weights = global_quadrature.get_weights();
381
382 // Calculate scale factor for weights
383 const double weight_scale_factor = std::pow(scale, dim);
384
385 for (unsigned int q = 0; q < original_points.size(); ++q)
386 {
387 transformed_points[q] =
388 rotation * (scale * original_points[q]) + new_origin;
389
390 // Scale the weight by scale^dim
391 transformed_weights[q] = original_weights[q] * weight_scale_factor;
392 }
393
394 return Quadrature<spacedim>(transformed_points, transformed_weights);
395}
396
397
398template <int dim, int spacedim, int n_components>
399unsigned int
404
405template <int dim, int spacedim, int n_components>
406void
415
416
417
418// Scalar case
419template class ReferenceCrossSection<1, 2, 1>;
420template class ReferenceCrossSection<1, 3, 1>;
421
422template class ReferenceCrossSection<2, 2, 1>;
423template class ReferenceCrossSection<2, 3, 1>;
424template class ReferenceCrossSection<3, 3, 1>;
425
426// Vector case
427template class ReferenceCrossSection<1, 2, 2>;
428template class ReferenceCrossSection<1, 3, 3>;
429
430template class ReferenceCrossSection<2, 2, 2>;
431template class ReferenceCrossSection<2, 3, 3>;
432template class ReferenceCrossSection<3, 3, 3>;
433
434// Explicit instantiations for ReferenceCrossSectionParameters
435// Scalar case
438
442
443// Vector case
446
ParameterAcceptor(const std::string &section_name="")
void add_parameter(const std::string &entry, ParameterType &parameter, const std::string &documentation="", ParameterHandler &prm_=prm, const Patterns::PatternBase &pattern=*Patterns::Tools::Convert< ParameterType >::to_pattern())
numbers::NumberTraits< Number >::real_type norm() const
Handles the construction and management of a reference inclusion geometry and its basis.
void make_grid()
Builds the mesh for the reference inclusion domain.
Quadrature< spacedim > get_transformed_quadrature(const Point< spacedim > &new_origin, const Tensor< 1, spacedim > &new_vertical, const double scale) const
unsigned int max_n_basis() const
Returns the total number of available basis functions.
PolynomialsP< spacedim > polynomials
Polynomial space used for modal basis generation.
const SparseMatrix< double > & get_mass_matrix() const
Returns the mass matrix corresponding to selected basis functions.
std::vector< Vector< double > > selected_basis_functions
Subset of selected basis functions.
DoFHandler< dim, spacedim > dof_handler
Degree of freedom handler for the inclusion.
void compute_basis()
Computes and stores all basis functions.
SparsityPattern sparsity_pattern
Sparsity pattern used for assembling the mass matrix.
ReferenceCrossSection(const ReferenceCrossSectionParameters< dim, spacedim, n_components > &par)
Constructs the ReferenceCrossSection from parameters.
void initialize()
Initializes the reference inclusion domain.
MappingQ< dim, spacedim > mapping
const std::vector< Vector< double > > & get_basis_functions() const
Returns the list of selected basis functions.
double measure(const double scale=1.0) const
unsigned int n_quadrature_points() const
Triangulation< dim, spacedim > triangulation
Triangulation of the reference inclusion domain.
const Quadrature< spacedim > & get_global_quadrature() const
Returns the global quadrature object in the embedding space.
unsigned int n_selected_basis() const
Returns the number of selected basis functions.
void setup_dofs()
Initializes the degrees of freedom and finite element space.
FESystem< dim, spacedim > fe
Finite element space for the inclusion.
const ReferenceCrossSectionParameters< dim, spacedim, n_components > & par
Reference to parameter configuration.
FullMatrix< double > basis_functions_on_qpoints
The basis functions computed on the quadrature points.
Quadrature< spacedim > global_quadrature
Quadrature rule in the embedding space.
const double & shape_value(const unsigned int i, const unsigned int q, const unsigned int comp) const
QGauss< dim > quadrature_formula
Quadrature formula for integration on the reference domain.
static ::ExceptionBase & ExcIndexRange(size_type arg1, size_type arg2, size_type arg3)
#define AssertIndexRange(index, range)
#define AssertThrow(cond, exc)
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternBase &sparsity_pattern, const AffineConstraints< number > &constraints={}, const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
update_values
update_JxW_values
update_quadrature_points
Expression max(const Expression &a, const Expression &b)
void hyper_ball(Triangulation< dim, spacedim > &tria, const Point< spacedim > &center={}, const double radius=1., const bool attach_spherical_manifold_on_boundary_cells=false)
void hyper_sphere(Triangulation< spacedim - 1, spacedim > &tria, const Point< spacedim > &center=Point< spacedim >(), const double radius=1.)
void hyper_cube(Triangulation< dim, spacedim > &tria, const double left=0., const double right=1., const bool colorize=false)
void flatten_triangulation(const Triangulation< dim, spacedim1 > &in_tria, Triangulation< dim, spacedim2 > &out_tria)
void scale(const double scaling_factor, Triangulation< dim, spacedim > &triangulation)
void shift(const Tensor< 1, spacedim > &shift_vector, Triangulation< dim, spacedim > &triangulation)
Tensor< 2, dim, Number > w(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
Tensor< 2, 3, Number > rotation_matrix_3d(const Tensor< 1, 3, Number > &axis, const Number &angle)
Tensor< 2, 2, Number > rotation_matrix_2d(const Number &angle)
Number signed_angle(const Tensor< 1, spacedim, Number > &a, const Tensor< 1, spacedim, Number > &b, const Tensor< 1, spacedim, Number > &axis)
Number angle(const Tensor< 1, spacedim, Number > &a, const Tensor< 1, spacedim, Number > &b)
void interpolate(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const Function< spacedim, typename VectorType::value_type > &function, VectorType &vec, const ComponentMask &component_mask={}, const unsigned int level=numbers::invalid_unsigned_int)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
Parameter configuration for a ReferenceCrossSection.
ReferenceCrossSectionParameters()
Constructor that registers parameters.
unsigned int refinement_level
Refinement level of the mesh.
std::vector< unsigned int > selected_coefficients
List of selected coefficient indices for reduced modeling.
std::string inclusion_type
Geometric type of inclusion ("hyper_ball", etc.).
unsigned int inclusion_degree
Degree of the polynomial basis for inclusion.