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
mesh_classifier.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
14
16
18#include <deal.II/fe/fe_q.h>
21
32#include <deal.II/lac/vector.h>
34
36
37#include <algorithm>
38
40
41namespace NonMatching
42{
43 namespace internal
44 {
45 namespace MeshClassifierImplementation
46 {
49 "The Triangulation has not been classified. You need to call the "
50 "reclassify()-function before using this function.");
51
54 "The incoming cell does not belong to the triangulation passed to "
55 "the constructor.");
56
57 /*
58 * Return LocationToLevelSet::inside/outside if all values in the vector
59 * are negative/positive.
60 * Return LocationToLevelSet::intersected if the values in the vector
61 * include both negative and positive numbers.
62 * Return LocationToLevelSet::aligned if all values in the vector are
63 * exactly zero.
64 */
65 template <typename VectorType>
67 location_from_dof_signs(const VectorType &local_levelset_values)
68 {
69 const auto [min_element, max_element] =
70 std::minmax_element(local_levelset_values.begin(),
71 local_levelset_values.end());
72
73 // Note that we actually want to compare that the values are exactly
74 // floating point zero here, even if the rule of thumb is that one never
75 // should.
76 if (*min_element == 0.0 && *max_element == 0.0)
78 if (*max_element <= 0)
80 if (0 <= *min_element)
82
84 }
85
86
87
92 template <int dim, typename VectorType>
94 {
95 public:
100 const VectorType &level_set);
101
106 get_fe_collection() const override;
107
112 unsigned int
114 &cell) const override;
115
120 void
122 const typename Triangulation<dim>::active_cell_iterator &cell,
123 const unsigned int face_index,
124 Vector<double> &local_levelset_values) override;
125
126 private:
131
137 };
138
139
140
141 template <int dim, typename VectorType>
143 const DoFHandler<dim> &dof_handler,
144 const VectorType &level_set)
145 : dof_handler(&dof_handler)
146 , level_set(&level_set)
147 {}
148
149
150
151 template <int dim, typename VectorType>
154 {
155 return dof_handler->get_fe_collection();
156 }
157
158
159
160 template <int dim, typename VectorType>
161 void
163 const typename Triangulation<dim>::active_cell_iterator &cell,
164 const unsigned int face_index,
165 Vector<double> &local_levelset_values)
166 {
167 const auto cell_with_dofs = cell->as_dof_handler_iterator(*dof_handler);
168
169 const unsigned int n_dofs_per_face =
170 dof_handler->get_fe().n_dofs_per_face();
171 std::vector<types::global_dof_index> dof_indices(n_dofs_per_face);
172 cell_with_dofs->face(face_index)->get_dof_indices(dof_indices);
173
174 local_levelset_values.reinit(dof_indices.size());
175
176 for (unsigned int i = 0; i < dof_indices.size(); i++)
177 local_levelset_values[i] =
179 dof_indices[i]);
180 }
181
182
183
184 template <int dim, typename VectorType>
185 unsigned int
187 const typename Triangulation<dim>::active_cell_iterator &cell) const
188 {
189 const auto cell_with_dofs = cell->as_dof_handler_iterator(*dof_handler);
190
191 return cell_with_dofs->active_fe_index();
192 }
193
194
199 template <int dim>
201 {
202 public:
208 const FiniteElement<dim> &element);
209
215 get_fe_collection() const override;
216
221 unsigned int
223 &cell) const override;
224
229 void
231 const typename Triangulation<dim>::active_cell_iterator &cell,
232 const unsigned int face_index,
233 Vector<double> &local_levelset_values) override;
234
235 private:
240
246
252 };
253
254
255
256 template <int dim>
258 const Function<dim> &level_set,
259 const FiniteElement<dim> &element)
260 : level_set(&level_set)
261 , fe_collection(element)
262 , fe_face_values(element,
263 Quadrature<dim - 1>(
264 element.get_unit_face_support_points()),
266 {}
267
268
269
270 template <int dim>
271 void
273 const typename Triangulation<dim>::active_cell_iterator &cell,
274 const unsigned int face_index,
275 Vector<double> &local_levelset_values)
276 {
277 AssertDimension(local_levelset_values.size(),
278 fe_face_values.n_quadrature_points);
279
280 fe_face_values.reinit(cell, face_index);
281 const std::vector<Point<dim>> &points =
282 fe_face_values.get_quadrature_points();
283
284 for (unsigned int i = 0; i < points.size(); i++)
285 local_levelset_values[i] = level_set->value(points[i]);
286 }
287
288
289
290 template <int dim>
293 {
294 return fe_collection;
295 }
296
297
298
299 template <int dim>
300 unsigned int
306 } // namespace MeshClassifierImplementation
307 } // namespace internal
308
309
310
311 template <int dim>
312 template <typename VectorType>
314 const VectorType &level_set)
315 : triangulation(&dof_handler.get_triangulation())
316 , level_set_description(
317 std::make_unique<internal::MeshClassifierImplementation::
318 DiscreteLevelSetDescription<dim, VectorType>>(
319 dof_handler,
320 level_set))
321 {
322#ifdef DEAL_II_WITH_LAPACK
323 const hp::FECollection<dim> &fe_collection =
324 dof_handler.get_fe_collection();
325 for (unsigned int i = 0; i < fe_collection.size(); i++)
326 {
327 // The level set function must be scalar.
328 AssertDimension(fe_collection[i].n_components(), 1);
329
330 Assert(fe_collection[i].has_face_support_points(),
332 "The elements in the FECollection of the incoming DoFHandler "
333 "must have face support points."));
334 }
335#else
336 AssertThrow(false, ExcNeedsLAPACK());
337#endif
338 }
339
340
341
342 template <int dim>
344 const Function<dim> &level_set,
345 const FiniteElement<dim> &element)
346 : triangulation(&triangulation)
347 , level_set_description(
348 std::make_unique<internal::MeshClassifierImplementation::
349 AnalyticLevelSetDescription<dim>>(level_set,
350 element))
351 {
352 // The level set function must be scalar.
353 AssertDimension(level_set.n_components, 1);
354 AssertDimension(element.n_components(), 1);
355 }
356
357
358
359 template <int dim>
360 void
362 {
363 initialize();
364 cell_locations.assign(triangulation->n_active_cells(),
366 face_locations.assign(triangulation->n_raw_faces(),
368
369 // Returns weather the incoming LocationToLevelSet is in the incoming set.
370 // This lambda can be factored away once C++20 is enabled, since set then
371 // has a contains function.
372 const auto contains =
373 [](const std::set<LocationToLevelSet> &local_face_locations,
374 const LocationToLevelSet &location) {
375 return local_face_locations.count(location) > 0;
376 };
377
378 // Loop over all cells and determine the location of all non artificial
379 // cells and faces.
380 for (const auto &cell : triangulation->active_cell_iterators())
381 if (!cell->is_artificial())
382 {
383 std::set<LocationToLevelSet> local_face_locations;
384
385 for (unsigned int f = 0; f < GeometryInfo<dim>::faces_per_cell; ++f)
386 {
387 const LocationToLevelSet face_location =
388 determine_face_location_to_levelset(cell, f);
389
390 face_locations[cell->face(f)->index()] = face_location;
391 local_face_locations.insert(face_location);
392 }
393
395
396 const bool all_faces_have_same_location =
397 local_face_locations.size() == 1;
398
399 if (all_faces_have_same_location)
400 {
401 cell_location = *local_face_locations.cbegin();
402 }
403 else if (contains(local_face_locations,
405 {
406 cell_location = LocationToLevelSet::intersected;
407 }
408 else if (contains(local_face_locations, LocationToLevelSet::aligned))
409 {
410 Assert(local_face_locations.size() == 2, ExcNotImplemented());
411
412 if (contains(local_face_locations, LocationToLevelSet::outside))
413 cell_location = LocationToLevelSet::outside;
414 else // contains LocationToLevelSet::inside
415 cell_location = LocationToLevelSet::intersected;
416 }
417 else
418 {
419 // In 2D, a cell can be intersected without any faces being
420 // intersected, if the zero contour cuts the cell diagonally
421 // through the vertices. In this case, two faces are inside and
422 // two are outside.
423 Assert(local_face_locations.size() == 2, ExcNotImplemented());
424 cell_location = LocationToLevelSet::intersected;
425 }
426
427
428 cell_locations[cell->active_cell_index()] = cell_location;
429 }
430 }
431
432
433
434 template <int dim>
437 const typename Triangulation<dim>::active_cell_iterator &cell,
438 const unsigned int face_index)
439 {
440 // The location of the face might already be computed on the neighboring
441 // cell. If this is the case we just return the value.
442 const LocationToLevelSet location =
443 face_locations.at(cell->face(face_index)->index());
444 if (location != LocationToLevelSet::unassigned)
445 return location;
446
447 // Determine the location by changing basis to FE_Bernstein and checking
448 // the signs of the dofs.
449 const unsigned int fe_index = level_set_description->active_fe_index(cell);
450 const unsigned int n_local_dofs =
451 lagrange_to_bernstein_face[fe_index][face_index].m();
452
453 Vector<double> local_levelset_values(n_local_dofs);
454 level_set_description->get_local_level_set_values(cell,
455 face_index,
456 local_levelset_values);
457
458 const FiniteElement<dim> &fe =
459 level_set_description->get_fe_collection()[fe_index];
460
461 const FE_Q_iso_Q1<dim> *fe_q_iso_q1 =
462 dynamic_cast<const FE_Q_iso_Q1<dim> *>(&fe);
463
464 const FE_Poly<dim> *fe_poly = dynamic_cast<const FE_Poly<dim> *>(&fe);
465
466 const bool is_linear = fe_q_iso_q1 != nullptr ||
467 (fe_poly != nullptr && fe_poly->get_degree() == 1);
468
469 // shortcut for linear elements
470 if (is_linear)
471 {
473 local_levelset_values);
474 }
475
476 lagrange_to_bernstein_face[fe_index][face_index].solve(
477 local_levelset_values);
478
480 local_levelset_values);
481 }
482
483
484
485 template <int dim>
488 const typename Triangulation<dim>::cell_iterator &cell) const
489 {
490 Assert(cell_locations.size() == triangulation->n_active_cells(),
492 Assert(&cell->get_triangulation() == triangulation,
494
495 return cell_locations.at(cell->active_cell_index());
496 }
497
498
499
500 template <int dim>
503 const typename Triangulation<dim>::cell_iterator &cell,
504 const unsigned int face_index) const
505 {
507 Assert(face_locations.size() == triangulation->n_raw_faces(),
509 Assert(&cell->get_triangulation() == triangulation,
511
512 return face_locations.at(cell->face(face_index)->index());
513 }
514
515
516
517 template <int dim>
518 void
520 {
521 const hp::FECollection<dim> &fe_collection =
522 level_set_description->get_fe_collection();
523
524 // The level set function must be scalar.
525 AssertDimension(fe_collection.n_components(), 1);
526
527 lagrange_to_bernstein_face.resize(fe_collection.size());
528
529 for (unsigned int i = 0; i < fe_collection.size(); i++)
530 {
531 const FiniteElement<dim> &element = fe_collection[i];
532 const FE_Q_Base<dim> *fe_q =
533 dynamic_cast<const FE_Q_Base<dim> *>(&element);
534 Assert(fe_q != nullptr, ExcNotImplemented());
535
536 const FE_Bernstein<dim> fe_bernstein(fe_q->get_degree());
537
538 const unsigned int dofs_per_face = fe_q->dofs_per_face;
539 for (unsigned int f = 0; f < GeometryInfo<dim>::faces_per_cell; f++)
540 {
541 FullMatrix<double> face_interpolation_matrix(dofs_per_face,
542 dofs_per_face);
543
545 *fe_q, face_interpolation_matrix, f);
546 lagrange_to_bernstein_face[i][f].reinit(dofs_per_face);
547 lagrange_to_bernstein_face[i][f] = face_interpolation_matrix;
548 lagrange_to_bernstein_face[i][f].compute_lu_factorization();
549 }
550 }
551 }
552
553} // namespace NonMatching
554
555#include "non_matching/mesh_classifier.inst"
556
const hp::FECollection< dim, spacedim > & get_fe_collection() const
virtual void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix, const unsigned int face_no=0) const override
unsigned int get_degree() const
const unsigned int dofs_per_face
Definition fe_data.h:420
unsigned int n_components() const
const unsigned int n_components
Definition function.h:162
LocationToLevelSet location_to_level_set(const typename Triangulation< dim >::cell_iterator &cell) const
LocationToLevelSet determine_face_location_to_levelset(const typename Triangulation< dim >::active_cell_iterator &cell, const unsigned int face_index)
MeshClassifier(const DoFHandler< dim > &level_set_dof_handler, const VectorType &level_set)
AnalyticLevelSetDescription(const Function< dim > &level_set, const FiniteElement< dim > &element)
unsigned int active_fe_index(const typename Triangulation< dim >::active_cell_iterator &cell) const override
void get_local_level_set_values(const typename Triangulation< dim >::active_cell_iterator &cell, const unsigned int face_index, Vector< double > &local_levelset_values) override
void get_local_level_set_values(const typename Triangulation< dim >::active_cell_iterator &cell, const unsigned int face_index, Vector< double > &local_levelset_values) override
unsigned int active_fe_index(const typename Triangulation< dim >::active_cell_iterator &cell) const override
DiscreteLevelSetDescription(const DoFHandler< dim > &dof_handler, const VectorType &level_set)
virtual size_type size() const override
virtual void reinit(const size_type N, const bool omit_zeroing_entries=false)
unsigned int size() const
Definition collection.h:314
unsigned int n_components() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
#define DeclExceptionMsg(Exception, defaulttext)
static ::ExceptionBase & ExcNeedsLAPACK()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
@ update_quadrature_points
Transformed quadrature points.
LocationToLevelSet location_from_dof_signs(const VectorType &local_levelset_values)
STL namespace.