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_loop.h
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) 2017 - 2023 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#ifndef dealii_mesh_worker_mesh_loop_h
15#define dealii_mesh_worker_mesh_loop_h
16
17#include <deal.II/base/config.h>
18
20#include <deal.II/base/types.h>
22
24#include <deal.II/grid/tria.h>
25
31
32#include <functional>
33#include <type_traits>
34
36
37// Forward declaration
38#ifndef DOXYGEN
39template <typename>
41#endif
42
43namespace MeshWorker
44{
45 namespace internal
46 {
51 template <typename CellIteratorType>
53 {
57 using type = CellIteratorType;
58 };
59
67 template <typename CellIteratorType>
69 {
73 // Since we can have filtered iterators and the like as template
74 // arguments, we recursivelyremove the template layers to retrieve the
75 // underlying iterator type.
77 };
78
87 template <typename CellIteratorType>
88 struct CellIteratorBaseType<FilteredIterator<CellIteratorType>>
89 {
93 // Since we can have nested filtered iterators, we recursively
94 // remove the template layers to retrieve the underlying iterator type.
96 };
97 } // namespace internal
98
99#ifdef DOXYGEN
104 using CellWorkerFunctionType = std::function<
105 void(const CellIteratorBaseType &, ScratchData &, CopyData &)>;
106
111 using CopierFunctionType = std::function<void(const CopyData &)>;
112
118 std::function<void(const CellIteratorBaseType &,
119 const unsigned int,
120 ScratchData &,
121 CopyData &)>;
122
128 std::function<void(const CellIteratorBaseType &,
129 const unsigned int,
130 const unsigned int,
131 const CellIteratorBaseType &,
132 const unsigned int,
133 const unsigned int,
134 ScratchData &,
135 CopyData &)>;
136#endif
137
273 template <typename CellIteratorType,
274 class ScratchData,
275 class CopyData,
276 typename CellIteratorBaseType =
278 void
280#ifdef DOXYGEN
281 const CellIteratorType &begin,
282 const CellIteratorType &end,
283
284 const CellWorkerFunctionType &cell_worker,
285 const CopierType &copier,
286
287 const ScratchData &sample_scratch_data,
288 const CopyData &sample_copy_data,
289
290 const AssembleFlags flags = assemble_own_cells,
291
292 const BoundaryWorkerFunctionType &boundary_worker =
294
295 const FaceWorkerFunctionType &face_worker = FaceWorkerFunctionType(),
296 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
297 const unsigned int chunk_size = 8
298#else
299 const CellIteratorType &begin,
301
302 const std_cxx20::type_identity_t<std::function<
303 void(const CellIteratorBaseType &, ScratchData &, CopyData &)>>
304 &cell_worker,
305 const std_cxx20::type_identity_t<std::function<void(const CopyData &)>>
306 &copier,
307
308 const ScratchData &sample_scratch_data,
309 const CopyData &sample_copy_data,
310
311 const AssembleFlags flags = assemble_own_cells,
312
314 std::function<void(const CellIteratorBaseType &,
315 const unsigned int,
316 ScratchData &,
317 CopyData &)>> &boundary_worker =
318 std::function<void(const CellIteratorBaseType &,
319 const unsigned int,
320 ScratchData &,
321 CopyData &)>(),
322
324 std::function<void(const CellIteratorBaseType &,
325 const unsigned int,
326 const unsigned int,
327 const CellIteratorBaseType &,
328 const unsigned int,
329 const unsigned int,
330 ScratchData &,
331 CopyData &)>> &face_worker =
332 std::function<void(const CellIteratorBaseType &,
333 const unsigned int,
334 const unsigned int,
335 const CellIteratorBaseType &,
336 const unsigned int,
337 const unsigned int,
338 ScratchData &,
339 CopyData &)>(),
340
341 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
342 const unsigned int chunk_size = 8
343#endif
344 )
345 {
346 Assert(
347 (!cell_worker) == !(flags & work_on_cells),
349 "If you provide a cell worker function, you also need to request "
350 "that work should be done on cells by setting the 'work_on_cells' flag. "
351 "Conversely, if you don't provide a cell worker function, you "
352 "cannot set the 'work_on_cells' flag. One of these two "
353 "conditions is not satisfied."));
354
360 "If you provide a face worker function, you also need to request "
361 "that work should be done on interior faces by setting either the "
362 "'assemble_own_interior_faces_once' flag or the "
363 "'assemble_own_interior_faces_both' flag. "
364 "Conversely, if you don't provide a face worker function, you "
365 "cannot set either of these two flags. One of these two "
366 "conditions is not satisfied."));
367
371 "You can only 'specify assemble_ghost_faces_once' "
372 "OR 'assemble_ghost_faces_both', but not both of these flags."));
373
374 Assert(
375 !(flags & cells_after_faces) ||
378 "The option 'cells_after_faces' only makes sense if you assemble on cells."));
379
380 Assert(
381 (!face_worker) == !(flags & work_on_faces),
383 "If you provide a face worker function, you also need to request "
384 "that work should be done on faces by setting the 'work_on_faces' flag. "
385 "Conversely, if you don't provide a face worker function, you "
386 "cannot set the 'work_on_faces' flag. One of these two "
387 "conditions is not satisfied."));
388
389 Assert(
390 (!boundary_worker) == !(flags & assemble_boundary_faces),
392 "If you provide a boundary face worker function, you also need to request "
393 "that work should be done on boundary faces by setting the 'assemble_boundary_faces' flag. "
394 "Conversely, if you don't provide a boundary face worker function, you "
395 "cannot set the 'assemble_boundary_faces' flag. One of these two "
396 "conditions is not satisfied."));
397
398 auto cell_action = [&](const CellIteratorBaseType &cell,
399 ScratchData &scratch,
400 CopyData &copy) {
401 // First reset the CopyData class to the empty copy_data given by the
402 // user.
403 copy = sample_copy_data;
404
405 // Store the dimension in which we are working for later use
406 const auto dim = cell->get_triangulation().dimension;
407
408 const bool ignore_subdomain =
409 (cell->get_triangulation().locally_owned_subdomain() ==
411
412 types::subdomain_id current_subdomain_id =
413 (cell->is_level_cell() ? cell->level_subdomain_id() :
414 cell->subdomain_id());
415
416 const bool own_cell =
417 ignore_subdomain ||
418 (current_subdomain_id ==
419 cell->get_triangulation().locally_owned_subdomain());
420
421 if ((!ignore_subdomain) &&
422 (current_subdomain_id == numbers::artificial_subdomain_id))
423 return;
424
425 if (!(flags & (cells_after_faces)) &&
426 (((flags & (assemble_own_cells)) && own_cell) ||
427 ((flags & assemble_ghost_cells) && !own_cell)))
428 cell_worker(cell, scratch, copy);
429
430 if (flags & (work_on_faces | work_on_boundary))
431 for (const unsigned int face_no : cell->face_indices())
432 {
433 if (cell->at_boundary(face_no) &&
434 !cell->has_periodic_neighbor(face_no))
435 {
436 // only integrate boundary faces of own cells
437 if ((flags & assemble_boundary_faces) && own_cell)
438 boundary_worker(cell, face_no, scratch, copy);
439 }
440 else
441 {
442 // interior face, potentially assemble
444 neighbor = cell->neighbor_or_periodic_neighbor(face_no);
445
446 types::subdomain_id neighbor_subdomain_id =
448 if (neighbor->is_level_cell())
449 neighbor_subdomain_id = neighbor->level_subdomain_id();
450 // subdomain id is only valid for active cells
451 else if (neighbor->is_active())
452 neighbor_subdomain_id = neighbor->subdomain_id();
453
454 const bool own_neighbor =
455 ignore_subdomain ||
456 (neighbor_subdomain_id ==
457 cell->get_triangulation().locally_owned_subdomain());
458
459 // skip all faces between two ghost cells
460 if (!own_cell && !own_neighbor)
461 continue;
462
463 // skip if the user doesn't want faces between own cells
464 if (own_cell && own_neighbor &&
467 continue;
468
469 // skip face to ghost
470 if (own_cell != own_neighbor &&
471 !(flags &
473 continue;
474
475 // Deal with refinement edges from the refined side. Assuming
476 // one-irregular meshes, this situation should only occur if
477 // both cells are active.
478 const bool periodic_neighbor =
479 cell->has_periodic_neighbor(face_no);
480
481 if (dim > 1 && ((!periodic_neighbor &&
482 cell->neighbor_is_coarser(face_no) &&
483 neighbor->is_active()) ||
484 (periodic_neighbor &&
485 cell->periodic_neighbor_is_coarser(face_no) &&
486 neighbor->is_active())))
487 {
488 Assert(cell->is_active(), ExcInternalError());
489
490 // skip if only one processor needs to assemble the face
491 // to a ghost cell and the fine cell is not ours.
492 if (!own_cell && (flags & assemble_ghost_faces_once))
493 continue;
494
495 const std::pair<unsigned int, unsigned int>
496 neighbor_face_no =
497 periodic_neighbor ?
498 cell->periodic_neighbor_of_coarser_periodic_neighbor(
499 face_no) :
500 cell->neighbor_of_coarser_neighbor(face_no);
501
502 face_worker(cell,
503 face_no,
505 neighbor,
506 neighbor_face_no.first,
507 neighbor_face_no.second,
508 scratch,
509 copy);
510
512 {
513 // If own faces are to be assembled from both sides,
514 // call the faceworker again with swapped arguments.
515 // This is because we won't be looking at an adaptively
516 // refined edge coming from the other side.
517 face_worker(neighbor,
518 neighbor_face_no.first,
519 neighbor_face_no.second,
520 cell,
521 face_no,
523 scratch,
524 copy);
525 }
526 }
527 else if (dim == 1 && cell->level() > neighbor->level())
528 {
529 // In one dimension, there is no other check to do
530 const unsigned int neighbor_face_no =
531 periodic_neighbor ?
532 cell->periodic_neighbor_face_no(face_no) :
533 cell->neighbor_face_no(face_no);
534 Assert(periodic_neighbor ||
535 neighbor->face(neighbor_face_no) ==
536 cell->face(face_no),
538
539 face_worker(cell,
540 face_no,
542 neighbor,
543 neighbor_face_no,
545 scratch,
546 copy);
547
549 {
550 // If own faces are to be assembled from both sides,
551 // call the faceworker again with swapped arguments.
552 face_worker(neighbor,
553 neighbor_face_no,
555 cell,
556 face_no,
558 scratch,
559 copy);
560 }
561 }
562 else
563 {
564 // If iterator is active and neighbor is refined, skip
565 // internal face.
567 neighbor->has_children())
568 continue;
569
570 // Now neighbor is on the same refinement level.
571 // Double check.
572 Assert((!periodic_neighbor &&
573 !cell->neighbor_is_coarser(face_no)) ||
574 (periodic_neighbor &&
575 !cell->periodic_neighbor_is_coarser(face_no)),
577
578 // If we own both cells only do faces from one side (unless
579 // AssembleFlags says otherwise). Here, we rely on cell
580 // comparison that will look at cell->index().
581 if (own_cell && own_neighbor &&
583 (neighbor < cell))
584 continue;
585
586 // We only look at faces to ghost on the same level once
587 // (only where own_cell=true and own_neighbor=false)
588 if (!own_cell)
589 continue;
590
591 // now only one processor assembles faces_to_ghost. We let
592 // the processor with the smaller (level-)subdomain id
593 // assemble the face.
594 if (own_cell && !own_neighbor &&
595 (flags & assemble_ghost_faces_once) &&
596 (neighbor_subdomain_id < current_subdomain_id))
597 continue;
598
599 const unsigned int neighbor_face_no =
600 periodic_neighbor ?
601 cell->periodic_neighbor_face_no(face_no) :
602 cell->neighbor_face_no(face_no);
603 Assert(periodic_neighbor ||
604 neighbor->face(neighbor_face_no) ==
605 cell->face(face_no),
607
608 face_worker(cell,
609 face_no,
611 neighbor,
612 neighbor_face_no,
614 scratch,
615 copy);
616 }
617 }
618 } // faces
619
620 // Execute the cell_worker if faces are handled before cells
621 if ((flags & cells_after_faces) &&
622 (((flags & assemble_own_cells) && own_cell) ||
623 ((flags & assemble_ghost_cells) && !own_cell)))
624 cell_worker(cell, scratch, copy);
625 };
626
627 // Submit to workstream
629 end,
631 copier,
632 sample_scratch_data,
633 sample_copy_data,
634 queue_length,
635 chunk_size);
636 }
637
707 template <typename CellIteratorType,
708 class ScratchData,
709 class CopyData,
710 typename CellIteratorBaseType =
712 void
714 IteratorRange<CellIteratorType> iterator_range,
715 const std_cxx20::type_identity_t<std::function<
716 void(const CellIteratorBaseType &, ScratchData &, CopyData &)>>
717 &cell_worker,
718 const std_cxx20::type_identity_t<std::function<void(const CopyData &)>>
719 &copier,
720
721 const ScratchData &sample_scratch_data,
722 const CopyData &sample_copy_data,
723
724 const AssembleFlags flags = assemble_own_cells,
725
727 std::function<void(const CellIteratorBaseType &,
728 const unsigned int,
729 ScratchData &,
730 CopyData &)>> &boundary_worker =
731 std::function<void(const CellIteratorBaseType &,
732 const unsigned int,
733 ScratchData &,
734 CopyData &)>(),
735
737 std::function<void(const CellIteratorBaseType &,
738 const unsigned int,
739 const unsigned int,
740 const CellIteratorBaseType &,
741 const unsigned int,
742 const unsigned int,
743 ScratchData &,
744 CopyData &)>> &face_worker =
745 std::function<void(const CellIteratorBaseType &,
746 const unsigned int,
747 const unsigned int,
748 const CellIteratorBaseType &,
749 const unsigned int,
750 const unsigned int,
751 ScratchData &,
752 CopyData &)>(),
753
754 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
755 const unsigned int chunk_size = 8)
756 {
757 // Call the function above
758 mesh_loop<typename IteratorRange<CellIteratorType>::IteratorOverIterators,
760 CopyData,
761 CellIteratorBaseType>(iterator_range.begin(),
762 iterator_range.end(),
763 cell_worker,
764 copier,
765 sample_scratch_data,
766 sample_copy_data,
767 flags,
768 boundary_worker,
769 face_worker,
770 queue_length,
771 chunk_size);
772 }
773
833 template <typename CellIteratorType,
834 class ScratchData,
835 class CopyData,
836 class MainClass>
837 void
838 mesh_loop(const CellIteratorType &begin,
840 MainClass &main_class,
841 void (MainClass::*cell_worker)(const CellIteratorType &,
842 ScratchData &,
843 CopyData &),
844 void (MainClass::*copier)(const CopyData &),
845 const ScratchData &sample_scratch_data,
846 const CopyData &sample_copy_data,
847 const AssembleFlags flags = assemble_own_cells,
848 void (MainClass::*boundary_worker)(const CellIteratorType &,
849 const unsigned int,
850 ScratchData &,
851 CopyData &) = nullptr,
852 void (MainClass::*face_worker)(const CellIteratorType &,
853 const unsigned int,
854 const unsigned int,
855 const CellIteratorType &,
856 const unsigned int,
857 const unsigned int,
858 ScratchData &,
859 CopyData &) = nullptr,
860 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
861 const unsigned int chunk_size = 8)
862 {
863 std::function<void(const CellIteratorType &, ScratchData &, CopyData &)>
864 f_cell_worker;
865
866 std::function<void(
867 const CellIteratorType &, const unsigned int, ScratchData &, CopyData &)>
868 f_boundary_worker;
869
870 std::function<void(const CellIteratorType &,
871 const unsigned int,
872 const unsigned int,
873 const CellIteratorType &,
874 const unsigned int,
875 const unsigned int,
876 ScratchData &,
877 CopyData &)>
878 f_face_worker;
879
880 if (cell_worker != nullptr)
881 f_cell_worker = [&main_class,
882 cell_worker](const CellIteratorType &cell_iterator,
883 ScratchData &scratch_data,
884 CopyData &copy_data) {
885 (main_class.*cell_worker)(cell_iterator, scratch_data, copy_data);
886 };
887
888 if (boundary_worker != nullptr)
889 f_boundary_worker =
890 [&main_class, boundary_worker](const CellIteratorType &cell_iterator,
891 const unsigned int face_no,
892 ScratchData &scratch_data,
893 CopyData &copy_data) {
894 (main_class.*
895 boundary_worker)(cell_iterator, face_no, scratch_data, copy_data);
896 };
897
898 if (face_worker != nullptr)
899 f_face_worker = [&main_class,
900 face_worker](const CellIteratorType &cell_iterator_1,
901 const unsigned int face_index_1,
902 const unsigned int subface_index_1,
903 const CellIteratorType &cell_iterator_2,
904 const unsigned int face_index_2,
905 const unsigned int subface_index_2,
906 ScratchData &scratch_data,
907 CopyData &copy_data) {
908 (main_class.*face_worker)(cell_iterator_1,
909 face_index_1,
910 subface_index_1,
911 cell_iterator_2,
912 face_index_2,
913 subface_index_2,
914 scratch_data,
915 copy_data);
916 };
917
918 mesh_loop(
919 begin,
920 end,
921 f_cell_worker,
922 [&main_class, copier](const CopyData &copy_data) {
923 (main_class.*copier)(copy_data);
924 },
925 sample_scratch_data,
926 sample_copy_data,
927 flags,
928 f_boundary_worker,
929 f_face_worker,
930 queue_length,
931 chunk_size);
932 }
933
1013 template <typename CellIteratorType,
1014 class ScratchData,
1015 class CopyData,
1016 class MainClass,
1017 typename CellIteratorBaseType =
1019 void
1021 MainClass &main_class,
1022 void (MainClass::*cell_worker)(const CellIteratorBaseType &,
1023 ScratchData &,
1024 CopyData &),
1025 void (MainClass::*copier)(const CopyData &),
1026 const ScratchData &sample_scratch_data,
1027 const CopyData &sample_copy_data,
1028 const AssembleFlags flags = assemble_own_cells,
1029 void (MainClass::*boundary_worker)(const CellIteratorBaseType &,
1030 const unsigned int,
1031 ScratchData &,
1032 CopyData &) = nullptr,
1033 void (MainClass::*face_worker)(const CellIteratorBaseType &,
1034 const unsigned int,
1035 const unsigned int,
1036 const CellIteratorBaseType &,
1037 const unsigned int,
1038 const unsigned int,
1039 ScratchData &,
1040 CopyData &) = nullptr,
1041 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1042 const unsigned int chunk_size = 8)
1043 {
1044 // Call the function above
1045 mesh_loop<typename IteratorRange<CellIteratorType>::IteratorOverIterators,
1047 CopyData,
1048 MainClass,
1049 CellIteratorBaseType>(iterator_range.begin(),
1050 iterator_range.end(),
1051 main_class,
1052 cell_worker,
1053 copier,
1054 sample_scratch_data,
1055 sample_copy_data,
1056 flags,
1057 boundary_worker,
1058 face_worker,
1059 queue_length,
1060 chunk_size);
1061 }
1062} // namespace MeshWorker
1063
1065
1066#endif
*  iterator end()
*  *  iterator begin()
IteratorOverIterators end() const
IteratorOverIterators begin()
static unsigned int n_threads()
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
void cell_action(IteratorType cell, DoFInfoBox< dim, DOFINFO > &dof_info, INFOBOX &info, const std::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &cell_worker, const std::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &boundary_worker, const std::function< void(DOFINFO &, DOFINFO &, typename INFOBOX::CellInfo &, typename INFOBOX::CellInfo &)> &face_worker, const LoopControl &loop_control)
Definition loop.h:314
void mesh_loop(const CellIteratorType &begin, const CellIteratorType &end, const CellWorkerFunctionType &cell_worker, const CopierType &copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const AssembleFlags flags=assemble_own_cells, const BoundaryWorkerFunctionType &boundary_worker=BoundaryWorkerFunctionType(), const FaceWorkerFunctionType &face_worker=FaceWorkerFunctionType(), const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
Definition mesh_loop.h:279
std::function< void(const CellIteratorBaseType &, const unsigned int, ScratchData &, CopyData &)> BoundaryWorkerFunctionType
Definition mesh_loop.h:121
std::function< void(const CellIteratorBaseType &, const unsigned int, const unsigned int, const CellIteratorBaseType &, const unsigned int, const unsigned int, ScratchData &, CopyData &)> FaceWorkerFunctionType
Definition mesh_loop.h:135
std::function< void(const CellIteratorBaseType &, ScratchData &, CopyData &)> CellWorkerFunctionType
Definition mesh_loop.h:105
std::function< void(const CopyData &)> CopierFunctionType
Definition mesh_loop.h:111
@ assemble_boundary_faces
@ assemble_own_interior_faces_once
@ assemble_ghost_faces_both
@ assemble_own_interior_faces_both
@ assemble_ghost_faces_once
void run(const std::vector< std::vector< Iterator > > &colored_iterators, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
bool is_active_iterator(const DI &)
Definition loop.h:46
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
constexpr types::subdomain_id artificial_subdomain_id
Definition types.h:406
constexpr types::subdomain_id invalid_subdomain_id
Definition types.h:385
typename type_identity< T >::type type_identity_t
Definition type_traits.h:93
typename CellIteratorBaseType< CellIteratorType >::type type
Definition mesh_loop.h:95