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
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) 2009 - 2024 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_loop_h
15#define dealii_mesh_worker_loop_h
16
17#include <deal.II/base/config.h>
18
21
23#include <deal.II/grid/tria.h>
24
28
29#include <functional>
30
32
33// Forward declaration
34#ifndef DOXYGEN
35template <typename>
37#endif
38
39namespace internal
40{
44 template <class DI>
45 inline bool
47 {
48 return false;
49 }
50
51 template <typename AccessorType>
52 inline bool
54 {
55 return true;
56 }
57
58 template <typename AccessorType>
59 inline bool
61 const ::FilteredIterator<TriaActiveIterator<AccessorType>> &)
62 {
63 return true;
64 }
65
66 template <int dim, class DOFINFO, class A>
67 void
69 {
70 dinfo.assemble(*assembler);
71 }
72} // namespace internal
73
74
75
198namespace MeshWorker
199{
204 {
205 public:
210 : own_cells(true)
211 , ghost_cells(false)
212 , faces_to_ghost(LoopControl::one)
213 , own_faces(LoopControl::one)
214 , cells_first(true)
215 {}
216
221
227
234 {
246 both
247 };
248
262
273
279 };
280
281
282
308 template <class INFOBOX,
309 class DOFINFO,
310 int dim,
311 int spacedim,
312 typename IteratorType>
315 IteratorType cell,
316 DoFInfoBox<dim, DOFINFO> &dof_info,
317 INFOBOX &info,
318 const std::function<void(DOFINFO &, typename INFOBOX::CellInfo &)>
319 &cell_worker,
320 const std::function<void(DOFINFO &, typename INFOBOX::CellInfo &)>
321 &boundary_worker,
322 const std::function<void(DOFINFO &,
323 DOFINFO &,
324 typename INFOBOX::CellInfo &,
325 typename INFOBOX::CellInfo &)> &face_worker,
326 const LoopControl &loop_control)
327 {
328 const bool ignore_subdomain =
329 (cell->get_triangulation().locally_owned_subdomain() ==
331
332 types::subdomain_id csid = (cell->is_level_cell()) ?
333 cell->level_subdomain_id() :
334 cell->subdomain_id();
335
336 const bool own_cell =
337 ignore_subdomain ||
338 (csid == cell->get_triangulation().locally_owned_subdomain());
339
340 dof_info.reset();
341
342 if ((!ignore_subdomain) && (csid == numbers::artificial_subdomain_id))
343 return;
344
345 dof_info.cell.reinit(cell);
346 dof_info.cell_valid = true;
347
348 const bool integrate_cell = (cell_worker != nullptr);
349 const bool integrate_boundary = (boundary_worker != nullptr);
350 const bool integrate_interior_face = (face_worker != nullptr);
351
352 if (integrate_cell)
353 info.cell.reinit(dof_info.cell);
354 // Execute this, if cells
355 // have to be dealt with
356 // before faces
357 if (integrate_cell && loop_control.cells_first &&
358 ((loop_control.own_cells && own_cell) ||
359 (loop_control.ghost_cells && !own_cell)))
360 cell_worker(dof_info.cell, info.cell);
361
362 // Call the callback function in
363 // the info box to do
364 // computations between cell and
365 // face action.
366 info.post_cell(dof_info);
367
368 if (integrate_interior_face || integrate_boundary)
369 for (const unsigned int face_no : cell->face_indices())
370 {
371 typename IteratorType::AccessorType::Container::face_iterator face =
372 cell->face(face_no);
373 if (cell->at_boundary(face_no) &&
374 !cell->has_periodic_neighbor(face_no))
375 {
376 // only integrate boundary faces of own cells
377 if (integrate_boundary && own_cell)
378 {
379 dof_info.interior_face_available[face_no] = true;
380 dof_info.interior[face_no].reinit(cell, face, face_no);
381 info.boundary.reinit(dof_info.interior[face_no]);
382 boundary_worker(dof_info.interior[face_no], info.boundary);
383 }
384 }
385 else if (integrate_interior_face)
386 {
387 // Interior face
389 cell->neighbor_or_periodic_neighbor(face_no);
390
392 if (neighbor->is_level_cell())
393 neighbid = neighbor->level_subdomain_id();
394 // subdomain id is only valid for active cells
395 else if (neighbor->is_active())
396 neighbid = neighbor->subdomain_id();
397
398 const bool own_neighbor =
399 ignore_subdomain ||
400 (neighbid ==
401 cell->get_triangulation().locally_owned_subdomain());
402
403 // skip all faces between two ghost cells
404 if (!own_cell && !own_neighbor)
405 continue;
406
407 // skip if the user doesn't want faces between own cells
408 if (own_cell && own_neighbor &&
409 loop_control.own_faces == LoopControl::never)
410 continue;
411
412 // skip face to ghost
413 if (own_cell != own_neighbor &&
414 loop_control.faces_to_ghost == LoopControl::never)
415 continue;
416
417 // Deal with refinement edges from the refined side. Assuming
418 // one-irregular meshes, this situation should only occur if both
419 // cells are active.
420 const bool periodic_neighbor =
421 cell->has_periodic_neighbor(face_no);
422
423 if ((!periodic_neighbor && cell->neighbor_is_coarser(face_no)) ||
424 (periodic_neighbor &&
425 cell->periodic_neighbor_is_coarser(face_no)))
426 {
427 Assert(cell->is_active(), ExcInternalError());
428 Assert(neighbor->is_active(), ExcInternalError());
429
430 // skip if only one processor needs to assemble the face
431 // to a ghost cell and the fine cell is not ours.
432 if (!own_cell &&
433 loop_control.faces_to_ghost == LoopControl::one)
434 continue;
435
436 const std::pair<unsigned int, unsigned int> neighbor_face_no =
437 periodic_neighbor ?
438 cell->periodic_neighbor_of_coarser_periodic_neighbor(
439 face_no) :
440 cell->neighbor_of_coarser_neighbor(face_no);
441 const typename IteratorType::AccessorType::Container::
442 face_iterator nface =
443 neighbor->face(neighbor_face_no.first);
444
445 dof_info.interior_face_available[face_no] = true;
446 dof_info.exterior_face_available[face_no] = true;
447 dof_info.interior[face_no].reinit(cell, face, face_no);
448 info.face.reinit(dof_info.interior[face_no]);
449 dof_info.exterior[face_no].reinit(neighbor,
450 nface,
451 neighbor_face_no.first,
452 neighbor_face_no.second);
453 info.subface.reinit(dof_info.exterior[face_no]);
454
455 face_worker(dof_info.interior[face_no],
456 dof_info.exterior[face_no],
457 info.face,
458 info.subface);
459 }
460 else
461 {
462 // If iterator is active and neighbor is refined, skip
463 // internal face.
465 neighbor->has_children())
466 {
467 Assert(
468 loop_control.own_faces != LoopControl::both,
470 "Assembling from both sides for own_faces is not "
471 "supported with hanging nodes!"));
472 continue;
473 }
474
475 // Now neighbor is on same level, double-check this:
476 Assert(cell->level() == neighbor->level(),
478
479 // If we own both cells only do faces from one side (unless
480 // LoopControl says otherwise). Here, we rely on cell
481 // comparison that will look at cell->index().
482 if (own_cell && own_neighbor &&
483 loop_control.own_faces == LoopControl::one &&
484 (neighbor < cell))
485 continue;
486
487 // independent of loop_control.faces_to_ghost,
488 // we only look at faces to ghost on the same level once
489 // (only where own_cell=true and own_neighbor=false)
490 if (!own_cell)
491 continue;
492
493 // now only one processor assembles faces_to_ghost. We let the
494 // processor with the smaller (level-)subdomain id assemble
495 // the face.
496 if (own_cell && !own_neighbor &&
497 loop_control.faces_to_ghost == LoopControl::one &&
498 (neighbid < csid))
499 continue;
500
501 const unsigned int neighbor_face_no =
502 periodic_neighbor ?
503 cell->periodic_neighbor_face_no(face_no) :
504 cell->neighbor_face_no(face_no);
505 Assert(periodic_neighbor ||
506 neighbor->face(neighbor_face_no) == face,
508 // Regular interior face
509 dof_info.interior_face_available[face_no] = true;
510 dof_info.exterior_face_available[face_no] = true;
511 dof_info.interior[face_no].reinit(cell, face, face_no);
512 info.face.reinit(dof_info.interior[face_no]);
513 dof_info.exterior[face_no].reinit(neighbor,
514 neighbor->face(
515 neighbor_face_no),
516 neighbor_face_no);
517 info.neighbor.reinit(dof_info.exterior[face_no]);
518
519 face_worker(dof_info.interior[face_no],
520 dof_info.exterior[face_no],
521 info.face,
522 info.neighbor);
523 }
524 }
525 } // faces
526 // Call the callback function in
527 // the info box to do
528 // computations between face and
529 // cell action.
530 info.post_faces(dof_info);
531
532 // Execute this, if faces
533 // have to be handled first
534 if (integrate_cell && !loop_control.cells_first &&
535 ((loop_control.own_cells && own_cell) ||
536 (loop_control.ghost_cells && !own_cell)))
537 cell_worker(dof_info.cell, info.cell);
538 }
539
540
555 template <int dim,
556 int spacedim,
557 class DOFINFO,
558 class INFOBOX,
559 typename AssemblerType,
560 typename IteratorType>
562 loop(IteratorType begin,
564 DOFINFO &dinfo,
565 INFOBOX &info,
566 const std::function<void(std_cxx20::type_identity_t<DOFINFO> &,
567 typename INFOBOX::CellInfo &)> &cell_worker,
568 const std::function<void(std_cxx20::type_identity_t<DOFINFO> &,
569 typename INFOBOX::CellInfo &)> &boundary_worker,
570 const std::function<void(std_cxx20::type_identity_t<DOFINFO> &,
572 typename INFOBOX::CellInfo &,
573 typename INFOBOX::CellInfo &)> &face_worker,
574 AssemblerType &assembler,
575 const LoopControl &lctrl = LoopControl())
576 {
577 DoFInfoBox<dim, DOFINFO> dof_info(dinfo);
578
579 assembler.initialize_info(dof_info.cell, false);
580 for (const unsigned int i : GeometryInfo<dim>::face_indices())
581 {
582 assembler.initialize_info(dof_info.interior[i], true);
583 assembler.initialize_info(dof_info.exterior[i], true);
584 }
585
586 // Loop over all cells
588 begin,
589 end,
590 [&cell_worker, &boundary_worker, &face_worker, &lctrl](
591 IteratorType cell, INFOBOX &info, DoFInfoBox<dim, DOFINFO> &dof_info) {
592 cell_action<INFOBOX, DOFINFO, dim, spacedim, IteratorType>(
593 cell,
594 dof_info,
595 info,
596 cell_worker,
597 boundary_worker,
598 face_worker,
599 lctrl);
600 },
601 [&assembler](const MeshWorker::DoFInfoBox<dim, DOFINFO> &dinfo) {
602 ::internal::assemble<dim, DOFINFO, AssemblerType>(dinfo,
603 &assembler);
604 },
605 info,
606 dof_info);
607 }
608
609
620 template <int dim,
621 int spacedim,
622 typename IteratorType,
623 typename AssemblerType>
627 DoFInfo<dim, spacedim> &dof_info,
629 const LocalIntegrator<dim, spacedim> &integrator,
630 AssemblerType &assembler,
631 const LoopControl &lctrl = LoopControl())
632 {
633 std::function<void(DoFInfo<dim, spacedim> &,
635 cell_worker;
636 std::function<void(DoFInfo<dim, spacedim> &,
638 boundary_worker;
639 std::function<void(DoFInfo<dim, spacedim> &,
643 face_worker;
644 if (integrator.use_cell)
645 cell_worker =
646 [&integrator](DoFInfo<dim, spacedim> &dof_info,
647 IntegrationInfo<dim, spacedim> &integration_info) {
648 integrator.cell(dof_info, integration_info);
649 };
650 if (integrator.use_boundary)
651 boundary_worker =
652 [&integrator](DoFInfo<dim, spacedim> &dof_info,
653 IntegrationInfo<dim, spacedim> &integration_info) {
654 integrator.boundary(dof_info, integration_info);
655 };
656 if (integrator.use_face)
657 face_worker =
658 [&integrator](DoFInfo<dim, spacedim> &dof_info_1,
659 DoFInfo<dim, spacedim> &dof_info_2,
660 IntegrationInfo<dim, spacedim> &integration_info_1,
661 IntegrationInfo<dim, spacedim> &integration_info_2) {
662 integrator.face(dof_info_1,
663 dof_info_2,
664 integration_info_1,
665 integration_info_2);
666 };
667
668 loop<dim, spacedim>(begin,
669 end,
670 dof_info,
671 box,
672 cell_worker,
673 boundary_worker,
674 face_worker,
675 assembler,
676 lctrl);
677 }
678
679} // namespace MeshWorker
680
682
683#endif
*  iterator end()
*  *  iterator begin()
DOFINFO interior[GeometryInfo< dim >::faces_per_cell]
Definition dof_info.h:261
void assemble(ASSEMBLER &ass) const
Definition dof_info.h:526
bool exterior_face_available[GeometryInfo< dim >::faces_per_cell]
Definition dof_info.h:277
bool interior_face_available[GeometryInfo< dim >::faces_per_cell]
Definition dof_info.h:271
DOFINFO exterior[GeometryInfo< dim >::faces_per_cell]
Definition dof_info.h:265
virtual void cell(DoFInfo< dim, spacedim, number > &dinfo, IntegrationInfo< dim, spacedim > &info) const
virtual void face(DoFInfo< dim, spacedim, number > &dinfo1, DoFInfo< dim, spacedim, number > &dinfo2, IntegrationInfo< dim, spacedim > &info1, IntegrationInfo< dim, spacedim > &info2) const
virtual void boundary(DoFInfo< dim, spacedim, number > &dinfo, IntegrationInfo< dim, spacedim > &info) const
FaceOption own_faces
Definition loop.h:272
FaceOption faces_to_ghost
Definition loop.h:261
#define DEAL_II_DEPRECATED
Definition config.h:294
#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 integration_loop(IteratorType begin, std_cxx20::type_identity_t< IteratorType > end, DoFInfo< dim, spacedim > &dof_info, IntegrationInfoBox< dim, spacedim > &box, const LocalIntegrator< dim, spacedim > &integrator, AssemblerType &assembler, const LoopControl &lctrl=LoopControl())
Definition loop.h:625
void loop(IteratorType begin, std_cxx20::type_identity_t< IteratorType > end, DOFINFO &dinfo, INFOBOX &info, const std::function< void(std_cxx20::type_identity_t< DOFINFO > &, typename INFOBOX::CellInfo &)> &cell_worker, const std::function< void(std_cxx20::type_identity_t< DOFINFO > &, typename INFOBOX::CellInfo &)> &boundary_worker, const std::function< void(std_cxx20::type_identity_t< DOFINFO > &, std_cxx20::type_identity_t< DOFINFO > &, typename INFOBOX::CellInfo &, typename INFOBOX::CellInfo &)> &face_worker, AssemblerType &assembler, const LoopControl &lctrl=LoopControl())
Definition loop.h:562
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)
void assemble(const MeshWorker::DoFInfoBox< dim, DOFINFO > &dinfo, A *assembler)
Definition loop.h:68
bool is_active_iterator(const DI &)
Definition loop.h:46
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
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices()