Line data Source code
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 65454968 : 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 65454968 : node->packed_indexing_size() +
71 65454968 : 1 + mesh->get_boundary_info().n_boundary_ids(node);
72 : }
73 :
74 :
75 :
76 : template <>
77 : unsigned int
78 151988550 : Packing<const Node *>::packed_size (const std::vector<largest_id_type>::const_iterator in)
79 : {
80 223734 : 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 151988550 : DofObject::unpackable_indexing_size(in+pre_indexing_size);
88 :
89 : const int n_bcs = cast_int<int>
90 151988550 : (*(in + pre_indexing_size + indexing_size));
91 223734 : libmesh_assert_greater_equal (n_bcs, 0);
92 :
93 151988550 : return pre_indexing_size + indexing_size + 1 + n_bcs;
94 : }
95 :
96 :
97 :
98 : template <>
99 : unsigned int
100 71818 : Packing<const Node *>::packed_size (const std::vector<largest_id_type>::iterator in)
101 : {
102 71818 : return packed_size(std::vector<largest_id_type>::const_iterator(in));
103 : }
104 :
105 :
106 :
107 : template <>
108 : unsigned int
109 51311224 : Packing<const Node *>::packable_size (const Node * const & node,
110 : const DistributedMesh * mesh)
111 : {
112 51311224 : return packable_size(node, static_cast<const MeshBase *>(mesh));
113 : }
114 :
115 :
116 :
117 : template <>
118 : unsigned int
119 0 : Packing<const Node *>::packable_size (const Node * const & node,
120 : const ParallelMesh * mesh)
121 : {
122 0 : 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 65380550 : 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 71818 : libmesh_assert(node);
138 :
139 : #ifndef NDEBUG
140 71818 : *data_out++ = (node_magic_header);
141 : #endif
142 :
143 65380550 : *data_out++ = (static_cast<largest_id_type>(node->processor_id()));
144 65380550 : *data_out++ = (static_cast<largest_id_type>(node->id()));
145 :
146 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
147 65380550 : if (node->valid_unique_id())
148 65380550 : *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 0 : *data_out++ = (static_cast<largest_id_type>(DofObject::invalid_unique_id));
152 : #endif
153 :
154 261522200 : for (unsigned int i=0; i != LIBMESH_DIM; ++i)
155 : {
156 196141650 : const Real node_i = (*node)(i);
157 : largest_id_type Real_as_idtypes[idtypes_per_Real];
158 196141650 : std::memcpy(Real_as_idtypes, &node_i, sizeof(Real));
159 392283300 : for (unsigned int j=0; j != idtypes_per_Real; ++j)
160 215454 : *data_out++ =(Real_as_idtypes[j]);
161 : }
162 :
163 : // Add any DofObject indices
164 65380550 : node->pack_indexing(data_out);
165 :
166 : // Add any nodal boundary condition ids
167 143636 : std::vector<boundary_id_type> bcs;
168 65380550 : mesh->get_boundary_info().boundary_ids(node, bcs);
169 :
170 71818 : libmesh_assert(bcs.size() < std::numeric_limits<largest_id_type>::max());
171 :
172 130689282 : *data_out++ =(bcs.size());
173 :
174 75368654 : for (const auto & bid : bcs)
175 19947590 : *data_out++ = bid;
176 65380550 : }
177 :
178 :
179 :
180 : template <>
181 : Node *
182 151840774 : Packing<Node *>::unpack (std::vector<largest_id_type>::const_iterator in,
183 : MeshBase * mesh)
184 : {
185 : #ifndef NDEBUG
186 75958 : const std::vector<largest_id_type>::const_iterator original_in = in;
187 75958 : const largest_id_type incoming_header = *in++;
188 75958 : libmesh_assert_equal_to (incoming_header, node_magic_header);
189 : #endif
190 :
191 151840774 : const processor_id_type processor_id = cast_int<processor_id_type>(*in++);
192 75958 : libmesh_assert(processor_id == DofObject::invalid_processor_id ||
193 : processor_id < mesh->n_processors());
194 :
195 151840774 : const dof_id_type id = cast_int<dof_id_type>(*in++);
196 :
197 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
198 151840774 : const unique_id_type unique_id = cast_int<unique_id_type>(*in++);
199 : #endif
200 :
201 151840774 : Node * node = mesh->query_node_ptr(id);
202 :
203 151840774 : if (node)
204 : {
205 28524 : 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 490100076 : for (unsigned int i=0; i != LIBMESH_DIM; ++i)
216 : {
217 : Real idtypes_as_Real;
218 367575057 : std::memcpy(&idtypes_as_Real, &(*in), sizeof(Real));
219 85572 : in += idtypes_per_Real;
220 85572 : libmesh_assert_less_equal ((*node)(i), idtypes_as_Real + (std::max(Real(1),idtypes_as_Real)*TOLERANCE*TOLERANCE));
221 85572 : libmesh_assert_greater_equal ((*node)(i), idtypes_as_Real - (std::max(Real(1),idtypes_as_Real)*TOLERANCE*TOLERANCE));
222 :
223 367660629 : if (processor_id != mesh->processor_id())
224 306062661 : (*node)(i) = idtypes_as_Real;
225 : }
226 :
227 122525019 : if (!node->has_dofs())
228 : {
229 86475714 : node->unpack_indexing(in);
230 25310 : libmesh_assert_equal_to (DofObject::unpackable_indexing_size(in),
231 : node->packed_indexing_size());
232 86475714 : 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
238 36049305 : in += DofObject::unpackable_indexing_size(in);
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 29315755 : auto unode = std::make_unique<Node>();
247 :
248 117263020 : for (unsigned int i=0; i != LIBMESH_DIM; ++i)
249 : {
250 : Real idtypes_as_Real;
251 87947265 : std::memcpy(&idtypes_as_Real, &(*in), sizeof(Real));
252 87947265 : (*unode)(i) = idtypes_as_Real;
253 142302 : in += idtypes_per_Real;
254 : }
255 :
256 29315755 : unode->set_id() = id;
257 : #ifdef LIBMESH_ENABLE_UNIQUE_ID
258 47434 : unode->set_unique_id(unique_id);
259 : #endif
260 29315755 : unode->processor_id() = processor_id;
261 :
262 29315755 : unode->unpack_indexing(in);
263 47434 : libmesh_assert_equal_to (DofObject::unpackable_indexing_size(in),
264 : unode->packed_indexing_size());
265 29315755 : in += unode->packed_indexing_size();
266 :
267 29410623 : node = mesh->add_node(std::move(unode));
268 29220887 : }
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 151840774 : const largest_id_type num_bcs = *in++;
275 : // libmesh_assert_greater_equal (num_bcs, 0);
276 :
277 175099898 : for (largest_id_type bc_it=0; bc_it < num_bcs; bc_it++)
278 17584 : mesh->get_boundary_info().add_node
279 23276708 : (node, cast_int<boundary_id_type>(*in++));
280 :
281 : #ifndef NDEBUG
282 75958 : libmesh_assert (in - original_in ==
283 : cast_int<int>
284 : (Parallel::Packing<const Node*>::packed_size(original_in)));
285 : #endif
286 :
287 151840774 : 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 51288376 : 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 51288376 : pack(node, data_out, static_cast<const MeshBase*>(mesh));
303 51288376 : }
304 :
305 :
306 :
307 : template <>
308 : void
309 0 : 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 0 : pack(node, data_out, static_cast<const MeshBase*>(mesh));
314 0 : }
315 :
316 :
317 :
318 : template <>
319 : Node *
320 51288376 : Packing<Node *>::unpack (std::vector<largest_id_type>::const_iterator in,
321 : DistributedMesh * mesh)
322 : {
323 51288376 : return unpack(in, static_cast<MeshBase*>(mesh));
324 : }
325 :
326 :
327 :
328 : template <>
329 : Node *
330 0 : Packing<Node *>::unpack (std::vector<largest_id_type>::const_iterator in,
331 : ParallelMesh * mesh)
332 : {
333 0 : return unpack(in, static_cast<MeshBase*>(mesh));
334 : }
335 :
336 : } // namespace Parallel
337 :
338 : } // namespace libMesh
|