libMesh
parallel_node.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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
62 Packing<const Node *>::packable_size (const Node * const & node,
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
109 Packing<const Node *>::packable_size (const Node * const & node,
110  const DistributedMesh * mesh)
111 {
112  return packable_size(node, static_cast<const MeshBase *>(mesh));
113 }
114 
115 
116 
117 template <>
118 unsigned int
119 Packing<const Node *>::packable_size (const Node * const & node,
120  const ParallelMesh * mesh)
121 {
122  return packable_size(node, static_cast<const MeshBase *>(mesh));
123 }
124 
125 
126 // Ignore warning about memcpy to a boost float128 address
127 #ifdef LIBMESH_DEFAULT_QUADRUPLE_PRECISION
128 #include "libmesh/ignore_warnings.h"
129 #endif
130 
131 template <>
132 void
133 Packing<const Node *>::pack (const Node * const & node,
134  std::back_insert_iterator<std::vector<largest_id_type>> data_out,
135  const MeshBase * mesh)
136 {
137  libmesh_assert(node);
138 
139 #ifndef NDEBUG
140  *data_out++ = (node_magic_header);
141 #endif
142 
143  *data_out++ = (static_cast<largest_id_type>(node->processor_id()));
144  *data_out++ = (static_cast<largest_id_type>(node->id()));
145 
146 #ifdef LIBMESH_ENABLE_UNIQUE_ID
147  if (node->valid_unique_id())
148  *data_out++ = (static_cast<largest_id_type>(node->unique_id()));
149  else
150  // OK to send invalid unique id, we must not own this DOF
151  *data_out++ = (static_cast<largest_id_type>(DofObject::invalid_unique_id));
152 #endif
153 
154  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
155  {
156  const Real node_i = (*node)(i);
157  largest_id_type Real_as_idtypes[idtypes_per_Real];
158  std::memcpy(Real_as_idtypes, &node_i, sizeof(Real));
159  for (unsigned int j=0; j != idtypes_per_Real; ++j)
160  *data_out++ =(Real_as_idtypes[j]);
161  }
162 
163  // Add any DofObject indices
164  node->pack_indexing(data_out);
165 
166  // Add any nodal boundary condition ids
167  std::vector<boundary_id_type> bcs;
168  mesh->get_boundary_info().boundary_ids(node, bcs);
169 
170  libmesh_assert(bcs.size() < std::numeric_limits<largest_id_type>::max());
171 
172  *data_out++ =(bcs.size());
173 
174  for (const auto & bid : bcs)
175  *data_out++ = bid;
176 }
177 
178 
179 
180 template <>
181 Node *
182 Packing<Node *>::unpack (std::vector<largest_id_type>::const_iterator in,
183  MeshBase * mesh)
184 {
185 #ifndef NDEBUG
186  const std::vector<largest_id_type>::const_iterator original_in = in;
187  const largest_id_type incoming_header = *in++;
188  libmesh_assert_equal_to (incoming_header, node_magic_header);
189 #endif
190 
191  const processor_id_type processor_id = cast_int<processor_id_type>(*in++);
193  processor_id < mesh->n_processors());
194 
195  const dof_id_type id = cast_int<dof_id_type>(*in++);
196 
197 #ifdef LIBMESH_ENABLE_UNIQUE_ID
198  const unique_id_type unique_id = cast_int<unique_id_type>(*in++);
199 #endif
200 
201  Node * node = mesh->query_node_ptr(id);
202 
203  if (node)
204  {
205  libmesh_assert_equal_to (node->processor_id(), processor_id);
206 
207  // We currently don't communicate mesh motion via packed Nodes,
208  // so it should usually be safe to assume (and assert) that Node
209  // locations are consistent between processors.
210  //
211  // There may be exceptions due to rounding in file I/O, so we'll
212  // only assert equality to within a tight tolerance, and we'll
213  // believe the sender's node locations over our own if we don't
214  // own the node.
215  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
216  {
217  Real idtypes_as_Real;
218  std::memcpy(&idtypes_as_Real, &(*in), sizeof(Real));
219  in += idtypes_per_Real;
220  libmesh_assert_less_equal ((*node)(i), idtypes_as_Real + (std::max(Real(1),idtypes_as_Real)*TOLERANCE*TOLERANCE));
221  libmesh_assert_greater_equal ((*node)(i), idtypes_as_Real - (std::max(Real(1),idtypes_as_Real)*TOLERANCE*TOLERANCE));
222 
223  if (processor_id != mesh->processor_id())
224  (*node)(i) = idtypes_as_Real;
225  }
226 
227  if (!node->has_dofs())
228  {
229  node->unpack_indexing(in);
230  libmesh_assert_equal_to (DofObject::unpackable_indexing_size(in),
231  node->packed_indexing_size());
232  in += node->packed_indexing_size();
233  }
234  else
235  {
236  // FIXME: We should add some debug mode tests to ensure that
237  // the encoded indexing is consistent
239  }
240  }
241  else
242  {
243  // If we don't already have it, we need to allocate it.
244  // There is no Node::build() API that lets you defer setting
245  // the (x,y,z) values, so we just use the Node constructor.
246  auto unode = std::make_unique<Node>();
247 
248  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
249  {
250  Real idtypes_as_Real;
251  std::memcpy(&idtypes_as_Real, &(*in), sizeof(Real));
252  (*unode)(i) = idtypes_as_Real;
253  in += idtypes_per_Real;
254  }
255 
256  unode->set_id() = id;
257 #ifdef LIBMESH_ENABLE_UNIQUE_ID
258  unode->set_unique_id(unique_id);
259 #endif
260  unode->processor_id() = processor_id;
261 
262  unode->unpack_indexing(in);
263  libmesh_assert_equal_to (DofObject::unpackable_indexing_size(in),
264  unode->packed_indexing_size());
265  in += unode->packed_indexing_size();
266 
267  node = mesh->add_node(std::move(unode));
268  }
269 
270  // FIXME: We should add some debug mode tests to ensure that the
271  // encoded boundary conditions are consistent
272 
273  // Add any nodal boundary condition ids
274  const largest_id_type num_bcs = *in++;
275  // libmesh_assert_greater_equal (num_bcs, 0);
276 
277  for (largest_id_type bc_it=0; bc_it < num_bcs; bc_it++)
279  (node, cast_int<boundary_id_type>(*in++));
280 
281 #ifndef NDEBUG
282  libmesh_assert (in - original_in ==
283  cast_int<int>
285 #endif
286 
287  return node;
288 }
289 
290 
291 #ifdef LIBMESH_DEFAULT_QUADRUPLE_PRECISION
292 #include "libmesh/restore_warnings.h"
293 #endif
294 
295 
296 template <>
297 void
298 Packing<const Node *>::pack (const Node * const & node,
299  std::back_insert_iterator<std::vector<largest_id_type>> data_out,
300  const DistributedMesh * mesh)
301 {
302  pack(node, data_out, static_cast<const MeshBase*>(mesh));
303 }
304 
305 
306 
307 template <>
308 void
309 Packing<const Node *>::pack (const Node * const & node,
310  std::back_insert_iterator<std::vector<largest_id_type>> data_out,
311  const ParallelMesh * mesh)
312 {
313  pack(node, data_out, static_cast<const MeshBase*>(mesh));
314 }
315 
316 
317 
318 template <>
319 Node *
320 Packing<Node *>::unpack (std::vector<largest_id_type>::const_iterator in,
322 {
323  return unpack(in, static_cast<MeshBase*>(mesh));
324 }
325 
326 
327 
328 template <>
329 Node *
330 Packing<Node *>::unpack (std::vector<largest_id_type>::const_iterator in,
331  ParallelMesh * mesh)
332 {
333  return unpack(in, static_cast<MeshBase*>(mesh));
334 }
335 
336 } // namespace Parallel
337 
338 } // namespace libMesh
A Node is like a Point, but with more information.
Definition: node.h:52
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:575
static constexpr Real TOLERANCE
MeshBase & mesh
uint64_t largest_id_type
Definition: id_types.h:148
unique_id_type unique_id() const
Definition: dof_object.h:844
void boundary_ids(const Node *node, std::vector< boundary_id_type > &vec_to_fill) const
Fills a user-provided std::vector with the boundary ids associated with Node node.
The libMesh namespace provides an interface to certain functionality in the library.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
static T unpack(BufferIter in, Context *ctx)
Definition: parallel_elem.h:90
static unsigned int packable_size(const T &object, const Context *context)
This is the MeshBase class.
Definition: mesh_base.h:75
std::size_t n_boundary_ids() const
uint8_t processor_id_type
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
dof_id_type id() const
Definition: dof_object.h:828
static const unique_id_type invalid_unique_id
An invalid unique_id to distinguish an uninitialized DofObject.
Definition: dof_object.h:487
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:493
static unsigned int packed_size(BufferIter iter)
virtual const Node * query_node_ptr(const dof_id_type i) const =0
libmesh_assert(ctx)
bool valid_unique_id() const
Definition: dof_object.h:893
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
static void pack(const T &object, OutputIter data_out, const Context *context)
virtual Node * add_node(Node *n)=0
Add Node n to the end of the vertex array.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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:560
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:642
processor_id_type processor_id() const
processor_id_type processor_id() const
Definition: dof_object.h:905
uint8_t unique_id_type
Definition: id_types.h:86
uint8_t dof_id_type
Definition: id_types.h:67