libMesh
parallel_ghost_sync.h
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2017 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 #ifndef LIBMESH_PARALLEL_GHOST_SYNC_H
21 #define LIBMESH_PARALLEL_GHOST_SYNC_H
22 
23 // Local Includes
24 #include "libmesh/auto_ptr.h"
25 #include "libmesh/elem.h"
26 #include "libmesh/location_maps.h"
27 #include "libmesh/mesh_base.h"
28 #include "libmesh/parallel.h"
29 
30 
31 namespace libMesh
32 {
33 
34 
35 
36 //--------------------------------------------------------------------------
37 namespace Parallel {
38 
39 //------------------------------------------------------------------------
56 template <typename Iterator,
57  typename DofObjType,
58  typename SyncFunctor>
59 void sync_dofobject_data_by_xyz(const Communicator & comm,
60  const Iterator & range_begin,
61  const Iterator & range_end,
62  LocationMap<DofObjType> * location_map,
63  SyncFunctor & sync);
64 
65 //------------------------------------------------------------------------
78 template <typename Iterator,
79  typename SyncFunctor>
80 void sync_dofobject_data_by_id(const Communicator & comm,
81  const Iterator & range_begin,
82  const Iterator & range_end,
83  SyncFunctor & sync);
84 
92 template <typename Iterator,
93  typename DofObjectCheckFunctor,
94  typename SyncFunctor>
95 void sync_dofobject_data_by_id(const Communicator & comm,
96  const Iterator & range_begin,
97  const Iterator & range_end,
98  const DofObjectCheckFunctor & dofobj_check,
99  SyncFunctor & sync);
100 
101 //------------------------------------------------------------------------
115 template <typename Iterator,
116  typename SyncFunctor>
117 void sync_element_data_by_parent_id(MeshBase & mesh,
118  const Iterator & range_begin,
119  const Iterator & range_end,
120  SyncFunctor & sync);
121 
122 //------------------------------------------------------------------------
146 template <typename ElemCheckFunctor,
147  typename NodeCheckFunctor,
148  typename SyncFunctor>
149 void sync_node_data_by_element_id(MeshBase & mesh,
150  const MeshBase::const_element_iterator & range_begin,
151  const MeshBase::const_element_iterator & range_end,
152  const ElemCheckFunctor & elem_check,
153  const NodeCheckFunctor & node_check,
154  SyncFunctor & sync);
155 
156 
157 //------------------------------------------------------------------------
158 // Parallel members
159 
160 
161 // "Check" Functor to perform sync operations with no exclusions
163 {
165 
166  bool operator() (const DofObject *) const { return true; }
167 
168  bool operator() (const Elem *, unsigned int) const
169  { return true; }
170 };
171 
172 
173 
174 template <typename Iterator,
175  typename DofObjType,
176  typename SyncFunctor>
178  const Iterator & range_begin,
179  const Iterator & range_end,
180  LocationMap<DofObjType> & location_map,
181  SyncFunctor & sync)
182 {
183  // This function must be run on all processors at once
184  libmesh_parallel_only(comm);
185 
186  // We need a valid location_map
187 #ifdef DEBUG
188  bool need_map_update = (range_begin != range_end && location_map.empty());
189  comm.max(need_map_update);
190  libmesh_assert(!need_map_update);
191 #endif
192 
193  // Count the objects to ask each processor about
194  std::vector<dof_id_type>
195  ghost_objects_from_proc(comm.size(), 0);
196 
197  for (Iterator it = range_begin; it != range_end; ++it)
198  {
199  DofObjType * obj = *it;
200  libmesh_assert (obj);
201  processor_id_type obj_procid = obj->processor_id();
202  if (obj_procid != DofObject::invalid_processor_id)
203  ghost_objects_from_proc[obj_procid]++;
204  }
205 
206  // Request sets to send to each processor
207  std::vector<std::vector<Real>>
208  requested_objs_x(comm.size()),
209  requested_objs_y(comm.size()),
210  requested_objs_z(comm.size());
211  // Corresponding ids to keep track of
212  std::vector<std::vector<dof_id_type>>
213  requested_objs_id(comm.size());
214 
215  // We know how many objects live on each processor, so reserve()
216  // space for each.
217  for (processor_id_type p=0; p != comm.size(); ++p)
218  if (p != comm.rank())
219  {
220  requested_objs_x[p].reserve(ghost_objects_from_proc[p]);
221  requested_objs_y[p].reserve(ghost_objects_from_proc[p]);
222  requested_objs_z[p].reserve(ghost_objects_from_proc[p]);
223  requested_objs_id[p].reserve(ghost_objects_from_proc[p]);
224  }
225  for (Iterator it = range_begin; it != range_end; ++it)
226  {
227  DofObjType * obj = *it;
228  processor_id_type obj_procid = obj->processor_id();
229  if (obj_procid == comm.rank() ||
230  obj_procid == DofObject::invalid_processor_id)
231  continue;
232 
233  Point p = location_map.point_of(*obj);
234  requested_objs_x[obj_procid].push_back(p(0));
235  requested_objs_y[obj_procid].push_back(p(1));
236  requested_objs_z[obj_procid].push_back(p(2));
237  requested_objs_id[obj_procid].push_back(obj->id());
238  }
239 
240  // Trade requests with other processors
241  for (processor_id_type p=1; p != comm.size(); ++p)
242  {
243  // Trade my requests with processor procup and procdown
244  const processor_id_type procup =
245  cast_int<processor_id_type>
246  ((comm.rank() + p) % comm.size());
247  const processor_id_type procdown =
248  cast_int<processor_id_type>
249  ((comm.size() + comm.rank() - p) %
250  comm.size());
251  std::vector<Real> request_to_fill_x,
252  request_to_fill_y,
253  request_to_fill_z;
254  comm.send_receive(procup, requested_objs_x[procup],
255  procdown, request_to_fill_x);
256  comm.send_receive(procup, requested_objs_y[procup],
257  procdown, request_to_fill_y);
258  comm.send_receive(procup, requested_objs_z[procup],
259  procdown, request_to_fill_z);
260 
261  // Find the local id of each requested object
262  std::vector<dof_id_type> request_to_fill_id(request_to_fill_x.size());
263  for (std::size_t i=0; i != request_to_fill_x.size(); ++i)
264  {
265  Point pt(request_to_fill_x[i],
266  request_to_fill_y[i],
267  request_to_fill_z[i]);
268 
269  // Look for this object in the multimap
270  DofObjType * obj = location_map.find(pt);
271 
272  // We'd better find every object we're asked for
273  libmesh_assert (obj);
274 
275  // Return the object's correct processor id,
276  // and our (correct if it's local) id for it.
277  request_to_fill_id[i] = obj->id();
278  }
279 
280  // Gather whatever data the user wants
281  std::vector<typename SyncFunctor::datum> data;
282  sync.gather_data(request_to_fill_id, data);
283 
284  // Trade back the results
285  std::vector<typename SyncFunctor::datum> received_data;
286  comm.send_receive(procdown, data,
287  procup, received_data);
288  libmesh_assert_equal_to (requested_objs_x[procup].size(),
289  received_data.size());
290 
291  // Let the user process the results
292  sync.act_on_data(requested_objs_id[procup], received_data);
293  }
294 }
295 
296 
297 
298 template <typename Iterator,
299  typename SyncFunctor>
301  const Iterator & range_begin,
302  const Iterator & range_end,
303  SyncFunctor & sync)
304 {
305  sync_dofobject_data_by_id(comm, range_begin, range_end, SyncEverything(), sync);
306 }
307 
308 template <typename Iterator,
309  typename DofObjectCheckFunctor,
310  typename SyncFunctor>
312  const Iterator & range_begin,
313  const Iterator & range_end,
314  const DofObjectCheckFunctor & dofobj_check,
315  SyncFunctor & sync)
316 {
317  // This function must be run on all processors at once
318  libmesh_parallel_only(comm);
319 
320  // Count the objects to ask each processor about
321  std::vector<dof_id_type>
322  ghost_objects_from_proc(comm.size(), 0);
323 
324  for (Iterator it = range_begin; it != range_end; ++it)
325  {
326  DofObject * obj = *it;
327  libmesh_assert (obj);
328 
329  // We may want to pass Elem* or Node* to the check function, not
330  // just DofObject*
331  if (!dofobj_check(*it))
332  continue;
333 
334  processor_id_type obj_procid = obj->processor_id();
335  if (obj_procid != DofObject::invalid_processor_id)
336  ghost_objects_from_proc[obj_procid]++;
337  }
338 
339  // Request sets to send to each processor
340  std::vector<std::vector<dof_id_type>>
341  requested_objs_id(comm.size());
342 
343  // We know how many objects live on each processor, so reserve()
344  // space for each.
345  for (processor_id_type p=0; p != comm.size(); ++p)
346  if (p != comm.rank())
347  {
348  requested_objs_id[p].reserve(ghost_objects_from_proc[p]);
349  }
350  for (Iterator it = range_begin; it != range_end; ++it)
351  {
352  DofObject * obj = *it;
353 
354  if (!dofobj_check(*it))
355  continue;
356 
357  processor_id_type obj_procid = obj->processor_id();
358  if (obj_procid == comm.rank() ||
359  obj_procid == DofObject::invalid_processor_id)
360  continue;
361 
362  requested_objs_id[obj_procid].push_back(obj->id());
363  }
364 
365  // Trade requests with other processors
366  for (processor_id_type p=1; p != comm.size(); ++p)
367  {
368  // Trade my requests with processor procup and procdown
369  const processor_id_type procup =
370  cast_int<processor_id_type>
371  ((comm.rank() + p) % comm.size());
372  const processor_id_type procdown =
373  cast_int<processor_id_type>
374  ((comm.size() + comm.rank() - p) %
375  comm.size());
376  std::vector<dof_id_type> request_to_fill_id;
377  comm.send_receive(procup, requested_objs_id[procup],
378  procdown, request_to_fill_id);
379 
380  // Gather whatever data the user wants
381  std::vector<typename SyncFunctor::datum> data;
382  sync.gather_data(request_to_fill_id, data);
383 
384  // Trade back the results
385  std::vector<typename SyncFunctor::datum> received_data;
386  comm.send_receive(procdown, data,
387  procup, received_data);
388  libmesh_assert_equal_to (requested_objs_id[procup].size(),
389  received_data.size());
390 
391  // Let the user process the results
392  sync.act_on_data(requested_objs_id[procup], received_data);
393  }
394 }
395 
396 
397 
398 // If there's no refined elements, there's nothing to sync
399 #ifdef LIBMESH_ENABLE_AMR
400 template <typename Iterator,
401  typename SyncFunctor>
403  const Iterator & range_begin,
404  const Iterator & range_end,
405  SyncFunctor & sync)
406 {
407  const Communicator & comm (mesh.comm());
408 
409  // This function must be run on all processors at once
410  libmesh_parallel_only(comm);
411 
412  // Count the objects to ask each processor about
413  std::vector<dof_id_type>
414  ghost_objects_from_proc(comm.size(), 0);
415 
416  for (Iterator it = range_begin; it != range_end; ++it)
417  {
418  DofObject * obj = *it;
419  libmesh_assert (obj);
420  processor_id_type obj_procid = obj->processor_id();
421  if (obj_procid != DofObject::invalid_processor_id)
422  ghost_objects_from_proc[obj_procid]++;
423  }
424 
425  // Request sets to send to each processor
426  std::vector<std::vector<dof_id_type>>
427  requested_objs_id(comm.size()),
428  requested_objs_parent_id(comm.size());
429  std::vector<std::vector<unsigned char>>
430  requested_objs_child_num(comm.size());
431 
432  // We know how many objects live on each processor, so reserve()
433  // space for each.
434  for (processor_id_type p=0; p != comm.size(); ++p)
435  if (p != comm.rank())
436  {
437  requested_objs_id[p].reserve(ghost_objects_from_proc[p]);
438  requested_objs_parent_id[p].reserve(ghost_objects_from_proc[p]);
439  requested_objs_child_num[p].reserve(ghost_objects_from_proc[p]);
440  }
441 
442  for (Iterator it = range_begin; it != range_end; ++it)
443  {
444  Elem * elem = *it;
445  processor_id_type obj_procid = elem->processor_id();
446  if (obj_procid == comm.rank() ||
447  obj_procid == DofObject::invalid_processor_id)
448  continue;
449  const Elem * parent = elem->parent();
450  if (!parent || !elem->active())
451  continue;
452 
453  requested_objs_id[obj_procid].push_back(elem->id());
454  requested_objs_parent_id[obj_procid].push_back(parent->id());
455  requested_objs_child_num[obj_procid].push_back
456  (cast_int<unsigned char>
457  (parent->which_child_am_i(elem)));
458  }
459 
460  // Trade requests with other processors
461  for (processor_id_type p=1; p != comm.size(); ++p)
462  {
463  // Trade my requests with processor procup and procdown
464  const processor_id_type procup =
465  cast_int<processor_id_type>
466  ((comm.rank() + p) % comm.size());
467  const processor_id_type procdown =
468  cast_int<processor_id_type>
469  ((comm.size() + comm.rank() - p) %
470  comm.size());
471  std::vector<dof_id_type> request_to_fill_parent_id;
472  std::vector<unsigned char> request_to_fill_child_num;
473  comm.send_receive(procup, requested_objs_parent_id[procup],
474  procdown, request_to_fill_parent_id);
475  comm.send_receive(procup, requested_objs_child_num[procup],
476  procdown, request_to_fill_child_num);
477 
478  // Find the id of each requested element
479  std::size_t request_size = request_to_fill_parent_id.size();
480  std::vector<dof_id_type> request_to_fill_id(request_size);
481  for (std::size_t i=0; i != request_size; ++i)
482  {
483  Elem & parent = mesh.elem_ref(request_to_fill_parent_id[i]);
484  libmesh_assert(parent.has_children());
485  Elem * child = parent.child_ptr(request_to_fill_child_num[i]);
486  libmesh_assert(child);
487  libmesh_assert(child->active());
488  request_to_fill_id[i] = child->id();
489  }
490 
491  // Gather whatever data the user wants
492  std::vector<typename SyncFunctor::datum> data;
493  sync.gather_data(request_to_fill_id, data);
494 
495  // Trade back the results
496  std::vector<typename SyncFunctor::datum> received_data;
497  comm.send_receive(procdown, data,
498  procup, received_data);
499  libmesh_assert_equal_to (requested_objs_id[procup].size(),
500  received_data.size());
501 
502  // Let the user process the results
503  sync.act_on_data(requested_objs_id[procup], received_data);
504  }
505 }
506 #else
507 template <typename Iterator,
508  typename SyncFunctor>
510  const Iterator &,
511  const Iterator &,
512  SyncFunctor &)
513 {
514 }
515 #endif // LIBMESH_ENABLE_AMR
516 
517 
518 
519 template <typename ElemCheckFunctor,
520  typename NodeCheckFunctor,
521  typename SyncFunctor>
523  const MeshBase::const_element_iterator & range_begin,
524  const MeshBase::const_element_iterator & range_end,
525  const ElemCheckFunctor & elem_check,
526  const NodeCheckFunctor & node_check,
527  SyncFunctor & sync)
528 {
529  const Communicator & comm (mesh.comm());
530 
531  // This function must be run on all processors at once
532  libmesh_parallel_only(comm);
533 
534  // Keep track of which nodes we've asked about, so we only hit each
535  // once?
536  // std::unordered_set<dof_id_type> queried_nodes;
537 
538  // No. We need to ask every neighboring processor about every node,
539  // probably repeatedly. Imagine a vertex surrounded by triangles,
540  // each on a different processor, with a ghosting policy that
541  // include only face neighbors and not point neighbors. Then the
542  // only way for authoritative information to trickle out from that
543  // vertex is by being passed along, one neighbor at a time, to
544  // processors who mostly don't even see the node's true owner!
545 
546  bool need_sync = false;
547 
548  do
549  {
550  // This is the last sync we need, unless we later discover
551  // otherwise
552  need_sync = false;
553 
554  // Count the objects to ask each processor about
555  std::vector<dof_id_type>
556  ghost_objects_from_proc(comm.size(), 0);
557 
558  for (MeshBase::const_element_iterator it = range_begin;
559  it != range_end; ++it)
560  {
561  const Elem * elem = *it;
562  libmesh_assert (elem);
563 
564  if (!elem_check(elem))
565  continue;
566 
567  const processor_id_type proc_id = elem->processor_id();
568  if (proc_id == comm.rank() ||
570  continue;
571 
572  for (auto n : elem->node_index_range())
573  {
574  if (!node_check(elem, n))
575  continue;
576 
577  ghost_objects_from_proc[proc_id]++;
578  }
579  }
580 
581  // Now repeat that iteration, filling request sets this time.
582 
583  // Request sets to send to each processor
584  std::vector<std::vector<dof_id_type>>
585  requested_objs_elem_id(comm.size());
586  std::vector<std::vector<unsigned char>>
587  requested_objs_node_num(comm.size());
588 
589  // Keep track of current local ids for each too
590  std::vector<std::vector<dof_id_type>>
591  requested_objs_id(comm.size());
592 
593  // We know how many objects live on each processor, so reserve()
594  // space for each.
595  for (processor_id_type p=0; p != comm.size(); ++p)
596  if (p != comm.rank())
597  {
598  requested_objs_elem_id[p].reserve(ghost_objects_from_proc[p]);
599  requested_objs_node_num[p].reserve(ghost_objects_from_proc[p]);
600  requested_objs_id[p].reserve(ghost_objects_from_proc[p]);
601  }
602 
603  for (MeshBase::const_element_iterator it = range_begin;
604  it != range_end; ++it)
605  {
606  const Elem * elem = *it;
607  libmesh_assert (elem);
608 
609  if (!elem_check(elem))
610  continue;
611 
612  const processor_id_type proc_id = elem->processor_id();
613  if (proc_id == comm.rank() ||
615  continue;
616 
617  const dof_id_type elem_id = elem->id();
618 
619  for (auto n : elem->node_index_range())
620  {
621  if (!node_check(elem, n))
622  continue;
623 
624  const Node & node = elem->node_ref(n);
625  const dof_id_type node_id = node.id();
626 
627  requested_objs_elem_id[proc_id].push_back(elem_id);
628  requested_objs_node_num[proc_id].push_back
629  (cast_int<unsigned char>(n));
630  requested_objs_id[proc_id].push_back(node_id);
631  }
632  }
633 
634  // Trade requests with other processors
635  for (processor_id_type p=1; p != comm.size(); ++p)
636  {
637  // Trade my requests with processor procup and procdown
638  const processor_id_type procup =
639  cast_int<processor_id_type>
640  ((comm.rank() + p) % comm.size());
641  const processor_id_type procdown =
642  cast_int<processor_id_type>
643  ((comm.size() + comm.rank() - p) %
644  comm.size());
645 
646  libmesh_assert_equal_to (requested_objs_id[procup].size(),
647  ghost_objects_from_proc[procup]);
648  libmesh_assert_equal_to (requested_objs_elem_id[procup].size(),
649  ghost_objects_from_proc[procup]);
650  libmesh_assert_equal_to (requested_objs_node_num[procup].size(),
651  ghost_objects_from_proc[procup]);
652 
653  std::vector<dof_id_type> request_to_fill_elem_id;
654  std::vector<unsigned char> request_to_fill_node_num;
655  comm.send_receive(procup, requested_objs_elem_id[procup],
656  procdown, request_to_fill_elem_id);
657  comm.send_receive(procup, requested_objs_node_num[procup],
658  procdown, request_to_fill_node_num);
659 
660  // Find the id of each requested element
661  std::size_t request_size = request_to_fill_elem_id.size();
662  std::vector<dof_id_type> request_to_fill_id(request_size);
663  for (std::size_t i=0; i != request_size; ++i)
664  {
665  const Elem & elem = mesh.elem_ref(request_to_fill_elem_id[i]);
666 
667  const unsigned int n = request_to_fill_node_num[i];
668  libmesh_assert_less (n, elem.n_nodes());
669 
670  const Node & node = elem.node_ref(n);
671 
672  // This isn't a safe assertion in the case where we're
673  // syncing processor ids
674  // libmesh_assert_equal_to (node->processor_id(), comm.rank());
675 
676  request_to_fill_id[i] = node.id();
677  }
678 
679  // Gather whatever data the user wants
680  std::vector<typename SyncFunctor::datum> data;
681  sync.gather_data(request_to_fill_id, data);
682 
683  // Trade back the results
684  std::vector<typename SyncFunctor::datum> received_data;
685  comm.send_receive(procdown, data,
686  procup, received_data);
687  libmesh_assert_equal_to (requested_objs_elem_id[procup].size(),
688  received_data.size());
689 
690  // Let the user process the results. If any of the results
691  // were different than what the user expected, then we'll
692  // need to sync again just in case this processor has to
693  // pass on the changes to yet another processor.
694  bool data_changed =
695  sync.act_on_data(requested_objs_id[procup], received_data);
696 
697  if (data_changed)
698  need_sync = true;
699  }
700  comm.max(need_sync);
701  } while (need_sync);
702 }
703 
704 
705 }
706 
707 
708 
709 // This struct can be created and passed to the
710 // Parallel::sync_dofobject_data_by_id() function.
712 {
713  // The constructor. You need a reference to the mesh where you will
714  // be setting/getting nodal positions.
715  explicit
717 
718  // The datum typedef is required of this functor, so that the
719  // Parallel::sync_dofobject_data_by_id() function can create e.g.
720  // std::vector<datum>.
721  typedef Point datum;
722 
723  // First required interface. This function must fill up the data vector for the
724  // ids specified in the ids vector.
725  void gather_data (const std::vector<dof_id_type> & ids, std::vector<datum> & data) const;
726 
727  // Second required interface. This function must do something with the data in
728  // the data vector for the ids in the ids vector.
729  void act_on_data (const std::vector<dof_id_type> & ids, std::vector<datum> & data) const;
730 
732 };
733 
734 
735 } // namespace libMesh
736 
737 #endif // LIBMESH_PARALLEL_GHOST_SYNC_H
T * find(const Point &, const Real tol=TOLERANCE)
bool has_children() const
Definition: elem.h:2295
A Node is like a Point, but with more information.
Definition: node.h:52
Encapsulates the MPI_Comm object.
Definition: parallel.h:657
bool active() const
Definition: elem.h:2257
unsigned int size() const
Definition: parallel.h:726
void max(T &r) const
Take a local variable and replace it with the maximum of it&#39;s values on all processors.
The definition of the const_element_iterator struct.
Definition: mesh_base.h:1494
IntRange< unsigned short > node_index_range() const
Definition: elem.h:2065
const Elem * parent() const
Definition: elem.h:2346
Point point_of(const T &) const
This is the base class from which all geometric element types are derived.
Definition: elem.h:89
MeshBase & mesh
uint8_t processor_id_type
Definition: id_types.h:99
void sync_dofobject_data_by_xyz(const Communicator &comm, const Iterator &range_begin, const Iterator &range_end, LocationMap< DofObjType > *location_map, SyncFunctor &sync)
Request data about a range of ghost nodes uniquely identified by their xyz location or a range of act...
The libMesh namespace provides an interface to certain functionality in the library.
This is the MeshBase class.
Definition: mesh_base.h:68
libmesh_assert(j)
virtual unsigned int n_nodes() const =0
void send_receive(const unsigned int dest_processor_id, const T1 &send, const unsigned int source_processor_id, T2 &recv, const MessageTag &send_tag=no_tag, const MessageTag &recv_tag=any_tag) const
Send data send to one processor while simultaneously receiving other data recv from a (potentially di...
static const processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
Definition: dof_object.h:335
void sync_node_data_by_element_id(MeshBase &mesh, const MeshBase::const_element_iterator &range_begin, const MeshBase::const_element_iterator &range_end, const ElemCheckFunctor &elem_check, const NodeCheckFunctor &node_check, SyncFunctor &sync)
Request data about a range of ghost nodes uniquely identified by an element id and local node id...
const Elem * child_ptr(unsigned int i) const
Definition: elem.h:2445
const Node & node_ref(const unsigned int i) const
Definition: elem.h:1896
void sync_dofobject_data_by_id(const Communicator &comm, const Iterator &range_begin, const Iterator &range_end, SyncFunctor &sync)
Request data about a range of ghost dofobjects uniquely identified by their id.
Data structures that enable location-based lookups The key is a hash of the Point location...
Definition: location_maps.h:53
bool operator()(const DofObject *) const
unsigned int which_child_am_i(const Elem *e) const
Definition: elem.h:2487
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:490
const Parallel::Communicator & comm() const
The DofObject defines an abstract base class for objects that have degrees of freedom associated with...
Definition: dof_object.h:51
bool empty() const
Definition: location_maps.h:63
unsigned int rank() const
Definition: parallel.h:724
IterBase * data
Ideally this private member data should have protected access.
dof_id_type id() const
Definition: dof_object.h:632
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
void sync_element_data_by_parent_id(MeshBase &mesh, const Iterator &range_begin, const Iterator &range_end, SyncFunctor &sync)
Request data about a range of ghost elements uniquely identified by their parent id and which child t...
uint8_t dof_id_type
Definition: id_types.h:64
processor_id_type processor_id() const
Definition: dof_object.h:694