Reference documentation for deal.II version 9.1.0-pre
mesh_loop.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #ifndef dealii_mesh_worker_mesh_loop_h
18 #define dealii_mesh_worker_mesh_loop_h
19 
20 #include <deal.II/base/config.h>
21 
22 #include <deal.II/base/template_constraints.h>
23 #include <deal.II/base/work_stream.h>
24 
25 #include <deal.II/grid/filtered_iterator.h>
26 #include <deal.II/grid/tria.h>
27 
28 #include <deal.II/meshworker/assemble_flags.h>
29 #include <deal.II/meshworker/dof_info.h>
30 #include <deal.II/meshworker/integration_info.h>
31 #include <deal.II/meshworker/local_integrator.h>
32 #include <deal.II/meshworker/loop.h>
33 
34 #include <functional>
35 
36 DEAL_II_NAMESPACE_OPEN
37 
38 template <typename>
39 class TriaActiveIterator;
40 
41 namespace MeshWorker
42 {
118  template <class CellIteratorType, class ScratchData, class CopyData>
119  void
120  mesh_loop(const CellIteratorType & begin,
121  const typename identity<CellIteratorType>::type &end,
122 
123  const typename identity<std::function<
124  void(const CellIteratorType &, ScratchData &, CopyData &)>>::type
125  &cell_worker,
126  const typename identity<std::function<void(const CopyData &)>>::type
127  &copier,
128 
129  const ScratchData &sample_scratch_data,
130  const CopyData & sample_copy_data,
131 
132  const AssembleFlags flags = assemble_own_cells,
133 
134  const typename identity<std::function<void(const CellIteratorType &,
135  const unsigned int &,
136  ScratchData &,
137  CopyData &)>>::type
138  &boundary_worker = std::function<void(const CellIteratorType &,
139  const unsigned int &,
140  ScratchData &,
141  CopyData &)>(),
142 
143  const typename identity<std::function<void(const CellIteratorType &,
144  const unsigned int &,
145  const unsigned int &,
146  const CellIteratorType &,
147  const unsigned int &,
148  const unsigned int &,
149  ScratchData &,
150  CopyData &)>>::type
151  &face_worker = std::function<void(const CellIteratorType &,
152  const unsigned int &,
153  const unsigned int &,
154  const CellIteratorType &,
155  const unsigned int &,
156  const unsigned int &,
157  ScratchData &,
158  CopyData &)>(),
159 
160  const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
161  const unsigned int chunk_size = 8)
162  {
163  Assert(
164  (!cell_worker) == !(flags & work_on_cells),
165  ExcMessage(
166  "If you specify a cell_worker, you need to set assemble_own_cells or assemble_ghost_cells."));
167 
168  Assert(
169  (flags &
172  ExcMessage(
173  "You can only specify assemble_own_interior_faces_once OR assemble_own_interior_faces_both."));
174 
175  Assert(
178  ExcMessage(
179  "You can only specify assemble_ghost_faces_once OR assemble_ghost_faces_both."));
180 
181  Assert(
182  !(flags & cells_after_faces) ||
184  ExcMessage(
185  "The option cells_after_faces only makes sense if you assemble on cells."));
186 
187  Assert((!face_worker) == !(flags & work_on_faces),
188  ExcMessage(
189  "If you specify a face_worker, assemble_face_* needs to be set."));
190 
191  Assert(
192  (!boundary_worker) == !(flags & assemble_boundary_faces),
193  ExcMessage(
194  "If you specify a boundary_worker, assemble_boundary_faces needs to be set."));
195 
196  auto cell_action = [&](const CellIteratorType &cell,
197  ScratchData & scratch,
198  CopyData & copy) {
199  // First reset the CopyData class to the empty copy_data given by the
200  // user.
201  copy = sample_copy_data;
202 
203  const bool ignore_subdomain =
204  (cell->get_triangulation().locally_owned_subdomain() ==
206 
207  types::subdomain_id current_subdomain_id =
208  (cell->is_level_cell() ? cell->level_subdomain_id() :
209  cell->subdomain_id());
210 
211  const bool own_cell =
212  ignore_subdomain ||
213  (current_subdomain_id ==
214  cell->get_triangulation().locally_owned_subdomain());
215 
216  if ((!ignore_subdomain) &&
217  (current_subdomain_id == numbers::artificial_subdomain_id))
218  return;
219 
220  if (!(flags & (cells_after_faces)) &&
221  (((flags & (assemble_own_cells)) && own_cell) ||
222  ((flags & assemble_ghost_cells) && !own_cell)))
223  cell_worker(cell, scratch, copy);
224 
225  if (flags & (work_on_faces | work_on_boundary))
226  for (unsigned int face_no = 0;
227  face_no < GeometryInfo<CellIteratorType::AccessorType::Container::
228  dimension>::faces_per_cell;
229  ++face_no)
230  {
231  typename CellIteratorType::AccessorType::Container::face_iterator
232  face = cell->face(face_no);
233  if (cell->at_boundary(face_no) &&
234  !cell->has_periodic_neighbor(face_no))
235  {
236  // only integrate boundary faces of own cells
237  if ((flags & assemble_boundary_faces) && own_cell)
238  boundary_worker(cell, face_no, scratch, copy);
239  }
240  else
241  {
242  // interior face, potentially assemble
244  cell->neighbor_or_periodic_neighbor(face_no);
245 
246  types::subdomain_id neighbor_subdomain_id =
248  if (neighbor->is_level_cell())
249  neighbor_subdomain_id = neighbor->level_subdomain_id();
250  // subdomain id is only valid for active cells
251  else if (neighbor->active())
252  neighbor_subdomain_id = neighbor->subdomain_id();
253 
254  const bool own_neighbor =
255  ignore_subdomain ||
256  (neighbor_subdomain_id ==
257  cell->get_triangulation().locally_owned_subdomain());
258 
259  // skip all faces between two ghost cells
260  if (!own_cell && !own_neighbor)
261  continue;
262 
263  // skip if the user doesn't want faces between own cells
264  if (own_cell && own_neighbor &&
267  continue;
268 
269  // skip face to ghost
270  if (own_cell != own_neighbor &&
271  !(flags &
273  continue;
274 
275  // Deal with refinement edges from the refined side. Assuming
276  // one-irregular meshes, this situation should only occur if
277  // both cells are active.
278  const bool periodic_neighbor =
279  cell->has_periodic_neighbor(face_no);
280 
281  if ((!periodic_neighbor &&
282  cell->neighbor_is_coarser(face_no)) ||
283  (periodic_neighbor &&
284  cell->periodic_neighbor_is_coarser(face_no)))
285  {
286  Assert(!cell->has_children(), ExcInternalError());
287  Assert(!neighbor->has_children(), ExcInternalError());
288 
289  // skip if only one processor needs to assemble the face
290  // to a ghost cell and the fine cell is not ours.
291  if (!own_cell && (flags & assemble_ghost_faces_once))
292  continue;
293 
294  const std::pair<unsigned int, unsigned int>
295  neighbor_face_no =
296  periodic_neighbor ?
297  cell->periodic_neighbor_of_coarser_periodic_neighbor(
298  face_no) :
299  cell->neighbor_of_coarser_neighbor(face_no);
300 
301  face_worker(cell,
302  face_no,
304  neighbor,
305  neighbor_face_no.first,
306  neighbor_face_no.second,
307  scratch,
308  copy);
309 
311  {
312  // If own faces are to be assembled from both sides,
313  // call the faceworker again with swapped arguments.
314  // This is because we won't be looking at an adaptively
315  // refined edge coming from the other side.
316  face_worker(neighbor,
317  neighbor_face_no.first,
318  neighbor_face_no.second,
319  cell,
320  face_no,
322  scratch,
323  copy);
324  }
325  }
326  else
327  {
328  // If iterator is active and neighbor is refined, skip
329  // internal face.
330  if (internal::is_active_iterator(cell) &&
331  neighbor->has_children())
332  continue;
333 
334  // Now neighbor is on same level, double-check this:
335  Assert(cell->level() == neighbor->level(),
336  ExcInternalError());
337 
338  // If we own both cells only do faces from one side (unless
339  // AssembleFlags says otherwise). Here, we rely on cell
340  // comparison that will look at cell->index().
341  if (own_cell && own_neighbor &&
343  (neighbor < cell))
344  continue;
345 
346  // We only look at faces to ghost on the same level once
347  // (only where own_cell=true and own_neighbor=false)
348  if (!own_cell)
349  continue;
350 
351  // now only one processor assembles faces_to_ghost. We let
352  // the processor with the smaller (level-)subdomain id
353  // assemble the face.
354  if (own_cell && !own_neighbor &&
355  (flags & assemble_ghost_faces_once) &&
356  (neighbor_subdomain_id < current_subdomain_id))
357  continue;
358 
359  const unsigned int neighbor_face_no =
360  periodic_neighbor ?
361  cell->periodic_neighbor_face_no(face_no) :
362  cell->neighbor_face_no(face_no);
363  Assert(periodic_neighbor ||
364  neighbor->face(neighbor_face_no) == face,
365  ExcInternalError());
366 
367  face_worker(cell,
368  face_no,
370  neighbor,
371  neighbor_face_no,
373  scratch,
374  copy);
375  }
376  }
377  } // faces
378 
379  // Execute the cell_worker if faces are handled before cells
380  if ((flags & cells_after_faces) &&
381  (((flags & assemble_own_cells) && own_cell) ||
382  ((flags & assemble_ghost_cells) && !own_cell)))
383  cell_worker(cell, scratch, copy);
384  };
385 
386  // Submit to workstream
387  WorkStream::run(begin,
388  end,
389  cell_action,
390  copier,
391  sample_scratch_data,
392  sample_copy_data,
393  queue_length,
394  chunk_size);
395  }
396 } // namespace MeshWorker
397 
398 DEAL_II_NAMESPACE_CLOSE
399 
400 #endif
static const unsigned int invalid_unsigned_int
Definition: types.h:173
void mesh_loop(const CellIteratorType &begin, const typename identity< CellIteratorType >::type &end, const typename identity< std::function< void(const CellIteratorType &, ScratchData &, CopyData &)>>::type &cell_worker, const typename identity< std::function< void(const CopyData &)>>::type &copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const AssembleFlags flags=assemble_own_cells, const typename identity< std::function< void(const CellIteratorType &, const unsigned int &, ScratchData &, CopyData &)>>::type &boundary_worker=std::function< void(const CellIteratorType &, const unsigned int &, ScratchData &, CopyData &)>(), const typename identity< std::function< void(const CellIteratorType &, const unsigned int &, const unsigned int &, const CellIteratorType &, const unsigned int &, const unsigned int &, ScratchData &, CopyData &)>>::type &face_worker=std::function< void(const CellIteratorType &, const unsigned int &, const unsigned int &, const CellIteratorType &, const unsigned int &, const unsigned int &, ScratchData &, CopyData &)>(), const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
Definition: mesh_loop.h:120
const types::subdomain_id invalid_subdomain_id
Definition: types.h:255
static::ExceptionBase & ExcMessage(std::string arg1)
unsigned int subdomain_id
Definition: types.h:43
#define Assert(cond, exc)
Definition: exceptions.h:1227
bool is_active_iterator(const DI &)
Definition: loop.h:46
const types::subdomain_id artificial_subdomain_id
Definition: types.h:272
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)
Definition: work_stream.h:1099
static unsigned int n_threads()
void cell_action(ITERATOR 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:190
static::ExceptionBase & ExcInternalError()