libMesh
Loading...
Searching...
No Matches
checkpoint_io.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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// Local includes
19#include "libmesh/checkpoint_io.h"
20#include "libmesh/boundary_info.h"
21#include "libmesh/cell_c0polyhedron.h"
22#include "libmesh/distributed_mesh.h"
23#include "libmesh/elem.h"
24#include "libmesh/enum_to_string.h"
25#include "libmesh/enum_xdr_mode.h"
26#include "libmesh/face_c0polygon.h"
27#include "libmesh/libmesh_logging.h"
28#include "libmesh/mesh_base.h"
29#include "libmesh/mesh_communication.h"
30#include "libmesh/mesh_tools.h"
31#include "libmesh/node.h"
32#include "libmesh/parallel.h"
33#include "libmesh/partitioner.h"
34#include "libmesh/periodic_boundaries.h"
35#include "libmesh/periodic_boundary.h"
36#include "libmesh/metis_partitioner.h"
37#include "libmesh/remote_elem.h"
38#include "libmesh/xdr_io.h"
39#include "libmesh/xdr_cxx.h"
40#include "libmesh/utility.h"
41#include "libmesh/int_range.h"
42
43// C++ includes
44#include <algorithm>
45#include <iostream>
46#include <iomanip>
47#include <cstdio>
48#include <vector>
49#include <string>
50#include <cstring>
51#include <filesystem>
52#include <fstream>
53#include <sstream> // for ostringstream
54#include <unordered_map>
55#include <unordered_set>
56#ifdef LIBMESH_HAVE_DIRECT_H
57#include <direct.h> // rmdir() on Windows
58#endif
59#ifdef LIBMESH_HAVE_UNISTD_H
60#include <unistd.h> // rmdir() on Unix
61#endif
62
63namespace
64{
65// chunking computes the number of chunks and first-chunk-offset when splitting a mesh
66// into nsplits pieces using size procs for the given MPI rank. The number of chunks and offset
67// are stored in nchunks and first_chunk respectively.
70{
71 if (nsplits % size == 0) // the chunks divide evenly over the processors
72 {
73 nchunks = nsplits / size;
74 first_chunk = libMesh::cast_int<libMesh::processor_id_type>(nchunks * rank);
75 return;
76 }
77
78 libMesh::processor_id_type nextra = nsplits % size;
79 if (rank < nextra) // leftover chunks cause an extra chunk to be added to this processor
80 {
81 nchunks = libMesh::cast_int<libMesh::processor_id_type>(nsplits / size + 1);
82 first_chunk = libMesh::cast_int<libMesh::processor_id_type>(nchunks * rank);
83 }
84 else // no extra chunks, but first chunk is offset by extras on earlier ranks
85 {
86 nchunks = nsplits / size;
87 // account for the case where nchunks is zero where we want max int
88 first_chunk = libMesh::cast_int<libMesh::processor_id_type>
89 (std::max((int)((nchunks + 1) * (nsplits % size) + nchunks * (rank - nsplits % size)),
90 (1 - (int)nchunks) * std::numeric_limits<int>::max()));
91 }
92}
93
94std::string_view extension(std::string_view s)
95{
96 auto pos = s.rfind(".");
97 if (pos == std::string::npos)
98 return "";
99 return s.substr(pos, s.size() - pos);
100}
101
102std::string split_dir(const std::string & input_name, libMesh::processor_id_type n_procs)
103{
104 return input_name + "/" + std::to_string(n_procs);
105}
106
107
108std::string header_file(const std::string & input_name, libMesh::processor_id_type n_procs)
109{
110 return (split_dir(input_name, n_procs) + "/header").append(extension(input_name));
111}
112
113std::string
114split_file(const std::string & input_name,
117{
118 return (split_dir(input_name, n_procs) + "/split-" + std::to_string(n_procs) + "-" +
119 std::to_string(proc_id)).append(extension(input_name));
120}
121
122// Report, as a comma-separated list, the processor counts for which a split
123// already exists as a numbered subdirectory of input_name, to help a user
124// pick out why the split they asked for could not be found.
125std::string existing_splits(const std::string & input_name)
126{
127 std::error_code ec;
128 if (!std::filesystem::is_directory(input_name, ec))
129 return "";
130
131 std::vector<std::string> splits;
132 for (const auto & entry : std::filesystem::directory_iterator(input_name, ec))
133 {
134 const auto name = entry.path().filename().string();
135 if (!name.empty() && name.find_first_not_of("0123456789") == std::string::npos &&
136 entry.is_directory(ec))
137 splits.push_back(name);
138 }
139 std::sort(splits.begin(), splits.end());
140
141 std::string list;
142 for (const auto & split : splits)
143 list += (list.empty() ? "" : ", ") + split;
144 return list;
145}
146
147void make_dir(const std::string & input_name, libMesh::processor_id_type n_procs)
148{
149 auto ret = libMesh::Utility::mkdir(input_name.c_str());
150 // error only if we failed to create dir - don't care if it was already there
151 libmesh_error_msg_if
152 (ret != 0 && ret != -1,
153 "Failed to create mesh split directory '" << input_name << "': " << std::strerror(ret));
154
155 auto dir_name = split_dir(input_name, n_procs);
156 ret = libMesh::Utility::mkdir(dir_name.c_str());
157 if (ret == -1)
158 libmesh_warning("In CheckpointIO::write, directory '"
159 << dir_name << "' already exists, overwriting contents.");
160 else
161 libmesh_error_msg_if
162 (ret != 0, "Failed to create mesh split directory '" << dir_name << "': " << std::strerror(ret));
163}
164
165} // namespace
166
167namespace libMesh
168{
169
170std::unique_ptr<CheckpointIO> split_mesh(MeshBase & mesh, processor_id_type nsplits)
171{
172 // There is currently an issue with DofObjects not being properly
173 // reset if the mesh is not first repartitioned onto 1 processor
174 // *before* being repartitioned onto the desired number of
175 // processors. So, this is a workaround, but not a particularly
176 // onerous one.
177 mesh.partition(1);
178 mesh.partition(nsplits);
179
180 processor_id_type my_num_chunks = 0;
181 processor_id_type my_first_chunk = 0;
182 chunking(mesh.comm().size(), mesh.comm().rank(), nsplits, my_num_chunks, my_first_chunk);
183
184 auto cpr = std::make_unique<CheckpointIO>(mesh);
185 cpr->current_processor_ids().clear();
186 for (processor_id_type i = my_first_chunk; i < my_first_chunk + my_num_chunks; i++)
187 cpr->current_processor_ids().push_back(i);
188 cpr->current_n_processors() = nsplits;
189 cpr->parallel() = true;
190 return cpr;
191}
192
193
194// ------------------------------------------------------------
195// CheckpointIO members
196CheckpointIO::CheckpointIO (MeshBase & mesh, const bool binary_in) :
197 MeshInput<MeshBase> (mesh,/* is_parallel_format = */ true),
198 MeshOutput<MeshBase>(mesh,/* is_parallel_format = */ true),
200 _binary (binary_in),
201 _parallel (false),
202 _version ("checkpoint-1.7"),
203 _my_processor_ids (1, processor_id()),
204 _my_n_processors (mesh.is_replicated() ? 1 : n_processors())
205{
206}
207
208CheckpointIO::CheckpointIO (const MeshBase & mesh, const bool binary_in) :
209 MeshInput<MeshBase> (), // write-only
210 MeshOutput<MeshBase>(mesh,/* is_parallel_format = */ true),
212 _binary (binary_in),
213 _parallel (false),
214 _version ("checkpoint-1.7"),
215 _my_processor_ids (1, processor_id()),
216 _my_n_processors (mesh.is_replicated() ? 1 : n_processors())
217{
218}
219
220CheckpointIO::~CheckpointIO () = default;
221
222processor_id_type CheckpointIO::select_split_config(const std::string & input_name, header_id_type & data_size)
223{
224 std::string header_name;
225
226 // We'll read a header file from processor 0 and broadcast.
227 if (this->processor_id() == 0)
228 {
229 header_name = header_file(input_name, _my_n_processors);
230
231 {
232 // look for header+splits with nprocs equal to _my_n_processors
233 std::ifstream in (header_name.c_str());
234 if (!in.good())
235 {
236 // otherwise fall back to a serial/single-split mesh
237 auto orig_header_name = header_name;
238 header_name = header_file(input_name, 1);
239 std::ifstream in2 (header_name.c_str());
240 const auto splits = existing_splits(input_name);
241 libmesh_error_msg_if(!in2.good(),
242 "ERROR: Neither one of the following files can be located:\n\t'"
243 << orig_header_name << "' nor\n\t'" << input_name << "'\n"
244 << "If you are running a parallel job, double check that you've "
245 << "created a split for " << _my_n_processors << " ranks.\n"
246 << "Note: One of paths above may refer to a valid directory on your "
247 << "system, however we are attempting to read a valid header file.\n"
248 << (splits.empty()
249 ? "No processor-count splits were found in '" + input_name + "'."
250 : "Splits that do exist in '" + input_name +
251 "': " + splits + "."));
252 }
253 }
254
255 Xdr io (header_name, this->binary() ? DECODE : READ);
256
257 // read the version, but don't care about it
258 std::string input_version;
259 io.data(input_version);
260
261 // read the data type
262 io.data (data_size);
263 }
264
265 this->comm().broadcast(data_size);
266 this->comm().broadcast(header_name);
267
268 // How many per-processor files are here?
269 largest_id_type input_n_procs;
270
271 switch (data_size) {
272 case 2:
273 input_n_procs = this->read_header<uint16_t>(header_name);
274 break;
275 case 4:
276 input_n_procs = this->read_header<uint32_t>(header_name);
277 break;
278 case 8:
279 input_n_procs = this->read_header<uint64_t>(header_name);
280 break;
281 default:
282 libmesh_error();
283 }
284
285 if (!input_n_procs)
286 input_n_procs = 1;
287 return cast_int<processor_id_type>(input_n_procs);
288}
289
290void CheckpointIO::cleanup(const std::string & input_name, processor_id_type n_procs)
291{
292 auto header = header_file(input_name, n_procs);
293 auto ret = std::remove(header.c_str());
294 if (ret != 0)
295 libmesh_warning("Failed to clean up checkpoint header '" << header << "': " << std::strerror(ret));
296
297 for (processor_id_type i = 0; i < n_procs; i++)
298 {
299 auto split = split_file(input_name, n_procs, i);
300 ret = std::remove(split.c_str());
301 if (ret != 0)
302 libmesh_warning("Failed to clean up checkpoint split file '" << split << "': " << std::strerror(ret));
303 }
304
305 auto dir = split_dir(input_name, n_procs);
306 ret = rmdir(dir.c_str());
307 if (ret != 0)
308 libmesh_warning("Failed to clean up checkpoint split dir '" << dir << "': " << std::strerror(ret));
309
310 // We expect that this may fail if there are other split configurations still present in this
311 // directory - so don't bother to check/warn for failure.
312 rmdir(input_name.c_str());
313}
314
315
317{
318 return
319 (this->version().find("1.5") != std::string::npos) ||
320 (this->version().find("1.6") != std::string::npos) ||
321 (this->version().find("1.7") != std::string::npos);
322}
323
324
326{
327 return
328 (this->version().find("1.6") != std::string::npos) ||
329 (this->version().find("1.7") != std::string::npos);
330}
331
332
334{
335 return (this->version().find("1.7") != std::string::npos);
336}
337
338
339void CheckpointIO::write (const std::string & name)
340{
341 LOG_SCOPE("write()", "CheckpointIO");
342
343 // convenient reference to our mesh
345
346 // FIXME: For backwards compatibility, we'll assume for now that we
347 // only want to write distributed meshes in parallel. Later we can
348 // do a gather_to_zero() and support that case too.
350
351 processor_id_type use_n_procs = 1;
352 if (_parallel)
353 use_n_procs = _my_n_processors;
354
355 std::string header_file_name = header_file(name, use_n_procs);
356 make_dir(name, use_n_procs);
357
358 // We'll write a header file from processor 0 to make it easier to do unambiguous
359 // restarts later:
360 if (this->processor_id() == 0)
361 {
362 Xdr io (header_file_name, this->binary() ? ENCODE : WRITE);
363
364 // write the version
365 io.data(_version, "# version");
366
367 // write what kind of data type we're using
368 header_id_type data_size = sizeof(largest_id_type);
369 io.data(data_size, "# integer size");
370
371 // Write out the max mesh dimension for backwards compatibility
372 // with code that sets it independently of element dimensions
373 {
374 uint16_t mesh_dimension = cast_int<uint16_t>(mesh.mesh_dimension());
375 io.data(mesh_dimension, "# dimensions");
376 }
377
378 // Write out whether or not this is serial output
379 {
380 uint16_t parallel = _parallel;
381 io.data(parallel, "# parallel");
382 }
383
384 // If we're writing out a parallel mesh then we need to write the number of processors
385 // so we can check it upon reading the file
386 if (_parallel)
387 {
389 io.data(n_procs, "# n_procs");
390 }
391
392 // write subdomain names
393 this->write_subdomain_names(io);
394
395 // write boundary id names
396 const BoundaryInfo & boundary_info = mesh.get_boundary_info();
397 write_bc_names(io, boundary_info, true); // sideset names
398 write_bc_names(io, boundary_info, false); // nodeset names
399
400 // write extra integer names
401 const bool write_extra_integers = this->version_at_least_1_5();
402
403 if (write_extra_integers)
404 {
405 largest_id_type n_node_integers = mesh.n_node_integers();
406 io.data(n_node_integers, "# n_extra_integers per node");
407
408 std::vector<std::string> node_integer_names;
409 for (unsigned int i=0; i != n_node_integers; ++i)
410 node_integer_names.push_back(mesh.get_node_integer_name(i));
411
412 io.data(node_integer_names);
413
414 largest_id_type n_elem_integers = mesh.n_elem_integers();
415 io.data(n_elem_integers, "# n_extra_integers per elem");
416
417 std::vector<std::string> elem_integer_names;
418 for (unsigned int i=0; i != n_elem_integers; ++i)
419 elem_integer_names.push_back(mesh.get_elem_integer_name(i));
420
421 io.data(elem_integer_names);
422 }
423
424 if (this->version_at_least_1_7())
426 }
427
428 // If this is a serial mesh written to a serial file then we're only
429 // going to write local data from processor 0. If this is a mesh being
430 // written in parallel then we're going to write from every
431 // processor.
432 std::vector<processor_id_type> ids_to_write;
433
434 // We're going to sort elements by pid in one pass, to avoid sending
435 // predicated iterators through the whole mesh N_p times.
436 //
437 // The data type here needs to be a non-const-pointer to whatever
438 // our element_iterator is a const-pointer to, for compatibility
439 // later.
440 typedef std::remove_const<MeshBase::const_element_iterator::value_type>::type nc_v_t;
441 std::unordered_map<processor_id_type, std::vector<nc_v_t>> elements_on_pid;
442
443 if (_parallel)
444 {
445 ids_to_write = _my_processor_ids;
446 for (processor_id_type p : ids_to_write)
447 elements_on_pid[p].clear();
448 auto eop_end = elements_on_pid.end();
449 for (auto & elem : mesh.element_ptr_range())
450 {
451 const processor_id_type p = elem->processor_id();
452 if (auto eop_it = elements_on_pid.find(p);
453 eop_it != eop_end)
454 eop_it->second.push_back(elem);
455 }
456 }
457 else if (mesh.is_serial())
458 {
459 if (mesh.processor_id() == 0)
460 {
461 // placeholder
462 ids_to_write.push_back(0);
463 }
464 }
465 else
466 {
467 libmesh_error_msg("Cannot write serial checkpoint from distributed mesh");
468 }
469
470 // Call build_side_list() and build_node_list() just *once* to avoid
471 // redundant expensive sorts during mesh splitting.
472 const BoundaryInfo & boundary_info = mesh.get_boundary_info();
473 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
474 bc_triples = boundary_info.build_side_list();
475 std::vector<std::tuple<dof_id_type, boundary_id_type>>
476 bc_tuples = boundary_info.build_node_list();
477
478 for (const auto & my_pid : ids_to_write)
479 {
480 auto file_name = split_file(name, use_n_procs, my_pid);
481 Xdr io (file_name, this->binary() ? ENCODE : WRITE);
482
483 std::set<const Elem *, CompareElemIdsByLevel> elements;
484
485 // For serial files or for already-distributed meshs, we write
486 // everything we can see.
487 if (!_parallel || !mesh.is_serial())
488 elements.insert(mesh.elements_begin(), mesh.elements_end());
489 // For parallel files written from serial meshes we write what
490 // we'd be required to keep if we were to be deleting remote
491 // elements. This allows us to write proper parallel files even
492 // from a ReplicateMesh.
493 //
494 // WARNING: If we have a DistributedMesh which used
495 // "add_extra_ghost_elem" rather than ghosting functors to
496 // preserve elements and which is *also* currently serialized
497 // then we're not preserving those elements here. As a quick
498 // workaround user code should delete_remote_elements() before
499 // writing the checkpoint; as a long term workaround user code
500 // should use ghosting functors instead of extra_ghost_elem
501 // lists.
502 else
503 {
505 {
506 if (const auto elements_vec_it = elements_on_pid.find(p);
507 elements_vec_it != elements_on_pid.end())
508 {
509 auto & p_elements = elements_vec_it->second;
510
511 // Be compatible with both deprecated and
512 // corrected MeshBase iterator types
514
515 v_t * elempp = p_elements.data();
516 v_t * elemend = elempp + p_elements.size();
517
519 pid_elements_begin = MeshBase::const_element_iterator
520 (elempp, elemend, Predicates::NotNull<v_t *>()),
521 pid_elements_end = MeshBase::const_element_iterator
522 (elemend, elemend, Predicates::NotNull<v_t *>()),
523 active_pid_elements_begin = MeshBase::const_element_iterator
524 (elempp, elemend, Predicates::Active<v_t *>()),
525 active_pid_elements_end = MeshBase::const_element_iterator
526 (elemend, elemend, Predicates::Active<v_t *>());
527
529 (mesh, p, active_pid_elements_begin,
530 active_pid_elements_end, elements);
531 connect_children(mesh, pid_elements_begin,
532 pid_elements_end, elements);
533 }
534 }
535 }
536
537 connected_node_set_type connected_nodes;
538 connect_element_dependencies(mesh, elements, connected_nodes);
539
540 // write the nodal locations
541 this->write_nodes (io, connected_nodes);
542
543 // write connectivity
544 this->write_connectivity (io, elements);
545
546 // write remote_elem connectivity
547 this->write_remote_elem (io, elements);
548
549 // write the boundary condition information
550 this->write_bcs (io, elements, bc_triples);
551
552 // write the nodeset information
553 this->write_nodesets (io, connected_nodes, bc_tuples);
554
555 // close it up
556 io.close();
557 }
558
559 // this->comm().barrier();
560}
561
563{
564 {
566
567 const std::map<subdomain_id_type, std::string> & subdomain_map = mesh.get_subdomain_name_map();
568
569 std::vector<largest_id_type> subdomain_ids; subdomain_ids.reserve(subdomain_map.size());
570 std::vector<std::string> subdomain_names; subdomain_names.reserve(subdomain_map.size());
571
572 // We need to loop over the map and make sure that there aren't any invalid entries. Since we
573 // return writable references in mesh_base, it's possible for the user to leave some entity names
574 // blank. We can't write those to the XDA file.
575 largest_id_type n_subdomain_names = 0;
576 for (const auto & [id, name] : subdomain_map)
577 if (!name.empty())
578 {
579 n_subdomain_names++;
580 subdomain_ids.push_back(id);
581 subdomain_names.push_back(name);
582 }
583
584 io.data(n_subdomain_names, "# subdomain id to name map");
585 // Write out the ids and names in two vectors
586 if (n_subdomain_names)
587 {
588 io.data(subdomain_ids);
589 io.data(subdomain_names);
590 }
591 }
592}
593
594
595
597 const connected_node_set_type & nodeset) const
598{
599 largest_id_type n_nodes_here = nodeset.size();
600
601 io.data(n_nodes_here, "# n_nodes on proc");
602
603 const bool write_extra_integers = this->version_at_least_1_5();
604 const unsigned int n_extra_integers =
605 write_extra_integers ? MeshOutput<MeshBase>::mesh().n_node_integers() : 0;
606
607 // Will hold the node id and pid and extra integers
608 std::vector<largest_id_type> id_pid(2 + n_extra_integers);
609
610 // For the coordinates
611 std::vector<Real> coords(LIBMESH_DIM);
612
613 for (const auto & node : nodeset)
614 {
615 id_pid[0] = node->id();
616 id_pid[1] = node->processor_id();
617
618 libmesh_assert_equal_to(n_extra_integers, node->n_extra_integers());
619 for (unsigned int i=0; i != n_extra_integers; ++i)
620 id_pid[2+i] = node->get_extra_integer(i);
621
622 io.data_stream(id_pid.data(), 2 + n_extra_integers, 2 + n_extra_integers);
623
624#ifdef LIBMESH_ENABLE_UNIQUE_ID
625 largest_id_type unique_id = node->unique_id();
626
627 io.data(unique_id, "# unique id");
628#endif
629
630 coords[0] = (*node)(0);
631
632#if LIBMESH_DIM > 1
633 coords[1] = (*node)(1);
634#endif
635
636#if LIBMESH_DIM > 2
637 coords[2] = (*node)(2);
638#endif
639
640 io.data_stream(coords.data(), LIBMESH_DIM, 3);
641 }
642}
643
644
645
647 const std::set<const Elem *, CompareElemIdsByLevel> & elements) const
648{
649 libmesh_assert (io.writing());
650
651 const bool write_extra_integers = this->version_at_least_1_5();
652 const bool write_runtime_topology = this->version_at_least_1_6();
653 const unsigned int n_extra_integers =
654 write_extra_integers ? MeshOutput<MeshBase>::mesh().n_elem_integers() : 0;
655
656 // Put these out here to reduce memory churn
657 // id type pid subdomain_id parent_id extra_integer_0 ...
658 std::vector<largest_id_type> elem_data(6 + n_extra_integers);
659 std::vector<largest_id_type> conn_data;
660 std::vector<largest_id_type> runtime_topology;
661
662 largest_id_type n_elems_here = elements.size();
663
664 io.data(n_elems_here, "# number of elements");
665
666 for (const auto & elem : elements)
667 {
668 unsigned int n_nodes = elem->n_nodes();
669
670 elem_data[0] = elem->id();
671 elem_data[1] = elem->type();
672 elem_data[2] = elem->processor_id();
673 elem_data[3] = elem->subdomain_id();
674
675#ifdef LIBMESH_ENABLE_AMR
676 if (elem->parent() != nullptr)
677 {
678 elem_data[4] = elem->parent()->id();
679 elem_data[5] = elem->parent()->which_child_am_i(elem);
680 }
681 else
682#endif
683 {
684 elem_data[4] = static_cast<largest_id_type>(-1);
685 elem_data[5] = static_cast<largest_id_type>(-1);
686 }
687
688 for (unsigned int i=0; i != n_extra_integers; ++i)
689 elem_data[6+i] = elem->get_extra_integer(i);
690
691 conn_data.resize(n_nodes);
692
693 for (unsigned int i=0; i<n_nodes; i++)
694 conn_data[i] = elem->node_id(i);
695
696 io.data_stream(elem_data.data(),
697 cast_int<unsigned int>(elem_data.size()),
698 cast_int<unsigned int>(elem_data.size()));
699
700#ifdef LIBMESH_ENABLE_UNIQUE_ID
701 largest_id_type unique_id = elem->unique_id();
702
703 io.data(unique_id, "# unique id");
704#endif
705
706#ifdef LIBMESH_ENABLE_AMR
707 uint16_t p_level = cast_int<uint16_t>(elem->p_level());
708 io.data(p_level, "# p_level");
709
710 uint16_t rflag = elem->refinement_flag();
711 io.data(rflag, "# rflag");
712
713 uint16_t pflag = elem->p_refinement_flag();
714 io.data(pflag, "# pflag");
715#endif
716
717 if (elem->runtime_topology())
718 {
719 libmesh_error_msg_if
720 (!write_runtime_topology,
721 "Checkpoint format 1.6 or newer is required to write " <<
722 Utility::enum_to_string(elem->type()) << " elements.");
723
724 runtime_topology.clear();
725 runtime_topology.push_back(n_nodes);
726 runtime_topology.push_back(elem->n_sides());
727 for (auto s : elem->side_index_range())
728 {
729 const auto side_nodes = elem->nodes_on_side(s);
730 runtime_topology.push_back(side_nodes.size());
731 for (const auto n : side_nodes)
732 runtime_topology.push_back(n);
733 }
734
735 io.data(runtime_topology, "# runtime topology");
736 }
737
738 io.data_stream(conn_data.data(),
739 cast_int<unsigned int>(conn_data.size()),
740 cast_int<unsigned int>(conn_data.size()));
741 }
742}
743
744
746 const std::set<const Elem *, CompareElemIdsByLevel> & elements) const
747{
748 libmesh_assert (io.writing());
749
750 // Find the remote_elem neighbor and child links
751 std::vector<largest_id_type> elem_ids, parent_ids;
752 std::vector<uint16_t> elem_sides, child_numbers;
753
754 for (const auto & elem : elements)
755 {
756 for (auto n : elem->side_index_range())
757 {
758 const Elem * neigh = elem->neighbor_ptr(n);
759 if (neigh == remote_elem ||
760 (neigh && !elements.count(neigh)))
761 {
762 elem_ids.push_back(elem->id());
763 elem_sides.push_back(n);
764 }
765 }
766
767#ifdef LIBMESH_ENABLE_AMR
768 if (elem->has_children())
769 {
770 for (unsigned short c = 0,
771 nc = cast_int<unsigned short>(elem->n_children());
772 c != nc; ++c)
773 {
774 const Elem * child = elem->child_ptr(c);
775 if (child == remote_elem ||
776 (child && !elements.count(child)))
777 {
778 parent_ids.push_back(elem->id());
779 child_numbers.push_back(c);
780 }
781 }
782 }
783#endif
784 }
785
786 io.data(elem_ids, "# remote neighbor elem_ids");
787 io.data(elem_sides, "# remote neighbor elem_sides");
788 io.data(parent_ids, "# remote child parent_ids");
789 io.data(child_numbers, "# remote child_numbers");
790}
791
792
793
795 const std::set<const Elem *, CompareElemIdsByLevel> & elements,
796 const std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> & bc_triples) const
797{
798 libmesh_assert (io.writing());
799
800 // Build a list of (elem, side, bc) tuples.
801 std::size_t bc_size = bc_triples.size();
802
803 std::vector<largest_id_type> element_id_list;
804 std::vector<uint16_t> side_list;
805 std::vector<largest_id_type> bc_id_list;
806
807 element_id_list.reserve(bc_size);
808 side_list.reserve(bc_size);
809 bc_id_list.reserve(bc_size);
810
811 std::unordered_set<dof_id_type> elems;
812 for (auto & e : elements)
813 elems.insert(e->id());
814
815 for (const auto & t : bc_triples)
816 if (elems.count(std::get<0>(t)))
817 {
818 element_id_list.push_back(std::get<0>(t));
819 side_list.push_back(std::get<1>(t));
820 bc_id_list.push_back(std::get<2>(t));
821 }
822
823
824 io.data(element_id_list, "# element ids for bcs");
825 io.data(side_list, "# sides of elements for bcs");
826 io.data(bc_id_list, "# bc ids");
827}
828
829
830
832 const connected_node_set_type & nodeset,
833 const std::vector<std::tuple<dof_id_type, boundary_id_type>> & bc_tuples) const
834{
835 libmesh_assert (io.writing());
836
837 // convenient reference to our mesh
839
840 // Build a list of (node, bc) tuples
841 std::size_t nodeset_size = bc_tuples.size();
842
843 std::vector<largest_id_type> node_id_list;
844 std::vector<largest_id_type> bc_id_list;
845
846 node_id_list.reserve(nodeset_size);
847 bc_id_list.reserve(nodeset_size);
848
849 for (const auto & t : bc_tuples)
850 if (nodeset.count(mesh.node_ptr(std::get<0>(t))))
851 {
852 node_id_list.push_back(std::get<0>(t));
853 bc_id_list.push_back(std::get<1>(t));
854 }
855
856 io.data(node_id_list, "# node id list");
857 io.data(bc_id_list, "# nodeset bc id list");
858}
859
860
861
862void CheckpointIO::write_bc_names (Xdr & io, const BoundaryInfo & info, bool is_sideset) const
863{
864 const std::map<boundary_id_type, std::string> & boundary_map = is_sideset ?
865 info.get_sideset_name_map() : info.get_nodeset_name_map();
866
867 std::vector<largest_id_type> boundary_ids; boundary_ids.reserve(boundary_map.size());
868 std::vector<std::string> boundary_names; boundary_names.reserve(boundary_map.size());
869
870 // We need to loop over the map and make sure that there aren't any invalid entries. Since we
871 // return writable references in boundary_info, it's possible for the user to leave some entity names
872 // blank. We can't write those to the XDA file.
873 largest_id_type n_boundary_names = 0;
874 for (const auto & [id, name] : boundary_map)
875 if (!name.empty())
876 {
877 n_boundary_names++;
878 boundary_ids.push_back(id);
879 boundary_names.push_back(name);
880 }
881
882 if (is_sideset)
883 io.data(n_boundary_names, "# sideset id to name map");
884 else
885 io.data(n_boundary_names, "# nodeset id to name map");
886 // Write out the ids and names in two vectors
887 if (n_boundary_names)
888 {
889 io.data(boundary_ids);
890 io.data(boundary_names);
891 }
892}
893
895{
896 std::vector<largest_id_type> pair_ids;
897 std::vector<Real> translations;
898
899#ifdef LIBMESH_ENABLE_PERIODIC
901
902 // MeshBase stores each pair once per direction; write each pair once,
903 // from its smaller boundary id, and re-register both directions on read.
905 for (const auto & [id, pb] : *db)
906 {
907 if (id > pb->pairedboundary)
908 continue;
909
910 // MeshBase only registers translations, which we can recover
911 // as the image of the origin.
912 libmesh_error_msg_if(!dynamic_cast<const PeriodicBoundary *>(pb.get()) ||
914 "CheckpointIO can only write translational disjoint neighbor "
915 "boundary pairs");
916
917 pair_ids.push_back(id);
918 pair_ids.push_back(pb->pairedboundary);
919
920 const Point translation = pb->get_corresponding_pos(Point(0));
921 for (auto d : make_range(LIBMESH_DIM))
922 translations.push_back(translation(d));
923 }
924#endif
925
926 largest_id_type n_pairs = pair_ids.size() / 2;
927 io.data(n_pairs, "# disjoint neighbor boundary pairs");
928 if (n_pairs)
929 {
930 io.data(pair_ids);
931 // data_stream, unlike the generic vector path, handles extended
932 // precision Real
933 io.data_stream(translations.data(),
934 cast_int<unsigned int>(translations.size()),
935 LIBMESH_DIM);
936 }
937}
938
939void CheckpointIO::read (const std::string & input_name)
940{
941 LOG_SCOPE("read()","CheckpointIO");
942
944
946
947 header_id_type data_size;
948 processor_id_type input_n_procs = select_split_config(input_name, data_size);
949 auto header_name = header_file(input_name, input_n_procs);
950 bool input_parallel = input_n_procs > 0;
951
952 // If this is a serial read then we're going to only read the mesh
953 // on processor 0, then broadcast it
954 if ((input_parallel && !mesh.is_replicated()) || mesh.processor_id() == 0)
955 {
956 // If we're trying to read a parallel checkpoint file on a
957 // replicated mesh, we'll read every file on processor 0 so we
958 // can broadcast it later. If we're on a distributed mesh then
959 // we'll read every id to it's own processor and we'll "wrap
960 // around" with any ids that exceed our processor count.
961 const processor_id_type begin_proc_id =
962 (input_parallel && !mesh.is_replicated()) ?
963 mesh.processor_id() : 0;
964 const processor_id_type stride =
965 (input_parallel && !mesh.is_replicated()) ?
966 mesh.n_processors() : 1;
967
968 for (processor_id_type proc_id = begin_proc_id; proc_id < input_n_procs;
969 proc_id = cast_int<processor_id_type>(proc_id + stride))
970 {
971 auto file_name = split_file(input_name, input_n_procs, proc_id);
972
973 {
974 std::ifstream in (file_name.c_str());
975
976 libmesh_error_msg_if(!in.good(), "ERROR: cannot locate specified file:\n\t" << file_name);
977 }
978
979 // Do we expect all our files' remote_elem entries to really
980 // be remote? Only if we're not reading multiple input
981 // files on the same processor.
982 const bool expect_all_remote =
983 (input_n_procs <= mesh.n_processors() &&
985
986 Xdr io (file_name, this->binary() ? DECODE : READ);
987
988 switch (data_size) {
989 case 2:
990 this->read_subfile<uint16_t>(io, expect_all_remote);
991 break;
992 case 4:
993 this->read_subfile<uint32_t>(io, expect_all_remote);
994 break;
995 case 8:
996 this->read_subfile<uint64_t>(io, expect_all_remote);
997 break;
998 default:
999 libmesh_error();
1000 }
1001
1002 io.close();
1003 }
1004 }
1005
1006 // If the mesh was only read on processor 0 then we need to broadcast it
1007 if (mesh.is_replicated())
1009 // If the mesh is really distributed then we need to make sure it
1010 // knows that
1011 else if (mesh.n_processors() > 1)
1013
1014 // If the mesh isn't getting even critical partitioning then we
1015 // should update cached data from the partitioning we just read in
1016 if (mesh.skip_partitioning())
1017 {
1020 }
1021}
1022
1023
1024
1025template <typename file_id_type>
1026file_id_type CheckpointIO::read_header (const std::string & name)
1027{
1029
1030 // Hack for codes which don't look at all elem dimensions
1031 uint16_t mesh_dimension;
1032
1033 // Will this be a parallel input file? With how many processors? Stay tuned!
1034 uint16_t input_parallel;
1035 file_id_type input_n_procs;
1036
1037 std::string input_version;
1038 std::vector<std::string> node_integer_names, elem_integer_names;
1039 std::vector<file_id_type> disjoint_pair_ids;
1040 std::vector<Real> disjoint_translations;
1041
1042 // We'll write a header file from processor 0 and broadcast.
1043 if (this->processor_id() == 0)
1044 {
1045 Xdr io (name, this->binary() ? DECODE : READ);
1046
1047 // read the version
1048 io.data(input_version);
1049
1050 // read the data type, don't care about it this time
1051 header_id_type data_size;
1052 io.data (data_size);
1053
1054 // read the dimension
1055 io.data (mesh_dimension);
1056
1057 // Read whether or not this is a parallel file
1058 io.data(input_parallel);
1059
1060 // With how many processors?
1061 if (input_parallel)
1062 io.data(input_n_procs);
1063
1064 // read subdomain names
1065 this->read_subdomain_names<file_id_type>(io);
1066
1067 // read boundary names
1068 BoundaryInfo & boundary_info = mesh.get_boundary_info();
1069
1070 this->read_bc_names<file_id_type>(io, boundary_info, true); // sideset names
1071 this->read_bc_names<file_id_type>(io, boundary_info, false); // nodeset names
1072
1073 // read extra integer names?
1074 std::swap(input_version, this->version());
1075 const bool read_extra_integers = this->version_at_least_1_5();
1076 std::swap(input_version, this->version());
1077
1078 if (read_extra_integers)
1079 this->read_integers_names<file_id_type>
1080 (io, node_integer_names, elem_integer_names);
1081
1082 std::swap(input_version, this->version());
1083 const bool read_disjoint_pairs = this->version_at_least_1_7();
1084 std::swap(input_version, this->version());
1085
1086 if (read_disjoint_pairs)
1087 this->read_disjoint_neighbor_boundary_pairs<file_id_type>
1088 (io, disjoint_pair_ids, disjoint_translations);
1089 }
1090
1091 // broadcast data from processor 0, set values everywhere
1092 this->comm().broadcast(input_version);
1093 this->version() = input_version;
1094
1095 this->comm().broadcast(mesh_dimension);
1096 mesh.set_mesh_dimension(cast_int<unsigned char>(mesh_dimension));
1097
1098 this->comm().broadcast(input_parallel);
1099
1100 if (input_parallel)
1101 this->comm().broadcast(input_n_procs);
1102 else
1103 input_n_procs = 1;
1104
1105 std::map<subdomain_id_type, std::string> & subdomain_map =
1107 this->comm().broadcast(subdomain_map);
1108
1109 BoundaryInfo & boundary_info = mesh.get_boundary_info();
1110 this->comm().broadcast(boundary_info.set_sideset_name_map());
1111 this->comm().broadcast(boundary_info.set_nodeset_name_map());
1112
1113 this->comm().broadcast(node_integer_names);
1114 this->comm().broadcast(elem_integer_names);
1115
1116 for (auto & int_name : node_integer_names)
1117 mesh.add_node_integer(int_name);
1118
1119 for (auto & int_name : elem_integer_names)
1120 mesh.add_elem_integer(int_name);
1121
1122 this->comm().broadcast(disjoint_pair_ids);
1123 this->comm().broadcast(disjoint_translations);
1124
1125#ifdef LIBMESH_ENABLE_PERIODIC
1126 // The file is the complete record of the pairs, so it replaces any
1127 // pairs left on a reused mesh rather than merging with them
1128 if (this->version_at_least_1_7())
1130 db->clear();
1131
1132 for (auto i : make_range(disjoint_pair_ids.size() / 2))
1133 {
1134 RealVectorValue translation;
1135 for (auto d : make_range(LIBMESH_DIM))
1136 translation(d) = disjoint_translations[LIBMESH_DIM * i + d];
1138 (cast_int<boundary_id_type>(disjoint_pair_ids[2 * i]),
1139 cast_int<boundary_id_type>(disjoint_pair_ids[2 * i + 1]),
1140 translation);
1141 }
1142#else
1143 libmesh_error_msg_if(!disjoint_pair_ids.empty(),
1144 "Reading disjoint neighbor boundary pairs requires --enable-periodic");
1145#endif
1146
1147 return input_parallel ? input_n_procs : 0;
1148}
1149
1150
1151
1152template <typename file_id_type>
1153void CheckpointIO::read_subfile (Xdr & io, bool expect_all_remote)
1154{
1155 // read the nodal locations
1156 this->read_nodes<file_id_type> (io);
1157
1158 // read connectivity
1159 this->read_connectivity<file_id_type> (io);
1160
1161 // read remote_elem connectivity
1162 this->read_remote_elem<file_id_type> (io, expect_all_remote);
1163
1164 // read the boundary conditions
1165 this->read_bcs<file_id_type> (io);
1166
1167 // read the nodesets
1168 this->read_nodesets<file_id_type> (io);
1169}
1170
1171
1172
1173template <typename file_id_type>
1175{
1177
1178 std::map<subdomain_id_type, std::string> & subdomain_map =
1180
1181 std::vector<file_id_type> subdomain_ids;
1182 subdomain_ids.reserve(subdomain_map.size());
1183
1184 std::vector<std::string> subdomain_names;
1185 subdomain_names.reserve(subdomain_map.size());
1186
1187 file_id_type n_subdomain_names = 0;
1188 io.data(n_subdomain_names, "# subdomain id to name map");
1189
1190 if (n_subdomain_names)
1191 {
1192 io.data(subdomain_ids);
1193 io.data(subdomain_names);
1194
1195 for (auto i : index_range(subdomain_ids))
1196 subdomain_map[cast_int<subdomain_id_type>(subdomain_ids[i])] =
1197 subdomain_names[i];
1198 }
1199}
1200
1201
1202
1203template <typename file_id_type>
1205{
1206 // convenient reference to our mesh
1208
1209 file_id_type n_nodes_here;
1210 io.data(n_nodes_here, "# n_nodes on proc");
1211
1212 const bool read_extra_integers = this->version_at_least_1_5();
1213
1214 const unsigned int n_extra_integers =
1215 read_extra_integers ? mesh.n_node_integers() : 0;
1216
1217 // Will hold the node id and pid and extra integers
1218 std::vector<file_id_type> id_pid(2 + n_extra_integers);
1219
1220 // For the coordinates
1221 std::vector<Real> coords(LIBMESH_DIM);
1222
1223 for (unsigned int i=0; i<n_nodes_here; i++)
1224 {
1225 io.data_stream(id_pid.data(), 2 + n_extra_integers, 2 + n_extra_integers);
1226
1227#ifdef LIBMESH_ENABLE_UNIQUE_ID
1228 file_id_type unique_id = 0;
1229 io.data(unique_id, "# unique id");
1230#endif
1231
1232 io.data_stream(coords.data(), LIBMESH_DIM, LIBMESH_DIM);
1233
1234 Point p;
1235 p(0) = coords[0];
1236
1237#if LIBMESH_DIM > 1
1238 p(1) = coords[1];
1239#endif
1240
1241#if LIBMESH_DIM > 2
1242 p(2) = coords[2];
1243#endif
1244
1245 const dof_id_type id = cast_int<dof_id_type>(id_pid[0]);
1246
1247 // "Wrap around" if we see more processors than we're using.
1248 processor_id_type pid =
1249 cast_int<processor_id_type>(id_pid[1] % mesh.n_processors());
1250
1251 // If we already have this node (e.g. from another file, when
1252 // reading multiple distributed CheckpointIO files into a
1253 // ReplicatedMesh) then we don't want to add it again (because
1254 // ReplicatedMesh can't handle that) but we do want to assert
1255 // consistency between what we're reading and what we have.
1256 const Node * old_node = mesh.query_node_ptr(id);
1257
1258 if (old_node)
1259 {
1260 libmesh_assert_equal_to(pid, old_node->processor_id());
1261
1262 libmesh_assert_equal_to(n_extra_integers, old_node->n_extra_integers());
1263#ifndef NDEBUG
1264 for (unsigned int ei=0; ei != n_extra_integers; ++ei)
1265 {
1266 const dof_id_type extra_int = cast_int<dof_id_type>(id_pid[2+ei]);
1267 libmesh_assert_equal_to(extra_int, old_node->get_extra_integer(ei));
1268 }
1269#endif
1270
1271#ifdef LIBMESH_ENABLE_UNIQUE_ID
1272 libmesh_assert_equal_to(unique_id, old_node->unique_id());
1273#endif
1274 }
1275 else
1276 {
1277 Node * node =
1278 mesh.add_point(p, id, pid);
1279
1280#ifdef LIBMESH_ENABLE_UNIQUE_ID
1281 node->set_unique_id(unique_id);
1282#endif
1283
1284 libmesh_assert_equal_to(n_extra_integers, node->n_extra_integers());
1285
1286 for (unsigned int ei=0; ei != n_extra_integers; ++ei)
1287 {
1288 const dof_id_type extra_int = cast_int<dof_id_type>(id_pid[2+ei]);
1289 node->set_extra_integer(ei, extra_int);
1290 }
1291 }
1292 }
1293}
1294
1295
1296
1297template <typename file_id_type>
1299{
1300 // convenient reference to our mesh
1302
1303 const bool read_extra_integers = this->version_at_least_1_5();
1304 const bool read_runtime_topology = this->version_at_least_1_6();
1305
1306 const unsigned int n_extra_integers =
1307 read_extra_integers ? mesh.n_elem_integers() : 0;
1308
1309 file_id_type n_elems_here;
1310 io.data(n_elems_here);
1311
1312 // Keep track of the highest dimensional element we've added to the mesh
1313 unsigned int highest_elem_dim = mesh.mesh_dimension();
1314
1315 // RHS: Originally we used invalid_processor_id as a "no parent" tag
1316 // number, because I'm an idiot. Let's try to support broken files
1317 // as much as possible.
1318 bool file_is_broken = false;
1319
1320 for (unsigned int i=0; i<n_elems_here; i++)
1321 {
1322 // id type pid subdomain_id parent_id
1323 std::vector<file_id_type> elem_data(6 + n_extra_integers);
1324 io.data_stream
1325 (elem_data.data(), cast_int<unsigned int>(elem_data.size()),
1326 cast_int<unsigned int>(elem_data.size()));
1327
1328#ifdef LIBMESH_ENABLE_UNIQUE_ID
1329 file_id_type unique_id = 0;
1330 io.data(unique_id, "# unique id");
1331#endif
1332
1333#ifdef LIBMESH_ENABLE_AMR
1334 uint16_t p_level = 0;
1335 io.data(p_level, "# p_level");
1336
1337 uint16_t rflag, pflag;
1338 io.data(rflag, "# rflag");
1339 io.data(pflag, "# pflag");
1340#endif
1341
1342 const ElemType elem_type =
1343 static_cast<ElemType>(elem_data[1]);
1344 const bool is_c0polygon = (elem_type == C0POLYGON);
1345 const bool is_c0polyhedron = (elem_type == C0POLYHEDRON);
1346
1347 unsigned int n_nodes = Elem::type_to_n_nodes_map[elem_data[1]];
1348 // Runtime-topology types have no fixed node count in this map.
1349 const bool has_runtime_topology = (n_nodes == invalid_uint);
1350 std::vector<std::vector<unsigned int>> nodes_on_sides;
1351
1352 if (has_runtime_topology)
1353 {
1354 libmesh_error_msg_if
1355 (!read_runtime_topology,
1356 "Checkpoint format 1.6 or newer is required to read " <<
1357 Utility::enum_to_string(elem_type) << " elements.");
1358
1359 std::vector<file_id_type> runtime_topology;
1360 io.data(runtime_topology, "# runtime topology");
1361 libmesh_error_msg_if(runtime_topology.size() < 2,
1362 "Invalid runtime element topology.");
1363
1364 std::size_t topology_index = 0;
1365 n_nodes =
1366 cast_int<unsigned int>(runtime_topology[topology_index++]);
1367 const unsigned int n_sides =
1368 cast_int<unsigned int>(runtime_topology[topology_index++]);
1369 nodes_on_sides.resize(n_sides);
1370
1371 for (auto s : index_range(nodes_on_sides))
1372 {
1373 libmesh_error_msg_if
1374 (topology_index == runtime_topology.size(),
1375 "Incomplete runtime element checkpoint topology.");
1376
1377 const unsigned int n_side_nodes =
1378 cast_int<unsigned int>(runtime_topology[topology_index++]);
1379 libmesh_error_msg_if
1380 (n_side_nodes > runtime_topology.size() - topology_index,
1381 "Invalid runtime element side checkpoint topology.");
1382
1383 auto & side_nodes = nodes_on_sides[s];
1384 side_nodes.resize(n_side_nodes);
1385 for (auto n : index_range(side_nodes))
1386 {
1387 const unsigned int local_node =
1388 cast_int<unsigned int>(runtime_topology[topology_index++]);
1389 libmesh_error_msg_if
1390 (local_node >= n_nodes,
1391 "Runtime element side checkpoint topology references "
1392 "an invalid local node.");
1393 side_nodes[n] = local_node;
1394 }
1395 }
1396
1397 libmesh_error_msg_if
1398 (topology_index != runtime_topology.size(),
1399 "Extra data in runtime element checkpoint topology.");
1400
1401 if (is_c0polygon)
1402 {
1403 libmesh_error_msg_if
1404 (n_nodes < 3 || n_sides != n_nodes,
1405 "Invalid C0POLYGON checkpoint topology.");
1406 for (const auto & side_nodes : nodes_on_sides)
1407 libmesh_error_msg_if
1408 (side_nodes.size() != 2,
1409 "Invalid C0POLYGON side checkpoint topology.");
1410 }
1411 else if (is_c0polyhedron)
1412 {
1413 libmesh_error_msg_if(n_sides < 4,
1414 "Invalid C0POLYHEDRON checkpoint topology.");
1415 for (const auto & side_nodes : nodes_on_sides)
1416 libmesh_error_msg_if
1417 (side_nodes.size() < 3,
1418 "Invalid C0POLYHEDRON side checkpoint topology.");
1419 }
1420 }
1421
1422 // Snag the node ids this element was connected to
1423 std::vector<file_id_type> conn_data(n_nodes);
1424 io.data_stream
1425 (conn_data.data(), cast_int<unsigned int>(conn_data.size()),
1426 cast_int<unsigned int>(conn_data.size()));
1427
1428 const dof_id_type id =
1429 cast_int<dof_id_type> (elem_data[0]);
1430 const processor_id_type proc_id =
1431 cast_int<processor_id_type>
1432 (elem_data[2] % mesh.n_processors());
1433 const subdomain_id_type subdomain_id =
1434 restrict_int<subdomain_id_type>(elem_data[3]);
1435
1436 // Old broken files used processsor_id_type(-1)...
1437 // But we *know* our first element will be level 0
1438 if (i == 0 && elem_data[4] == 65535)
1439 file_is_broken = true;
1440
1441 // On a broken file we can't tell whether a parent of 65535 is a
1442 // null parent or an actual parent of 65535. Assuming the
1443 // former will cause less breakage.
1444 Elem * parent =
1445 (elem_data[4] == static_cast<largest_id_type>(-1) ||
1446 (file_is_broken && elem_data[4] == 65535)) ?
1447 nullptr : mesh.elem_ptr(cast_int<dof_id_type>(elem_data[4]));
1448
1449 const unsigned short int child_num =
1450 (elem_data[5] == static_cast<largest_id_type>(-1) ||
1451 (file_is_broken && elem_data[5] == 65535)) ?
1452 static_cast<unsigned short>(-1) :
1453 cast_int<unsigned short>(elem_data[5]);
1454
1455 if (!parent)
1456 libmesh_assert_equal_to
1457 (child_num, static_cast<unsigned short>(-1));
1458
1459 Elem * old_elem = mesh.query_elem_ptr(id);
1460
1461 // If we already have this element (e.g. from another file,
1462 // when reading multiple distributed CheckpointIO files into
1463 // a ReplicatedMesh) then we don't want to add it again
1464 // (because ReplicatedMesh can't handle that) but we do want
1465 // to assert consistency between what we're reading and what
1466 // we have.
1467 if (old_elem)
1468 {
1469 libmesh_assert_equal_to(elem_type, old_elem->type());
1470 libmesh_assert_equal_to(proc_id, old_elem->processor_id());
1471 libmesh_assert_equal_to(subdomain_id, old_elem->subdomain_id());
1472 if (parent)
1473 libmesh_assert_equal_to(parent, old_elem->parent());
1474 else
1475 libmesh_assert(!old_elem->parent());
1476
1477 libmesh_assert_equal_to(n_extra_integers, old_elem->n_extra_integers());
1478#ifndef NDEBUG
1479 for (unsigned int ei=0; ei != n_extra_integers; ++ei)
1480 {
1481 const dof_id_type extra_int = cast_int<dof_id_type>(elem_data[6+ei]);
1482 libmesh_assert_equal_to(extra_int, old_elem->get_extra_integer(ei));
1483 }
1484#endif
1485
1486 libmesh_assert_equal_to(old_elem->n_nodes(), conn_data.size());
1487
1488 for (unsigned int n=0,
1489 n_conn = cast_int<unsigned int>(conn_data.size());
1490 n != n_conn; n++)
1491 libmesh_assert_equal_to
1492 (old_elem->node_id(n),
1493 cast_int<dof_id_type>(conn_data[n]));
1494
1495 if (has_runtime_topology)
1496 {
1497 libmesh_assert_equal_to(old_elem->n_sides(),
1498 nodes_on_sides.size());
1499#ifndef NDEBUG
1500 for (auto s : index_range(nodes_on_sides))
1501 libmesh_assert(old_elem->nodes_on_side(s) ==
1502 nodes_on_sides[s]);
1503#endif
1504 }
1505 }
1506 else
1507 {
1508 // Create the element
1509 std::unique_ptr<Elem> elem;
1510 std::unique_ptr<Node> generated_mid_elem_node;
1511
1512 if (is_c0polygon)
1513 elem = std::make_unique<C0Polygon>(n_nodes, parent);
1514 else if (is_c0polyhedron)
1515 {
1516 std::vector<std::shared_ptr<Polygon>> sides(nodes_on_sides.size());
1517 for (auto s : index_range(nodes_on_sides))
1518 {
1519 const auto & side_node_indices = nodes_on_sides[s];
1520 auto side =
1521 std::make_shared<C0Polygon>
1522 (cast_int<unsigned int>(side_node_indices.size()));
1523 for (auto n : index_range(side_node_indices))
1524 side->set_node
1525 (n, mesh.node_ptr(cast_int<dof_id_type>
1526 (conn_data[side_node_indices[n]])));
1527 sides[s] = std::move(side);
1528 }
1529
1530 elem = std::make_unique<C0Polyhedron>
1531 (sides, generated_mid_elem_node, parent);
1532
1533 libmesh_error_msg_if
1534 (elem->n_nodes() != conn_data.size(),
1535 "C0POLYHEDRON checkpoint topology is incompatible with "
1536 "this libMesh configuration.");
1537
1538 for (auto n : make_range(elem->n_vertices()))
1539 libmesh_error_msg_if
1540 (elem->node_id(n) !=
1541 cast_int<dof_id_type>(conn_data[n]),
1542 "C0POLYHEDRON checkpoint topology has inconsistent "
1543 "local node ordering.");
1544 }
1545 else
1546 elem = Elem::build(elem_type, parent);
1547
1548 if (has_runtime_topology)
1549 {
1550 libmesh_error_msg_if
1551 (!elem->runtime_topology() ||
1552 elem->n_nodes() != conn_data.size() ||
1553 elem->n_sides() != nodes_on_sides.size(),
1554 Utility::enum_to_string(elem_type) <<
1555 " checkpoint topology is incompatible with this "
1556 "libMesh configuration.");
1557
1558 for (auto s : index_range(nodes_on_sides))
1559 libmesh_error_msg_if
1560 (elem->nodes_on_side(s) != nodes_on_sides[s],
1561 Utility::enum_to_string(elem_type) <<
1562 " checkpoint topology has inconsistent side ordering.");
1563 }
1564
1565#ifdef LIBMESH_ENABLE_UNIQUE_ID
1566 elem->set_unique_id(unique_id);
1567#endif
1568
1569 if (elem->dim() > highest_elem_dim)
1570 highest_elem_dim = elem->dim();
1571
1572 elem->set_id() = id;
1573 elem->processor_id() = proc_id;
1574 elem->subdomain_id() = subdomain_id;
1575
1576#ifdef LIBMESH_ENABLE_AMR
1577 elem->hack_p_level(p_level);
1578
1579 elem->set_refinement_flag (cast_int<Elem::RefinementState>(rflag));
1580 elem->set_p_refinement_flag(cast_int<Elem::RefinementState>(pflag));
1581
1582 // Set parent connections
1583 if (parent)
1584 {
1585 // We must specify a child_num, because we will have
1586 // skipped adding any preceding remote_elem children
1587 parent->add_child(elem.get(), child_num);
1588 }
1589#else
1590 libmesh_ignore(child_num);
1591#endif
1592
1593 libmesh_assert(elem->n_nodes() == conn_data.size());
1594
1595 // Connect all the nodes to this element
1596 for (unsigned int n=0,
1597 n_conn = cast_int<unsigned int>(conn_data.size());
1598 n != n_conn; n++)
1599 elem->set_node(n,
1600 mesh.node_ptr(cast_int<dof_id_type>(conn_data[n])));
1601
1602 Elem * added_elem = mesh.add_elem(std::move(elem));
1603
1604 libmesh_assert_equal_to(n_extra_integers, added_elem->n_extra_integers());
1605 for (unsigned int ei=0; ei != n_extra_integers; ++ei)
1606 {
1607 const dof_id_type extra_int = cast_int<dof_id_type>(elem_data[6+ei]);
1608 added_elem->set_extra_integer(ei, extra_int);
1609 }
1610 }
1611 }
1612
1613 mesh.set_mesh_dimension(cast_int<unsigned char>(highest_elem_dim));
1614}
1615
1616
1617template <typename file_id_type>
1618void CheckpointIO::read_remote_elem (Xdr & io, bool libmesh_dbg_var(expect_all_remote))
1619{
1620 // convenient reference to our mesh
1622
1623 // Find the remote_elem neighbor links
1624 std::vector<file_id_type> elem_ids;
1625 std::vector<uint16_t> elem_sides;
1626
1627 io.data(elem_ids, "# remote neighbor elem_ids");
1628 io.data(elem_sides, "# remote neighbor elem_sides");
1629
1630 libmesh_assert_equal_to(elem_ids.size(), elem_sides.size());
1631
1632 for (auto i : index_range(elem_ids))
1633 {
1634 Elem & elem = mesh.elem_ref(cast_int<dof_id_type>(elem_ids[i]));
1635 if (!elem.neighbor_ptr(elem_sides[i]))
1636 elem.set_neighbor(elem_sides[i],
1637 const_cast<RemoteElem *>(remote_elem));
1638 else
1639 libmesh_assert(!expect_all_remote);
1640 }
1641
1642 // Find the remote_elem children links
1643 std::vector<file_id_type> parent_ids;
1644 std::vector<uint16_t> child_numbers;
1645
1646 io.data(parent_ids, "# remote child parent_ids");
1647 io.data(child_numbers, "# remote child_numbers");
1648
1649#ifdef LIBMESH_ENABLE_AMR
1650 for (auto i : index_range(parent_ids))
1651 {
1652 Elem & elem = mesh.elem_ref(cast_int<dof_id_type>(parent_ids[i]));
1653
1654 // We'd like to assert that no child pointer already exists to
1655 // be overwritten by remote_elem, but Elem doesn't actually have
1656 // an API that will return a child pointer without asserting
1657 // that it isn't nullptr.
1658 const Elem * child = elem.raw_child_ptr(child_numbers[i]);
1659
1660 if (!child)
1661 elem.add_child(const_cast<RemoteElem *>(remote_elem),
1662 child_numbers[i]);
1663 else
1664 libmesh_assert(!expect_all_remote);
1665 }
1666#endif
1667}
1668
1669
1670
1671template <typename file_id_type>
1673{
1674 // convenient reference to our mesh
1676
1677 // and our boundary info object
1678 BoundaryInfo & boundary_info = mesh.get_boundary_info();
1679
1680 std::vector<file_id_type> element_id_list;
1681 std::vector<uint16_t> side_list;
1682 std::vector<file_id_type> bc_id_list;
1683
1684 io.data(element_id_list, "# element ids for bcs");
1685 io.data(side_list, "# sides of elements for bcs");
1686 io.data(bc_id_list, "# bc ids");
1687
1688 for (auto i : index_range(element_id_list))
1689 boundary_info.add_side
1690 (cast_int<dof_id_type>(element_id_list[i]), side_list[i],
1691 cast_int<boundary_id_type>(bc_id_list[i]));
1692}
1693
1694
1695
1696template <typename file_id_type>
1698{
1699 // convenient reference to our mesh
1701
1702 // and our boundary info object
1703 BoundaryInfo & boundary_info = mesh.get_boundary_info();
1704
1705 std::vector<file_id_type> node_id_list;
1706 std::vector<file_id_type> bc_id_list;
1707
1708 io.data(node_id_list, "# node id list");
1709 io.data(bc_id_list, "# nodeset bc id list");
1710
1711 for (auto i : index_range(node_id_list))
1712 boundary_info.add_node
1713 (cast_int<dof_id_type>(node_id_list[i]),
1714 cast_int<boundary_id_type>(bc_id_list[i]));
1715}
1716
1717
1718
1719template <typename file_id_type>
1720void CheckpointIO::read_bc_names(Xdr & io, BoundaryInfo & info, bool is_sideset)
1721{
1722 std::map<boundary_id_type, std::string> & boundary_map = is_sideset ?
1723 info.set_sideset_name_map() : info.set_nodeset_name_map();
1724
1725 std::vector<file_id_type> boundary_ids;
1726 std::vector<std::string> boundary_names;
1727
1728 file_id_type n_boundary_names = 0;
1729
1730 if (is_sideset)
1731 io.data(n_boundary_names, "# sideset id to name map");
1732 else
1733 io.data(n_boundary_names, "# nodeset id to name map");
1734
1735 if (n_boundary_names)
1736 {
1737 io.data(boundary_ids);
1738 io.data(boundary_names);
1739 }
1740
1741 // Add them back into the map
1742 for (auto i : index_range(boundary_ids))
1743 boundary_map[cast_int<boundary_id_type>(boundary_ids[i])] =
1744 boundary_names[i];
1745}
1746
1747
1748template <typename file_id_type>
1750 (Xdr & io,
1751 std::vector<file_id_type> & pair_ids,
1752 std::vector<Real> & translations)
1753{
1754 file_id_type n_pairs = 0;
1755 io.data(n_pairs, "# disjoint neighbor boundary pairs");
1756 if (n_pairs)
1757 {
1758 io.data(pair_ids);
1759 libmesh_error_msg_if(pair_ids.size() != 2 * n_pairs,
1760 "Expected " << 2 * n_pairs << " disjoint neighbor boundary ids, found "
1761 << pair_ids.size());
1762
1763 translations.resize(LIBMESH_DIM * n_pairs);
1764 io.data_stream(translations.data(),
1765 cast_int<unsigned int>(translations.size()),
1766 LIBMESH_DIM);
1767 }
1768}
1769
1770
1771
1772template <typename file_id_type>
1774 (Xdr & io,
1775 std::vector<std::string> & node_integer_names,
1776 std::vector<std::string> & elem_integer_names)
1777{
1778 file_id_type n_node_integers, n_elem_integers;
1779
1780 io.data(n_node_integers, "# n_extra_integers per node");
1781 io.data(node_integer_names);
1782 io.data(n_elem_integers, "# n_extra_integers per elem");
1783 io.data(elem_integer_names);
1784}
1785
1786
1789{
1790 unsigned int max_level = 0;
1791
1792 for (const auto & elem : as_range(begin, end))
1793 max_level = std::max(elem->level(), max_level);
1794
1795 return max_level + 1;
1796}
1797
1798} // namespace libMesh
processor_id_type size() const
processor_id_type rank() const
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
std::vector< NodeBCTuple > build_node_list(NodeBCTupleSortBy sort_by=NodeBCTupleSortBy::NODE_ID) const
std::map< boundary_id_type, std::string > & set_sideset_name_map()
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure.
std::map< boundary_id_type, std::string > & set_nodeset_name_map()
void read_nodes(Xdr &io)
Read the nodal locations for a parallel, distributed mesh.
processor_id_type _my_n_processors
void write_bc_names(Xdr &io, const BoundaryInfo &info, bool is_sideset) const
Write boundary names information (sideset and nodeset)
file_id_type read_header(const std::string &name)
Read header data on processor 0, then broadcast.
void write_nodesets(Xdr &io, const connected_node_set_type &nodeset, const std::vector< std::tuple< dof_id_type, boundary_id_type > > &bc_tuples) const
Write the nodal boundary conditions for part of a mesh.
void read_subdomain_names(Xdr &io)
Read subdomain name information.
CheckpointIO(MeshBase &, const bool=false)
Constructor.
processor_id_type select_split_config(const std::string &input_name, header_id_type &data_size)
void write_connectivity(Xdr &io, const std::set< const Elem *, CompareElemIdsByLevel > &elements) const
Write the connectivity for part of a mesh.
bool version_at_least_1_6() const
virtual ~CheckpointIO()
Destructor.
void read_disjoint_neighbor_boundary_pairs(Xdr &io, std::vector< file_id_type > &pair_ids, std::vector< Real > &translations)
Read disjoint neighbor boundary pairs: the two boundary ids of each pair, and the LIBMESH_DIM transla...
void write_subdomain_names(Xdr &io) const
Write subdomain name information.
void read_connectivity(Xdr &io)
Read the connectivity for a parallel, distributed mesh.
void write_nodes(Xdr &io, const connected_node_set_type &nodeset) const
Write the nodal locations for part of a mesh.
void read_bcs(Xdr &io)
Read the boundary conditions for a parallel, distributed mesh.
void read_remote_elem(Xdr &io, bool expect_all_remote)
Read the remote_elem neighbor and child links for a parallel, distributed mesh.
void read_bc_names(Xdr &io, BoundaryInfo &info, bool is_sideset)
Read boundary names information (sideset and nodeset)
std::vector< processor_id_type > _my_processor_ids
void write_remote_elem(Xdr &io, const std::set< const Elem *, CompareElemIdsByLevel > &elements) const
Write the remote_elem neighbor and child links for part of a mesh.
void read_integers_names(Xdr &io, std::vector< std::string > &node_integer_names, std::vector< std::string > &elem_integer_names)
Read extra integers names information.
void read_nodesets(Xdr &io)
Read the nodeset conditions for a parallel, distributed mesh.
virtual void read(const std::string &input_name) override
This method implements reading a mesh from a specified file.
bool binary() const
Get/Set the flag indicating if we should read/write binary.
static void cleanup(const std::string &input_name, processor_id_type n_procs)
Used to remove a checkpoint directory and its corresponding files.
const std::string & version() const
Get/Set the version string.
virtual void write(const std::string &name) override
This method implements writing a mesh to a specified file.
void read_subfile(Xdr &io, bool expect_all_remote)
Read a non-header file.
void write_bcs(Xdr &io, const std::set< const Elem *, CompareElemIdsByLevel > &elements, const std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > &bc_triples) const
Write the side boundary conditions for part of a mesh.
bool parallel() const
Get/Set the flag indicating if we should read/write binary.
bool version_at_least_1_7() const
void write_disjoint_neighbor_boundary_pairs(Xdr &io) const
Write disjoint neighbor boundary pairs.
bool version_at_least_1_5() const
unsigned int n_active_levels_in(MeshBase::const_element_iterator begin, MeshBase::const_element_iterator end) const
dof_id_type get_extra_integer(const unsigned int index) const
Gets the value on this object of the extra integer associated with index, which should have been obta...
unsigned int n_extra_integers() const
Returns how many extra integers are associated to the DofObject.
processor_id_type processor_id() const
Definition dof_object.h:895
unique_id_type unique_id() const
Definition dof_object.h:849
static constexpr 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:484
void set_unique_id(unique_id_type new_id)
Sets the unique_id for this DofObject.
Definition dof_object.h:862
void set_extra_integer(const unsigned int index, const dof_id_type value)
Sets the value on this object of the extra integer associated with index, which should have been obta...
This is the base class from which all geometric element types are derived.
Definition elem.h:96
const Elem * raw_child_ptr(unsigned int i) const
Definition elem.h:3292
virtual unsigned int n_nodes() const =0
const Elem * parent() const
Definition elem.h:3168
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
Definition elem.h:2756
const Elem * child_ptr(unsigned int i) const
Definition elem.h:3301
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:382
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
subdomain_id_type subdomain_id() const
Definition elem.h:2712
static constexpr unsigned int type_to_n_nodes_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of nodes in the element...
Definition elem.h:664
void add_child(Elem *elem)
Adds a child pointer to the array of children of this element.
Definition elem.C:2155
virtual ElemType type() const =0
virtual unsigned int n_sides() const =0
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2605
const Elem * neighbor_ptr(unsigned int i) const
Definition elem.h:2736
This is the MeshBase class.
Definition mesh_base.h:81
virtual bool is_serial() const
Definition mesh_base.h:357
unsigned int n_elem_integers() const
Definition mesh_base.h:1094
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
virtual const Node * node_ptr(const dof_id_type i) const =0
unsigned int mesh_dimension() const
Definition mesh_base.C:435
virtual dof_id_type n_elem() const =0
virtual bool is_replicated() const
Definition mesh_base.h:379
unsigned int recalculate_n_partitions()
In a few (very rare) cases, the user may have manually tagged the elements with specific processor ID...
Definition mesh_base.C:1828
PeriodicBoundaries * get_disjoint_neighbor_boundary_pairs()
Definition mesh_base.C:2311
const std::map< subdomain_id_type, std::string > & get_subdomain_name_map() const
Definition mesh_base.h:1930
unsigned int add_node_integer(std::string name, bool allocate_data=true, dof_id_type default_value=DofObject::invalid_id)
Register an integer datum (of type dof_id_type) to be added to each node in the mesh.
Definition mesh_base.C:712
const std::string & get_node_integer_name(unsigned int i) const
Definition mesh_base.h:1205
virtual const Node * query_node_ptr(const dof_id_type i) const =0
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition mesh_base.h:423
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
virtual void update_post_partitioning()
Recalculate any cached data (or invalidate any caches that are computed on the fly) after elements an...
Definition mesh_base.C:1181
virtual const Elem * elem_ptr(const dof_id_type i) const =0
unsigned int add_elem_integer(std::string name, bool allocate_data=true, dof_id_type default_value=DofObject::invalid_id)
Register an integer datum (of type dof_id_type) to be added to each element in the mesh.
Definition mesh_base.C:623
const std::string & get_elem_integer_name(unsigned int i) const
Definition mesh_base.h:1083
virtual void set_distributed()
Asserts that not all elements and nodes of the mesh necessarily exist on the current processor.
Definition mesh_base.h:372
unsigned int n_node_integers() const
Definition mesh_base.h:1216
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
virtual const Elem & elem_ref(const dof_id_type i) const
Definition mesh_base.h:785
void add_disjoint_neighbor_boundary_pairs(const boundary_id_type b1, const boundary_id_type b2, const RealVectorValue &translation)
Register a pair of boundaries as disjoint neighbor boundary pairs.
Definition mesh_base.C:2287
std::map< subdomain_id_type, std::string > & set_subdomain_name_map()
Definition mesh_base.h:1928
virtual void partition(const unsigned int n_parts)
Call the default partitioner (currently metis_partition()).
Definition mesh_base.C:1784
void skip_partitioning(bool skip)
If true is passed in then nothing on this mesh will be (re)partitioned.
Definition mesh_base.h:1433
This is the MeshCommunication class.
void broadcast(MeshBase &) const
This method takes a mesh (which is assumed to reside on processor 0) and broadcasts it to all the oth...
This class defines an abstract interface for Mesh input.
Definition mesh_input.h:49
This class defines an abstract interface for Mesh output.
Definition mesh_output.h:54
const MT & mesh() const
A Node is like a Point, but with more information.
Definition node.h:55
An object whose state is distributed along a set of processors.
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
We're using a class instead of a typedef to allow forward declarations and future flexibility.
The definition of a periodic boundary.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:41
In parallel meshes where a ghost element has neighbors which do not exist on the local processor,...
Definition remote_elem.h:61
This class implements a C++ interface to the XDR (eXternal Data Representation) format.
Definition xdr_cxx.h:68
bool writing() const
Definition xdr_cxx.h:129
void data_stream(T *val, const unsigned int len, const unsigned int line_break=libMesh::invalid_uint)
Inputs or outputs a raw data stream.
Definition xdr_cxx.C:925
void close()
Closes the file if it is open.
Definition xdr_cxx.C:278
void data(T &a, std::string_view comment="")
Inputs or outputs a single value.
Definition xdr_cxx.C:860
MeshBase & mesh
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
tbb::split split
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
int mkdir(const char *pathname)
Create a directory.
Definition utility.C:152
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
void query_ghosting_functors(const MeshBase &mesh, processor_id_type pid, MeshBase::const_element_iterator elem_it, MeshBase::const_element_iterator elem_end, connected_elem_set_type &connected_elements)
ElemType
Defines an enum for geometric element types.
void libmesh_ignore(const Args &...)
libmesh_assert(ctx)
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition libmesh.h:303
std::unique_ptr< CheckpointIO > split_mesh(MeshBase &mesh, processor_id_type nsplits)
split_mesh takes the given initialized/opened mesh and partitions it into nsplits pieces or chunks.
uint64_t largest_id_type
Definition id_types.h:148
const RemoteElem * remote_elem
Definition remote_elem.C:57
std::set< const Node * > connected_node_set_type
void connect_element_dependencies(const MeshBase &mesh, connected_elem_set_type &connected_elements, connected_node_set_type &connected_nodes)
uint8_t dof_id_type
Definition id_types.h:67
void connect_children(const MeshBase &mesh, MeshBase::const_element_iterator elem_it, MeshBase::const_element_iterator elem_end, connected_elem_set_type &connected_elements)
uint8_t processor_id_type
Definition id_types.h:104
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition int_range.h:176
The definition of the const_element_iterator struct.
Definition mesh_base.h:2575
Used to iterate over non-nullptr, active entries in a container.
Used to iterate over non-nullptr entries in a container.
const dof_id_type n_nodes
Definition tecplot_io.C:67