include/meltpooldg/utilities/fe_subcell_face_evaluation.templates.hpp Source File

Developer Documentation: include/meltpooldg/utilities/fe_subcell_face_evaluation.templates.hpp Source File
Developer Documentation
fe_subcell_face_evaluation.templates.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <deal.II/base/exceptions.h>
4#include <deal.II/base/point.h>
5#include <deal.II/base/tensor.h>
6#include <deal.II/base/types.h>
7#include <deal.II/base/vectorization.h>
8
9#include <deal.II/lac/la_parallel_vector.h>
10
11#include <deal.II/matrix_free/evaluation_flags.h>
12#include <deal.II/matrix_free/face_info.h>
13#include <deal.II/matrix_free/matrix_free.h>
14#include <deal.II/matrix_free/operators.h>
15#include <deal.II/matrix_free/shape_info.h>
16
18
19#include <bitset>
20
21namespace MeltPoolDG
22{
23 template <int dim, int n_components, typename number>
25 const dealii::MatrixFree<dim, number> &matrix_free,
26 const bool is_interior_face,
27 const unsigned int dof_no,
28 const unsigned int quad_no)
29 : matrix_free(matrix_free)
30 , is_interior_face(is_interior_face)
31 , fe_cell_evaluator(matrix_free, dof_no, quad_no)
32 , fe_face_evaluator(matrix_free, true, dof_no, quad_no)
33 {
35 }
36
37 template <int dim, int n_components, typename number>
38 void
40 {
41 const dealii::internal::MatrixFreeFunctions::FaceToCellTopology<VectorizedArrayType::size()>
42 &face_info = matrix_free.get_face_info(face_batch_index);
43
44 is_boundary_face = face_batch_index >= matrix_free.n_inner_face_batches();
45
46 // Current implementation currently is only guaranteed to work for standard orientation
47 Assert(dim < 3 or face_info.face_orientation == 0, dealii::ExcNotImplemented());
48
49 // Currently the implementation does not support hanging faces.
50 Assert(face_info.subface_index >= dealii::GeometryInfo<dim>::max_children_per_cell,
51 dealii::ExcNotImplemented("Hanging faces are not supported."));
52
53 Assert(is_interior_face or !is_boundary_face,
54 dealii::ExcMessage("Exterior evaluation is not possible on boundary faces."));
55
56 fe_face_evaluator.reinit(face_batch_index);
57
58 if (is_interior_face)
59 {
60 fe_cell_evaluator.reinit(face_info.cells_interior);
61 face_no = face_info.interior_face_no;
62 }
63 else
64 {
65 fe_cell_evaluator.reinit(face_info.cells_exterior);
66 face_no = face_info.exterior_face_no;
67 }
68
69 this->face_batch_index = face_batch_index;
70
71 determine_subcell_face_sizes();
72 determine_subcell_face_normals();
73
74 determine_subcell_sizes();
75
76 determine_subcell_locations();
77
78 std::ranges::fill(submitted_fluxes, value_type());
79
80 is_reinitialized = true;
81 dof_values_initialized = false;
82 subcell_values_initialized = false;
83 subcell_fluxes_submitted = false;
84 }
85
86 template <int dim, int n_components, typename number>
87 void
89 const dealii::LinearAlgebra::distributed::Vector<number> &src_vector,
90 const std::bitset<n_lanes> &mask)
91 {
92 Assert(is_reinitialized, dealii::ExcNotInitialized());
93 fe_cell_evaluator.read_dof_values(src_vector, 0, mask);
94
95 dof_values_initialized = true;
96 }
97
98 template <int dim, int n_components, typename number>
99 void
101 const dealii::EvaluationFlags::EvaluationFlags evaluation_flags)
102 {
103 Assert(dof_values_initialized,
104 dealii::ExcMessage(
105 "DoF values have not been initialized. Call read_dof_values() before evaluate()."));
106
107 project_dof_values_to_subcell_values(evaluation_flags);
108 }
109
110 template <int dim, int n_components, typename number>
111 void
113 const dealii::LinearAlgebra::distributed::Vector<number> &input_vector,
114 const dealii::EvaluationFlags::EvaluationFlags evaluation_flags,
115 const std::bitset<n_lanes> &mask)
116 {
117 read_dof_values(input_vector, mask);
118 evaluate(evaluation_flags);
119 }
120
121 template <int dim, int n_components, typename number>
122 auto
124 const unsigned int subcell_index) const -> value_type
125 {
126 AssertIndexRange(subcell_index, n_subcells_face);
127 Assert(
128 subcell_values_initialized,
129 dealii::ExcMessage(
130 "FESubcellFaceEvaluation has not been reinitialized. Call reinit() before get_interior_value()."));
131 return layer_values[layer_index(subcell_index)];
132 }
133
134 template <int dim, int n_components, typename number>
135 void
137 const value_type &normal_flux)
138 {
139 AssertIndexRange(subcell_index, n_subcells_face);
140 Assert(is_reinitialized, dealii::ExcNotInitialized());
141
142 submitted_fluxes[subcell_index] = normal_flux;
143
144 subcell_fluxes_submitted = true;
145 }
146
147 template <int dim, int n_components, typename number>
148 void
150 dealii::LinearAlgebra::distributed::Vector<number> &dst_vector,
151 const std::bitset<n_lanes> &mask)
152 {
153 Assert(
154 subcell_fluxes_submitted,
155 dealii::ExcMessage(
156 "Subcell fluxes have not been submitted. Call submit_flux() before integrate_scatter()."));
157 integrate();
158 distribute_local_to_global(dst_vector, mask);
159 }
160
161 template <int dim, int n_components, typename number>
162 std::ranges::iota_view<unsigned int, unsigned int>
164 {
165 return {0U, n_subcells_face};
166 }
167
168 template <int dim, int n_components, typename number>
169 auto
171 const unsigned int subcell_index) const -> VectorizedArrayType
172 {
173 Assert(is_reinitialized, dealii::ExcNotInitialized());
174 AssertIndexRange(subcell_index, n_subcells_face);
175 return subcell_face_sizes[subcell_index];
176 }
177
178 template <int dim, int n_components, typename number>
179 auto
181 const unsigned int subcell_index) const -> dealii::Point<dim, VectorizedArrayType>
182 {
183 Assert(is_reinitialized, dealii::ExcNotInitialized());
184 AssertIndexRange(subcell_index, n_subcells_face);
185 return subcell_locations[subcell_index];
186 }
187
188 template <int dim, int n_components, typename number>
189 unsigned
191 {
192 return n_subcells_face;
193 }
194
195 template <int dim, int n_components, typename number>
196 auto
198 const unsigned int subcell_index) const -> dealii::Tensor<1, dim, VectorizedArrayType>
199 {
200 Assert(is_reinitialized, dealii::ExcNotInitialized());
201 AssertIndexRange(subcell_index, n_subcells_face);
202 return subcell_face_normals[subcell_index];
203 }
204
205 template <int dim, int n_components, typename number>
206 bool
208 {
209 Assert(is_reinitialized, dealii::ExcNotInitialized());
210 return is_boundary_face;
211 }
212
213 template <int dim, int n_components, typename number>
214 dealii::types::boundary_id
216 {
217 Assert(is_reinitialized, dealii::ExcNotInitialized());
218 Assert(
219 is_boundary_face,
220 dealii::ExcMessage(
221 "The current face is not a boundary face. Call boundary_id() only for boundary faces."));
222 return matrix_free.get_boundary_id(face_batch_index);
223 }
224
225 template <int dim, int n_components, typename number>
226 auto
228 const unsigned int subcell_index) const -> VectorizedArrayType
229 {
230 Assert(is_reinitialized, dealii::ExcNotInitialized());
231 AssertIndexRange(subcell_index, n_subcells_face);
232 return subcell_sizes[subcell_index];
233 }
234
235 template <int dim, int n_components, typename number>
236 void
238 {
239 for (const unsigned int q : subcell_face_indices())
240 {
241 subcell_face_sizes[q] = fe_face_evaluator.JxW(q);
242 }
243 }
244
245 template <int dim, int n_components, typename number>
246 void
248 {
249 for (const unsigned int q : subcell_face_indices())
250 {
251 subcell_face_normals[q] = fe_face_evaluator.normal_vector(q);
252 }
253 }
254
255 template <int dim, int n_components, typename number>
256 void
258 {
259 for (const unsigned int q : subcell_face_indices())
260 {
261 subcell_sizes[q] = fe_cell_evaluator.JxW(
262 face_to_cell_quadrature_index(face_no, q, fe_cell_evaluator.get_shape_info()));
263 }
264 }
265 template <int dim, int n_components, typename number>
266 void
268 {
269 // To apply the subcell fluxes, we consider the values of all q_points in the interior cell as
270 // zero, and we set the values of the q_points on the face to the submitted fluxes multiplied
271 // by the corresponding subcell face size and divided by the subcell size. We then transform
272 // those values to cells DoF values and finally add the values to the global vector.
273 // This way, we only apply the fluxes on the face and do not affect the values of the other
274 // q_points in the interior cell.
275 dealii::MatrixFreeOperators::CellwiseInverseMassMatrix<dim, -1, n_components, number> inverse(
276 fe_cell_evaluator);
277
278 std::fill(integrated_subcell_values_buffer.begin(),
279 integrated_subcell_values_buffer.end(),
281
282 for (unsigned int subcell : subcell_face_indices())
283 {
284 const unsigned int cell_q_index =
285 face_to_cell_quadrature_index(face_no, subcell, fe_cell_evaluator.get_shape_info());
286 const VectorizedArrayType scaling_factor =
287 subcell_face_sizes[subcell] / subcell_sizes[subcell];
288 if constexpr (n_components == 1)
289 integrated_subcell_values_buffer[cell_q_index] =
290 submitted_fluxes[subcell] * scaling_factor;
291 else
292 for (unsigned int c = 0; c < n_components; ++c)
293 integrated_subcell_values_buffer[c * fe_cell_evaluator.n_q_points + cell_q_index] =
294 submitted_fluxes[subcell][c] * scaling_factor;
295 }
296 inverse.transform_from_q_points_to_basis(n_components,
297 integrated_subcell_values_buffer.data(),
298 fe_cell_evaluator.begin_dof_values());
299 }
300
301 template <int dim, int n_components, typename number>
302 void
304 dealii::LinearAlgebra::distributed::Vector<number> &dst_vector,
305 const std::bitset<n_lanes> &mask)
306 {
307 fe_cell_evaluator.distribute_local_to_global(dst_vector, 0, mask);
308 }
309
310 template <int dim, int n_components, typename number>
311 void
313 {
314 n_subcells_1d = fe_cell_evaluator.get_shape_info().data[0].n_q_points_1d;
315 n_subcells_face = fe_cell_evaluator.get_shape_info().n_q_points_face;
316
317 const unsigned int padded_size = dealii::Utilities::fixed_power<dim - 1>(n_subcells_1d + 2);
318 layer_values.resize(padded_size);
319
320 submitted_fluxes.resize(n_subcells_face);
321 subcell_face_normals.resize(n_subcells_face);
322
323 subcell_face_sizes.resize(n_subcells_face);
324 subcell_sizes.resize(n_subcells_face);
325
326 subcell_locations.resize(n_subcells_face);
327 integrated_subcell_values_buffer.resize(n_components * fe_cell_evaluator.n_q_points);
328 }
329
330 template <int dim, int n_components, typename number>
331 void
333 const dealii::EvaluationFlags::EvaluationFlags evaluation_flags)
334 {
335 fe_cell_evaluator.evaluate(evaluation_flags);
336 if (evaluation_flags & dealii::EvaluationFlags::values)
337 {
338 for (const unsigned int subcell : subcell_face_indices())
339 {
340 const unsigned int cell_q_index =
341 face_to_cell_quadrature_index(face_no, subcell, fe_cell_evaluator.get_shape_info());
342 layer_values[layer_index(subcell)] = fe_cell_evaluator.get_value(cell_q_index);
343 }
344
345 subcell_values_initialized = true;
346 }
347
348 if (evaluation_flags & dealii::EvaluationFlags::gradients)
349 AssertThrow(false, dealii::ExcNotImplemented());
350 }
351
352 template <int dim, int n_components, typename number>
353 void
355 {
356 for (const unsigned int subcell : subcell_face_indices())
357 {
358 const unsigned int cell_q_index =
359 face_to_cell_quadrature_index(face_no, subcell, fe_cell_evaluator.get_shape_info());
360 subcell_locations[subcell] = fe_cell_evaluator.quadrature_point(cell_q_index);
361 }
362 }
363
364 template <int dim, int n_components, typename number>
365 unsigned int
367 const unsigned int subcell_index) const
368 {
369 AssertIndexRange(subcell_index, n_subcells_face);
370
371 const unsigned int n_padded_1d = n_subcells_1d + 2;
372
373 unsigned int remaining_index = subcell_index;
374 unsigned int index = 0;
375 unsigned int stride = 1;
376 for (unsigned int d = 0; d < dim - 1; ++d)
377 {
378 const unsigned int tangential_index = remaining_index % n_subcells_1d;
379 remaining_index /= n_subcells_1d;
380
381 index += (tangential_index + 1) * stride;
382 stride *= n_padded_1d;
383 }
384 return index;
385 }
386
387 template <int dim, int n_components, typename number>
388 unsigned int
390 const unsigned int face_no,
391 const unsigned int q_face,
392 const dealii::internal::MatrixFreeFunctions::ShapeInfo<number> &shape_info) const
393 {
394 AssertIndexRange(face_no, dealii::GeometryInfo<dim>::faces_per_cell);
395 AssertIndexRange(q_face, fe_face_evaluator.n_q_points);
396
397 if constexpr (dim == 1)
398 {
399 // Shortcut for 1D: the face quadrature index is either the first or last quadrature point
400 // of the cell, depending on the face number.
401 return face_no == 0 ? 0 : shape_info.n_q_points - 1;
402 }
403 else
404 {
405 const unsigned int direction = face_no / 2;
406 const unsigned int n = shape_info.data[0].n_q_points_1d;
407
408 unsigned int normal_stride = 1;
409 for (unsigned int d = 0; d < direction; ++d)
410 {
411 normal_stride *= n;
412 }
413
414 const unsigned int offset = (face_no % 2) * (n - 1) * normal_stride;
415
416 // deal.II uses the (z, x) system on faces 2 and 3 in 3D (i.e. z is varying fastest)
417 if (dim == 3 and direction == 1)
418 return offset + (q_face % n) * n * n + q_face / n;
419
420 const unsigned int tangential_stride = direction < dim - 1 ? n : 1;
421 return offset + q_face * tangential_stride;
422 }
423 }
424} // namespace MeltPoolDG
std::ranges::iota_view< unsigned int, unsigned int > subcell_face_indices() const
Definition fe_subcell_face_evaluation.templates.hpp:163
dealii::VectorizedArray< number > VectorizedArrayType
Definition fe_subcell_face_evaluation.hpp:120
void determine_subcell_locations()
Definition fe_subcell_face_evaluation.templates.hpp:354
VectorizedArrayType subcell_size(const unsigned int subcell_index) const
Definition fe_subcell_face_evaluation.templates.hpp:227
void reinit(const unsigned int face_batch_index)
Definition fe_subcell_face_evaluation.templates.hpp:39
dealii::Tensor< 1, dim, VectorizedArrayType > normal_vector(const unsigned int subcell_index) const
Definition fe_subcell_face_evaluation.templates.hpp:197
void determine_subcell_sizes()
Definition fe_subcell_face_evaluation.templates.hpp:257
void setup_internal_data_structures()
Definition fe_subcell_face_evaluation.templates.hpp:312
void project_dof_values_to_subcell_values(const dealii::EvaluationFlags::EvaluationFlags evaluation_flags)
Definition fe_subcell_face_evaluation.templates.hpp:332
VectorizedArrayType subcell_face_size(const unsigned int subcell_index) const
Definition fe_subcell_face_evaluation.templates.hpp:170
void gather_evaluate(const dealii::LinearAlgebra::distributed::Vector< number > &input_vector, const dealii::EvaluationFlags::EvaluationFlags evaluation_flags, const std::bitset< n_lanes > &mask=std::bitset< n_lanes >().flip())
Definition fe_subcell_face_evaluation.templates.hpp:112
void read_dof_values(const dealii::LinearAlgebra::distributed::Vector< number > &src_vector, const std::bitset< n_lanes > &mask=std::bitset< n_lanes >().flip())
Definition fe_subcell_face_evaluation.templates.hpp:88
value_type get_value(const unsigned int subcell_index) const
Definition fe_subcell_face_evaluation.templates.hpp:123
bool at_boundary() const
Definition fe_subcell_face_evaluation.templates.hpp:207
void distribute_local_to_global(dealii::LinearAlgebra::distributed::Vector< number > &dst_vector, const std::bitset< n_lanes > &mask=std::bitset< n_lanes >().flip())
Definition fe_subcell_face_evaluation.templates.hpp:303
void submit_flux(const unsigned int subcell_index, const value_type &normal_flux)
Definition fe_subcell_face_evaluation.templates.hpp:136
FESubcellFaceEvaluation(const dealii::MatrixFree< dim, number > &matrix_free, const bool is_interior_face, const unsigned int dof_no, const unsigned int quad_no)
Definition fe_subcell_face_evaluation.templates.hpp:24
void determine_subcell_face_normals()
Definition fe_subcell_face_evaluation.templates.hpp:247
void determine_subcell_face_sizes()
Definition fe_subcell_face_evaluation.templates.hpp:237
dealii::types::boundary_id boundary_id() const
Definition fe_subcell_face_evaluation.templates.hpp:215
dealii::Point< dim, VectorizedArrayType > subcell_location(const unsigned int subcell_index) const
Definition fe_subcell_face_evaluation.templates.hpp:180
unsigned int n_subcell_faces() const
Definition fe_subcell_face_evaluation.templates.hpp:190
unsigned int layer_index(const unsigned int subcell_index) const
Definition fe_subcell_face_evaluation.templates.hpp:366
void integrate_scatter(dealii::LinearAlgebra::distributed::Vector< number > &dst_vector, const std::bitset< n_lanes > &mask=std::bitset< n_lanes >().flip())
Definition fe_subcell_face_evaluation.templates.hpp:149
unsigned int face_to_cell_quadrature_index(const unsigned int face_no, const unsigned int q_face, const dealii::internal::MatrixFreeFunctions::ShapeInfo< number > &shape_info) const
Definition fe_subcell_face_evaluation.templates.hpp:389
void evaluate(const dealii::EvaluationFlags::EvaluationFlags evaluation_flags)
Definition fe_subcell_face_evaluation.templates.hpp:100
void integrate()
Definition fe_subcell_face_evaluation.templates.hpp:267
dealii::FEFaceEvaluation< dim, -1, 0, n_components, number, VectorizedArrayType >::value_type value_type
The type of the values on the subcells.
Definition fe_subcell_face_evaluation.hpp:127
Interface for a general preconditioner.
Definition boundary_condition_functions.hpp:17