libMesh
parallel_node.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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 // Local includes
21 #include "libmesh/boundary_info.h"
22 #include "libmesh/distributed_mesh.h"
23 #include "libmesh/mesh_base.h"
24 #include "libmesh/node.h"
25 #include "libmesh/parallel_mesh.h"
26 #include "libmesh/parallel_node.h"
27 
28 // C++ includes
29 #include <cstring> // memcpy
30 
31 // Helper functions in anonymous namespace
32 
33 namespace
34 {
35 using namespace libMesh;
36 
37 #ifdef LIBMESH_ENABLE_UNIQUE_ID
38 static const unsigned int header_size = 3;
39 #else
40 static const unsigned int header_size = 2;
41 #endif
42 
43 // use "(a+b-1)/b" trick to get a/b to round up
44 static const unsigned int idtypes_per_Real =
45  (sizeof(Real) + sizeof(largest_id_type) - 1) / sizeof(largest_id_type);
46 
47 #ifndef NDEBUG
48 // Currently this constant is only used for debugging.
49 static const largest_id_type node_magic_header = 1234567890;
50 #endif
51 }
52 
53 
54 namespace libMesh
55 {
56 
57 namespace Parallel
58 {
59 
60 template <>
61 unsigned int
63  const MeshBase * mesh)
64 {
65  return
66 #ifndef NDEBUG
67  1 + // add an int for the magic header when testing
68 #endif
69  header_size + LIBMESH_DIM*idtypes_per_Real +
70  node->packed_indexing_size() +
72 }
73 
74 
75 
76 template <>
77 unsigned int
78 Packing<const Node *>::packed_size (const std::vector<largest_id_type>::const_iterator in)
79 {
80  const unsigned int pre_indexing_size =
81 #ifndef NDEBUG
82  1 + // add an int for the magic header when testing
83 #endif
84  header_size + LIBMESH_DIM*idtypes_per_Real;
85 
86  const unsigned int indexing_size =
87  DofObject::unpackable_indexing_size(in+pre_indexing_size);
88 
89  const int n_bcs = cast_int<int>
90  (*(in + pre_indexing_size + indexing_size));
91  libmesh_assert_greater_equal (n_bcs, 0);
92 
93  return pre_indexing_size + indexing_size + 1 + n_bcs;
94 }
95 
96 
97 
98 template <>
99 unsigned int
100 Packing<const Node *>::packed_size (const std::vector<largest_id_type>::iterator in)
101 {
102  return packed_size(std::vector<largest_id_type>::const_iterator(in));
103 }
104 
105 
106 
107 template <>
108 unsigned int
110  const DistributedMesh * mesh)
111 {
112  return packable_size(node, static_cast<const MeshBase *>(mesh));
113 }
114 
115 
116 
117 template <>
118 unsigned int
120  const ParallelMesh * mesh)
121 {
122  return packable_size(node, static_cast<const MeshBase *>(mesh));
123 }
124 
125 
126 
127 template <>
128 void
129 Packing<const Node *>::pack (const Node * const & node,
130  std::back_insert_iterator<std::vector<largest_id_type>> data_out,
131  const MeshBase * mesh)
132 {
133  libmesh_assert(node);
134 
135 #ifndef NDEBUG
136  *data_out++ = (node_magic_header);
137 #endif
138 
139  *data_out++ = (static_cast<largest_id_type>(node->processor_id()));
140  *data_out++ = (static_cast<largest_id_type>(node->id()));
141 
142 #ifdef LIBMESH_ENABLE_UNIQUE_ID
143  if (node->valid_unique_id())
144  *data_out++ = (static_cast<largest_id_type>(node->unique_id()));
145  else
146  // OK to send invalid unique id, we must not own this DOF
147  *data_out++ = (static_cast<largest_id_type>(DofObject::invalid_unique_id));
148 #endif
149 
150  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
151  {
152  const Real node_i = (*node)(i);
153  largest_id_type Real_as_idtypes[idtypes_per_Real];
154  std::memcpy(Real_as_idtypes, &node_i, sizeof(Real));
155  for (unsigned int j=0; j != idtypes_per_Real; ++j)
156  *data_out++ =(Real_as_idtypes[j]);
157  }
158 
159  // Add any DofObject indices
160  node->pack_indexing(data_out);
161 
162  // Add any nodal boundary condition ids
163  std::vector<boundary_id_type> bcs;
164  mesh->get_boundary_info().boundary_ids(node, bcs);
165 
166  libmesh_assert(bcs.size() < std::numeric_limits<largest_id_type>::max());
167 
168  *data_out++ =(bcs.size());
169 
170  for (const auto & bid : bcs)
171  *data_out++ = bid;
172 }
173 
174 
175 
176 template <>
177 void
178 Packing<const Node *>::pack (const Node * const & node,
179  std::back_insert_iterator<std::vector<largest_id_type>> data_out,
180  const DistributedMesh * mesh)
181 {
182  pack(node, data_out, static_cast<const MeshBase*>(mesh));
183 }
184 
185 
186 
187 template <>
188 void
189 Packing<const Node *>::pack (const Node * const & node,
190  std::back_insert_iterator<std::vector<largest_id_type>> data_out,
191  const ParallelMesh * mesh)
192 {
193  pack(node, data_out, static_cast<const MeshBase*>(mesh));
194 }
195 
196 
197 
198 template <>
199 Node *
200 Packing<Node *>::unpack (std::vector<largest_id_type>::const_iterator in,
201  MeshBase * mesh)
202 {
203 #ifndef NDEBUG
204  const std::vector<largest_id_type>::const_iterator original_in = in;
205  const largest_id_type incoming_header = *in++;
206  libmesh_assert_equal_to (incoming_header, node_magic_header);
207 #endif
208 
209  const processor_id_type processor_id = cast_int<processor_id_type>(*in++);
211  processor_id < mesh->n_processors());
212 
213  const dof_id_type id = cast_int<dof_id_type>(*in++);
214 
215 #ifdef LIBMESH_ENABLE_UNIQUE_ID
216  const unique_id_type unique_id = cast_int<unique_id_type>(*in++);
217 #endif
218 
219  Node * node = mesh->query_node_ptr(id);
220 
221  if (node)
222  {
223  libmesh_assert_equal_to (node->processor_id(), processor_id);
224 
225  // We currently don't communicate mesh motion via packed Nodes,
226  // so it should usually be safe to assume (and assert) that Node
227  // locations are consistent between processors.
228  //
229  // There may be exceptions due to rounding in file I/O, so we'll
230  // only assert equality to within a tight tolerance, and we'll
231  // believe the sender's node locations over our own if we don't
232  // own the node.
233  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
234  {
235  Real idtypes_as_Real;
236  std::memcpy(&idtypes_as_Real, &(*in), sizeof(Real));
237  in += idtypes_per_Real;
238  libmesh_assert_less_equal ((*node)(i), idtypes_as_Real + (std::max(Real(1),idtypes_as_Real)*TOLERANCE*TOLERANCE));
239  libmesh_assert_greater_equal ((*node)(i), idtypes_as_Real - (std::max(Real(1),idtypes_as_Real)*TOLERANCE*TOLERANCE));
240 
241  if (processor_id != mesh->processor_id())
242  (*node)(i) = idtypes_as_Real;
243  }
244 
245  if (!node->has_dofs())
246  {
247  node->unpack_indexing(in);
248  libmesh_assert_equal_to (DofObject::unpackable_indexing_size(in),
249  node->packed_indexing_size());
250  in += node->packed_indexing_size();
251  }
252  else
253  {
254  // FIXME: We should add some debug mode tests to ensure that
255  // the encoded indexing is consistent
257  }
258  }
259  else
260  {
261  // If we don't already have it, we need to allocate it
262  node = new Node();
263 
264  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
265  {
266  Real idtypes_as_Real;
267  std::memcpy(&idtypes_as_Real, &(*in), sizeof(Real));
268  (*node)(i) = idtypes_as_Real;
269  in += idtypes_per_Real;
270  }
271 
272  node->set_id() = id;
273 #ifdef LIBMESH_ENABLE_UNIQUE_ID
274  node->set_unique_id() = unique_id;
275 #endif
276  node->processor_id() = processor_id;
277 
278  node->unpack_indexing(in);
279  libmesh_assert_equal_to (DofObject::unpackable_indexing_size(in),
280  node->packed_indexing_size());
281  in += node->packed_indexing_size();
282  }
283 
284  // FIXME: We should add some debug mode tests to ensure that the
285  // encoded boundary conditions are consistent
286 
287  // Add any nodal boundary condition ids
288  const largest_id_type num_bcs = *in++;
289  // libmesh_assert_greater_equal (num_bcs, 0);
290 
291  for (largest_id_type bc_it=0; bc_it < num_bcs; bc_it++)
293  (node, cast_int<boundary_id_type>(*in++));
294 
295 #ifndef NDEBUG
296  libmesh_assert (in - original_in ==
297  cast_int<int>
299 #endif
300 
301  return node;
302 }
303 
304 
305 
306 template <>
307 Node *
308 Packing<Node *>::unpack (std::vector<largest_id_type>::const_iterator in,
310 {
311  return unpack(in, static_cast<MeshBase*>(mesh));
312 }
313 
314 
315 
316 template <>
317 Node *
318 Packing<Node *>::unpack (std::vector<largest_id_type>::const_iterator in,
319  ParallelMesh * mesh)
320 {
321  return unpack(in, static_cast<MeshBase*>(mesh));
322 }
323 
324 } // namespace Parallel
325 
326 } // namespace libMesh
libMesh::ParallelMesh
Definition: parallel_mesh.h:34
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::BoundaryInfo::boundary_ids
std::vector< boundary_id_type > boundary_ids(const Node *node) const
Definition: boundary_info.C:985
libMesh::unique_id_type
uint8_t unique_id_type
Definition: id_types.h:86
libMesh::MeshBase::get_boundary_info
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:132
libMesh::DofObject::unpack_indexing
void unpack_indexing(std::vector< largest_id_type >::const_iterator begin)
A method for creating our index buffer from packed data - basically with our current implementation w...
Definition: dof_object.C:589
libMesh::DofObject::unpackable_indexing_size
static unsigned int unpackable_indexing_size(std::vector< largest_id_type >::const_iterator begin)
If we have indices packed into an buffer for communications, how much of that buffer applies to this ...
Definition: dof_object.C:569
libMesh::BoundaryInfo::add_node
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
Definition: boundary_info.C:636
libMesh::Parallel::Packing< const Node * >::packed_size
static unsigned int packed_size(BufferIter iter)
libMesh::Parallel::Packing< const Node * >::packable_size
static unsigned int packable_size(const Node *const &object, const Context *context)
libMesh::DofObject::set_id
dof_id_type & set_id()
Definition: dof_object.h:776
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::TOLERANCE
static const Real TOLERANCE
Definition: libmesh_common.h:128
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::DofObject::set_unique_id
unique_id_type & set_unique_id()
Definition: dof_object.h:797
libMesh::DofObject::valid_unique_id
bool valid_unique_id() const
Definition: dof_object.h:817
libMesh::largest_id_type
uint64_t largest_id_type
Definition: id_types.h:148
libMesh::DofObject::processor_id
processor_id_type processor_id() const
Definition: dof_object.h:829
libMesh::DofObject::packed_indexing_size
unsigned int packed_indexing_size() const
If we pack our indices into an buffer for communications, how many ints do we need?
Definition: dof_object.C:554
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::DofObject::invalid_unique_id
static const unique_id_type invalid_unique_id
An invalid unique_id to distinguish an uninitialized DofObject.
Definition: dof_object.h:426
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
libMesh::Parallel::Packing< Node * >::unpack
static Node * unpack(BufferIter in, Context *ctx)
libMesh::ParallelObject::processor_id
processor_id_type processor_id() const
Definition: parallel_object.h:106
libMesh::processor_id_type
uint8_t processor_id_type
Definition: id_types.h:104
libMesh::Node
A Node is like a Point, but with more information.
Definition: node.h:52
libMesh::BoundaryInfo::n_boundary_ids
std::size_t n_boundary_ids() const
Definition: boundary_info.h:360
libMesh::DofObject::unique_id
unique_id_type unique_id() const
Definition: dof_object.h:784
libMesh::DofObject::pack_indexing
void pack_indexing(std::back_insert_iterator< std::vector< largest_id_type >> target) const
A method for creating packed data from our index buffer - basically a copy with prepended size with o...
Definition: dof_object.C:636
libMesh::DofObject::id
dof_id_type id() const
Definition: dof_object.h:767
libMesh::DofObject::invalid_processor_id
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:432
libMesh::DofObject::has_dofs
bool has_dofs(const unsigned int s=libMesh::invalid_uint) const
Definition: dof_object.h:1138
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::MeshBase::query_node_ptr
virtual const Node * query_node_ptr(const dof_id_type i) const =0
libMesh::DistributedMesh
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
Definition: distributed_mesh.h:50
libMesh::Parallel::Packing< const Node * >::pack
static void pack(const Node *const &object, OutputIter data_out, const Context *context)