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_values.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) 2021 - 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
15
26#include <deal.II/lac/vector.h>
27
29
31
32namespace NonMatching
33{
39
40
41
42 template <int dim>
43 template <typename Number>
45 const Quadrature<1> &quadrature,
46 const RegionUpdateFlags region_update_flags,
47 const MeshClassifier<dim> &mesh_classifier,
48 const DoFHandler<dim> &dof_handler,
49 const ReadVector<Number> &level_set,
50 const AdditionalData &additional_data)
51 : mapping_collection(&::hp::StaticMappingQ1<dim>::mapping_collection)
52 , fe_collection(&fe_collection)
53 , q_collection_1D(quadrature)
54 , region_update_flags(region_update_flags)
55 , mesh_classifier(&mesh_classifier)
56 , quadrature_generator(q_collection_1D,
57 dof_handler,
58 level_set,
59 additional_data)
60 {
61 // Tensor products of each quadrature in q_collection_1d. Used on the
62 // non-intersected cells.
63 hp::QCollection<dim> q_collection;
64 for (const auto &quadrature : q_collection_1D)
65 q_collection.push_back(Quadrature<dim>(quadrature));
66
67 initialize(q_collection);
68 }
69
70
71
72 template <int dim>
73 template <typename Number>
75 const hp::FECollection<dim> &fe_collection,
76 const hp::QCollection<dim> &q_collection,
77 const hp::QCollection<1> &q_collection_1D,
78 const RegionUpdateFlags region_update_flags,
79 const MeshClassifier<dim> &mesh_classifier,
80 const DoFHandler<dim> &dof_handler,
81 const ReadVector<Number> &level_set,
82 const AdditionalData &additional_data)
83 : mapping_collection(&mapping_collection)
84 , fe_collection(&fe_collection)
85 , q_collection_1D(q_collection_1D)
86 , region_update_flags(region_update_flags)
87 , mesh_classifier(&mesh_classifier)
88 , quadrature_generator(q_collection_1D,
89 dof_handler,
90 level_set,
91 additional_data)
92 {
93 initialize(q_collection);
94 }
95
96
97
98 template <int dim>
99 void
101 {
102 current_cell_location = LocationToLevelSet::unassigned;
103 active_fe_index = numbers::invalid_unsigned_int;
104
105 Assert(fe_collection->size() > 0,
106 ExcMessage("Incoming hp::FECollection can not be empty."));
107 Assert(mapping_collection->size() == fe_collection->size() ||
108 mapping_collection->size() == 1,
109 ExcMessage("Size of hp::MappingCollection must be "
110 "the same as hp::FECollection or 1."));
111 Assert(q_collection.size() == fe_collection->size() ||
112 q_collection.size() == 1,
113 ExcMessage("Size of hp::QCollection<dim> must be the "
114 "same as hp::FECollection or 1."));
115 Assert(q_collection_1D.size() == fe_collection->size() ||
116 q_collection_1D.size() == 1,
117 ExcMessage("Size of hp::QCollection<1> must be the "
118 "same as hp::FECollection or 1."));
119
120 // For each element in fe_collection, create ::FEValues objects to use
121 // on the non-intersected cells.
122 fe_values_inside_full_quadrature.resize(fe_collection->size());
123 fe_values_outside_full_quadrature.resize(fe_collection->size());
124 for (unsigned int fe_index = 0; fe_index < fe_collection->size();
125 ++fe_index)
126 {
127 const unsigned int mapping_index =
128 mapping_collection->size() > 1 ? fe_index : 0;
129 const unsigned int q_index = q_collection.size() > 1 ? fe_index : 0;
130
131 fe_values_inside_full_quadrature[fe_index].emplace(
132 (*mapping_collection)[mapping_index],
133 (*fe_collection)[fe_index],
134 q_collection[q_index],
135 region_update_flags.inside);
136 fe_values_outside_full_quadrature[fe_index].emplace(
137 (*mapping_collection)[mapping_index],
138 (*fe_collection)[fe_index],
139 q_collection[q_index],
140 region_update_flags.outside);
141 }
142 }
143
144
145
146 template <int dim>
147 template <bool level_dof_access>
148 void
151 const unsigned int q_index,
152 const unsigned int mapping_index)
153 {
154 this->reinit_internal(cell,
155 q_index,
156 mapping_index,
157 cell->active_fe_index());
158 }
159
160
161
162 template <int dim>
163 void
165 const unsigned int q_index,
166 const unsigned int mapping_index,
167 const unsigned int fe_index)
168 {
169 this->reinit_internal(cell, q_index, mapping_index, fe_index);
170 }
171
172
173
174 template <int dim>
175 template <typename CellIteratorType>
176 void
177 FEValues<dim>::reinit_internal(const CellIteratorType &cell,
178 const unsigned int q_index_in,
179 const unsigned int mapping_index_in,
180 const unsigned int fe_index_in)
181 {
182 current_cell_location = mesh_classifier->location_to_level_set(cell);
183
184 if (fe_index_in == numbers::invalid_unsigned_int)
185 this->active_fe_index = 0;
186 else
187 this->active_fe_index = fe_index_in;
188
189 unsigned int mapping_index = mapping_index_in;
190 unsigned int q_index = q_index_in;
191 unsigned int q_index_1D = q_index_in;
192
193 if (mapping_index == numbers::invalid_unsigned_int)
194 {
195 if (mapping_collection->size() > 1)
196 mapping_index = active_fe_index;
197 else
198 mapping_index = 0;
199 }
200
201 if (q_index == numbers::invalid_unsigned_int)
202 {
203 if (fe_values_inside_full_quadrature.size() > 1)
204 q_index = active_fe_index;
205 else
206 q_index = 0;
207 }
208
209 if (q_index_1D == numbers::invalid_unsigned_int)
210 {
211 if (q_collection_1D.size() > 1)
212 q_index_1D = active_fe_index;
213 else
214 q_index_1D = 0;
215 }
216
217 // These objects were created with a quadrature based on the previous cell
218 // and are thus no longer valid.
219 fe_values_inside.reset();
220 fe_values_surface.reset();
221 fe_values_outside.reset();
222
223 switch (current_cell_location)
224 {
226 {
227 Assert((active_fe_index == mapping_index) ||
228 ((mapping_collection->size() == 1) &&
229 (mapping_index == 0)),
231 Assert(active_fe_index == q_index, ExcNotImplemented());
232
233 fe_values_inside_full_quadrature.at(q_index)->reinit(cell);
234 break;
235 }
237 {
238 Assert((active_fe_index == mapping_index) ||
239 ((mapping_collection->size() == 1) &&
240 (mapping_index == 0)),
242 Assert(active_fe_index == q_index, ExcNotImplemented());
243
244 fe_values_outside_full_quadrature.at(q_index)->reinit(cell);
245 break;
246 }
248 {
249 quadrature_generator.set_1D_quadrature(q_index_1D);
250 quadrature_generator.generate(cell);
251
252 const Quadrature<dim> &inside_quadrature =
253 quadrature_generator.get_inside_quadrature();
254 const Quadrature<dim> &outside_quadrature =
255 quadrature_generator.get_outside_quadrature();
256 const ImmersedSurfaceQuadrature<dim> &surface_quadrature =
257 quadrature_generator.get_surface_quadrature();
258
259 // Even if a cell is formally intersected the number of created
260 // quadrature points can be 0. Avoid creating an FEValues object
261 // if that is the case.
262 if (inside_quadrature.size() > 0)
263 {
264 fe_values_inside.emplace((*mapping_collection)[mapping_index],
265 (*fe_collection)[active_fe_index],
266 inside_quadrature,
267 region_update_flags.inside);
268
269 fe_values_inside->reinit(cell);
270 }
271
272 if (outside_quadrature.size() > 0)
273 {
274 fe_values_outside.emplace((*mapping_collection)[mapping_index],
275 (*fe_collection)[active_fe_index],
276 outside_quadrature,
277 region_update_flags.outside);
278
279 fe_values_outside->reinit(cell);
280 }
281
282 if (surface_quadrature.size() > 0)
283 {
284 fe_values_surface.emplace((*mapping_collection)[mapping_index],
285 (*fe_collection)[active_fe_index],
286 surface_quadrature,
287 region_update_flags.surface);
288 fe_values_surface->reinit(cell);
289 }
290
291 break;
292 }
293 default:
294 {
296 break;
297 }
298 }
299 }
300
301
302
303 template <int dim>
304 const std::optional<::FEValues<dim>> &
306 {
307 if (current_cell_location == LocationToLevelSet::inside)
308 return fe_values_inside_full_quadrature.at(active_fe_index);
309 else
310 return fe_values_inside;
311 }
312
313
314
315 template <int dim>
316 const std::optional<::FEValues<dim>> &
318 {
319 if (current_cell_location == LocationToLevelSet::outside)
320 return fe_values_outside_full_quadrature.at(active_fe_index);
321 else
322 return fe_values_outside;
323 }
324
325
326
327 template <int dim>
328 const std::optional<FEImmersedSurfaceValues<dim>> &
330 {
331 return fe_values_surface;
332 }
333
334
335
336 template <int dim>
337 template <typename Number>
339 const hp::FECollection<dim> &fe_collection,
340 const Quadrature<1> &quadrature,
341 const RegionUpdateFlags region_update_flags,
342 const MeshClassifier<dim> &mesh_classifier,
343 const DoFHandler<dim> &dof_handler,
344 const ReadVector<Number> &level_set,
345 const AdditionalData &additional_data)
346 : mapping_collection(&::hp::StaticMappingQ1<dim>::mapping_collection)
347 , fe_collection(&fe_collection)
348 , q_collection_1D(quadrature)
349 , region_update_flags(region_update_flags)
350 , mesh_classifier(&mesh_classifier)
351 , face_quadrature_generator(q_collection_1D,
352 dof_handler,
353 level_set,
354 additional_data)
355 {
356 // Tensor products of each quadrature in q_collection_1d. Used on the
357 // non-intersected cells.
358 hp::QCollection<dim - 1> q_collection;
359 for (const auto &quadrature : q_collection_1D)
360 q_collection.push_back(quadrature);
361
362 initialize(q_collection);
363 }
364
365
366
367 template <int dim>
368 template <typename Number>
370 const hp::MappingCollection<dim> &mapping_collection,
371 const hp::FECollection<dim> &fe_collection,
372 const hp::QCollection<dim - 1> &q_collection,
373 const hp::QCollection<1> &q_collection_1D,
374 const RegionUpdateFlags region_update_flags,
375 const MeshClassifier<dim> &mesh_classifier,
376 const DoFHandler<dim> &dof_handler,
377 const ReadVector<Number> &level_set,
378 const AdditionalData &additional_data)
379 : mapping_collection(&mapping_collection)
380 , fe_collection(&fe_collection)
381 , q_collection_1D(q_collection_1D)
382 , region_update_flags(region_update_flags)
383 , mesh_classifier(&mesh_classifier)
384 , face_quadrature_generator(q_collection_1D,
385 dof_handler,
386 level_set,
387 additional_data)
388 {
389 initialize(q_collection);
390 }
391
392
393
394 template <int dim>
395 void
397 const hp::QCollection<dim - 1> &q_collection)
398 {
399 current_face_location = LocationToLevelSet::unassigned;
400
401 Assert(fe_collection->size() > 0,
402 ExcMessage("Incoming hp::FECollection can not be empty."));
403 Assert(
404 mapping_collection->size() == fe_collection->size() ||
405 mapping_collection->size() == 1,
407 "Size of hp::MappingCollection must be the same as hp::FECollection or 1."));
408 Assert(
409 q_collection.size() == fe_collection->size() || q_collection.size() == 1,
411 "Size of hp::QCollection<dim> must be the same as hp::FECollection or 1."));
412 Assert(
413 q_collection_1D.size() == fe_collection->size() ||
414 q_collection_1D.size() == 1,
416 "Size of hp::QCollection<1> must be the same as hp::FECollection or 1."));
417
418 fe_values_inside_full_quadrature.emplace(*mapping_collection,
419 *fe_collection,
420 q_collection,
421 region_update_flags.inside);
422 fe_values_outside_full_quadrature.emplace(*mapping_collection,
423 *fe_collection,
424 q_collection,
425 region_update_flags.outside);
426 }
427
428
429
430 template <int dim>
431 template <typename CellAccessorType>
432 void
435 const unsigned int face_no,
436 const unsigned int q_index_in,
437 const unsigned int active_fe_index_in,
438 const std::function<void(::FEInterfaceValues<dim> &,
439 const unsigned int)> &call_reinit)
440 {
441 current_face_location =
442 mesh_classifier->location_to_level_set(cell, face_no);
443
444 // These objects were created with a quadrature based on the previous cell
445 // and are thus no longer valid.
446 fe_values_inside.reset();
447 fe_values_outside.reset();
448
449 switch (current_face_location)
450 {
452 {
453 call_reinit(*fe_values_inside_full_quadrature, q_index_in);
454 break;
455 }
457 {
458 call_reinit(*fe_values_outside_full_quadrature, q_index_in);
459 break;
460 }
462 {
463 unsigned int q_index = q_index_in;
464
465 if (q_index == numbers::invalid_unsigned_int)
466 {
467 unsigned int active_fe_index = active_fe_index_in;
468
469 if (active_fe_index == numbers::invalid_unsigned_int)
470 {
471 if constexpr (std::is_same_v<
473 CellAccessorType> ||
474 std::is_same_v<
476 CellAccessorType>)
477 active_fe_index = cell->active_fe_index();
478 else
479 active_fe_index = 0;
480 }
481
482 if (q_collection_1D.size() > 1)
483 q_index = active_fe_index;
484 else
485 q_index = 0;
486 }
487
488 AssertIndexRange(q_index, q_collection_1D.size());
489
490 face_quadrature_generator.set_1D_quadrature(q_index);
491 face_quadrature_generator.generate(cell, face_no);
492
493 const Quadrature<dim - 1> &inside_quadrature =
494 face_quadrature_generator.get_inside_quadrature();
495 const Quadrature<dim - 1> &outside_quadrature =
496 face_quadrature_generator.get_outside_quadrature();
497
498 // Even if a cell is formally intersected the number of created
499 // quadrature points can be 0. Avoid creating an FEInterfaceValues
500 // object if that is the case.
501 if (inside_quadrature.size() > 0)
502 {
503 fe_values_inside.emplace(*mapping_collection,
504 *fe_collection,
506 inside_quadrature),
507 region_update_flags.inside);
508
509 call_reinit(*fe_values_inside, /*q_index=*/0);
510 }
511
512 if (outside_quadrature.size() > 0)
513 {
514 fe_values_outside.emplace(*mapping_collection,
515 *fe_collection,
517 outside_quadrature),
518 region_update_flags.outside);
519
520 call_reinit(*fe_values_outside, /*q_index=*/0);
521 }
522 break;
523 }
524 default:
525 {
527 break;
528 }
529 }
530 }
531
532
533
534 template <int dim>
535 const std::optional<::FEInterfaceValues<dim>> &
537 {
538 if (current_face_location == LocationToLevelSet::inside)
539 return fe_values_inside_full_quadrature;
540 else
541 return fe_values_inside;
542 }
543
544
545
546 template <int dim>
547 const std::optional<::FEInterfaceValues<dim>> &
549 {
550 if (current_face_location == LocationToLevelSet::outside)
551 return fe_values_outside_full_quadrature;
552 else
553 return fe_values_outside;
554 }
555
556
557#include "non_matching/fe_values.inst"
558
559} // namespace NonMatching
const std::optional<::FEInterfaceValues< dim > > & get_outside_fe_values() const
Definition fe_values.cc:548
void initialize(const hp::QCollection< dim - 1 > &q_collection)
Definition fe_values.cc:396
const hp::QCollection< 1 > q_collection_1D
Definition fe_values.h:662
typename FaceQuadratureGenerator< dim >::AdditionalData AdditionalData
Definition fe_values.h:490
void do_reinit(const TriaIterator< CellAccessorType > &cell, const unsigned int face_no, const unsigned int q_index, const unsigned int active_fe_index, const std::function< void(::FEInterfaceValues< dim > &, const unsigned int)> &call_reinit)
Definition fe_values.cc:433
const std::optional<::FEInterfaceValues< dim > > & get_inside_fe_values() const
Definition fe_values.cc:536
FEInterfaceValues(const hp::FECollection< dim > &fe_collection, const Quadrature< 1 > &quadrature, const RegionUpdateFlags region_update_flags, const MeshClassifier< dim > &mesh_classifier, const DoFHandler< dim > &dof_handler, const ReadVector< Number > &level_set, const AdditionalData &additional_data=AdditionalData())
Definition fe_values.cc:338
const std::optional<::FEValues< dim > > & get_outside_fe_values() const
Definition fe_values.cc:317
void initialize(const hp::QCollection< dim > &q_collection)
Definition fe_values.cc:100
const std::optional< FEImmersedSurfaceValues< dim > > & get_surface_fe_values() const
Definition fe_values.cc:329
void reinit_internal(const CellIteratorType &cell, const unsigned int q_index, const unsigned int mapping_index, const unsigned int fe_index)
Definition fe_values.cc:177
const hp::QCollection< 1 > q_collection_1D
Definition fe_values.h:334
void reinit(const TriaIterator< DoFCellAccessor< dim, dim, level_dof_access > > &cell, const unsigned int q_index=numbers::invalid_unsigned_int, const unsigned int mapping_index=numbers::invalid_unsigned_int)
Definition fe_values.cc:149
FEValues(const hp::FECollection< dim > &fe_collection, const Quadrature< 1 > &quadrature, const RegionUpdateFlags region_update_flags, const MeshClassifier< dim > &mesh_classifier, const DoFHandler< dim > &dof_handler, const ReadVector< Number > &level_set, const AdditionalData &additional_data=AdditionalData())
Definition fe_values.cc:44
typename QuadratureGenerator< dim >::AdditionalData AdditionalData
Definition fe_values.h:144
const std::optional<::FEValues< dim > > & get_inside_fe_values() const
Definition fe_values.cc:305
unsigned int size() const
unsigned int size() const
Definition collection.h:314
void push_back(const Quadrature< dim_in > &new_quadrature)
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ASSERT_UNREACHABLE()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcMessage(std::string arg1)
@ update_default
No update.
Definition hp.h:115
constexpr unsigned int invalid_unsigned_int
Definition types.h:228