libMesh
checkpoint_io.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 #include "libmesh/checkpoint_io.h"
19 
20 // Local includes
21 #include "libmesh/boundary_info.h"
22 #include "libmesh/distributed_mesh.h"
23 #include "libmesh/elem.h"
24 #include "libmesh/enum_xdr_mode.h"
25 #include "libmesh/libmesh_logging.h"
26 #include "libmesh/mesh_base.h"
27 #include "libmesh/mesh_communication.h"
28 #include "libmesh/mesh_tools.h"
29 #include "libmesh/node.h"
30 #include "libmesh/parallel.h"
31 #include "libmesh/partitioner.h"
32 #include "libmesh/metis_partitioner.h"
33 #include "libmesh/remote_elem.h"
34 #include "libmesh/xdr_io.h"
35 #include "libmesh/xdr_cxx.h"
36 #include "libmesh/utility.h"
37 #include "libmesh/int_range.h"
38 
39 // C++ includes
40 #include <iostream>
41 #include <iomanip>
42 #include <cstdio>
43 #include <unistd.h>
44 #include <vector>
45 #include <string>
46 #include <cstring>
47 #include <fstream>
48 #include <sstream> // for ostringstream
49 #include <unordered_map>
50 #include <unordered_set>
51 
52 namespace
53 {
54 // chunking computes the number of chunks and first-chunk-offset when splitting a mesh
55 // into nsplits pieces using size procs for the given MPI rank. The number of chunks and offset
56 // are stored in nchunks and first_chunk respectively.
59 {
60  if (nsplits % size == 0) // the chunks divide evenly over the processors
61  {
62  nchunks = nsplits / size;
63  first_chunk = libMesh::cast_int<libMesh::processor_id_type>(nchunks * rank);
64  return;
65  }
66 
67  libMesh::processor_id_type nextra = nsplits % size;
68  if (rank < nextra) // leftover chunks cause an extra chunk to be added to this processor
69  {
70  nchunks = libMesh::cast_int<libMesh::processor_id_type>(nsplits / size + 1);
71  first_chunk = libMesh::cast_int<libMesh::processor_id_type>(nchunks * rank);
72  }
73  else // no extra chunks, but first chunk is offset by extras on earlier ranks
74  {
75  nchunks = nsplits / size;
76  // account for the case where nchunks is zero where we want max int
77  first_chunk = libMesh::cast_int<libMesh::processor_id_type>
78  (std::max((int)((nchunks + 1) * (nsplits % size) + nchunks * (rank - nsplits % size)),
79  (1 - (int)nchunks) * std::numeric_limits<int>::max()));
80  }
81 }
82 
83 std::string extension(const std::string & s)
84 {
85  auto pos = s.rfind(".");
86  if (pos == std::string::npos)
87  return "";
88  return s.substr(pos, s.size() - pos);
89 }
90 
91 std::string split_dir(const std::string & input_name, libMesh::processor_id_type n_procs)
92 {
93  return input_name + "/" + std::to_string(n_procs);
94 }
95 
96 
97 std::string header_file(const std::string & input_name, libMesh::processor_id_type n_procs)
98 {
99  return split_dir(input_name, n_procs) + "/header" + extension(input_name);
100 }
101 
102 std::string
103 split_file(const std::string & input_name,
106 {
107  return split_dir(input_name, n_procs) + "/split-" + std::to_string(n_procs) + "-" +
108  std::to_string(proc_id) + extension(input_name);
109 }
110 
111 void make_dir(const std::string & input_name, libMesh::processor_id_type n_procs)
112 {
113  auto ret = libMesh::Utility::mkdir(input_name.c_str());
114  // error only if we failed to create dir - don't care if it was already there
115  if (ret != 0 && ret != -1)
116  libmesh_error_msg(
117  "Failed to create mesh split directory '" << input_name << "': " << std::strerror(ret));
118 
119  auto dir_name = split_dir(input_name, n_procs);
120  ret = libMesh::Utility::mkdir(dir_name.c_str());
121  if (ret == -1)
122  libmesh_warning("In CheckpointIO::write, directory '"
123  << dir_name << "' already exists, overwriting contents.");
124  else if (ret != 0)
125  libmesh_error_msg(
126  "Failed to create mesh split directory '" << dir_name << "': " << std::strerror(ret));
127 }
128 
129 } // namespace
130 
131 namespace libMesh
132 {
133 
134 std::unique_ptr<CheckpointIO> split_mesh(MeshBase & mesh, processor_id_type nsplits)
135 {
136  // There is currently an issue with DofObjects not being properly
137  // reset if the mesh is not first repartitioned onto 1 processor
138  // *before* being repartitioned onto the desired number of
139  // processors. So, this is a workaround, but not a particularly
140  // onerous one.
141  mesh.partition(1);
142  mesh.partition(nsplits);
143 
144  processor_id_type my_num_chunks = 0;
145  processor_id_type my_first_chunk = 0;
146  chunking(mesh.comm().size(), mesh.comm().rank(), nsplits, my_num_chunks, my_first_chunk);
147 
148  auto cpr = libmesh_make_unique<CheckpointIO>(mesh);
149  cpr->current_processor_ids().clear();
150  for (processor_id_type i = my_first_chunk; i < my_first_chunk + my_num_chunks; i++)
151  cpr->current_processor_ids().push_back(i);
152  cpr->current_n_processors() = nsplits;
153  cpr->parallel() = true;
154  return cpr;
155 }
156 
157 
158 // ------------------------------------------------------------
159 // CheckpointIO members
160 CheckpointIO::CheckpointIO (MeshBase & mesh, const bool binary_in) :
161  MeshInput<MeshBase> (mesh,/* is_parallel_format = */ true),
162  MeshOutput<MeshBase>(mesh,/* is_parallel_format = */ true),
164  _binary (binary_in),
165  _parallel (false),
166  _version ("checkpoint-1.5"),
167  _my_processor_ids (1, processor_id()),
168  _my_n_processors (mesh.is_replicated() ? 1 : n_processors())
169 {
170 }
171 
172 CheckpointIO::CheckpointIO (const MeshBase & mesh, const bool binary_in) :
173  MeshOutput<MeshBase>(mesh,/* is_parallel_format = */ true),
175  _binary (binary_in),
176  _parallel (false),
177  _my_processor_ids (1, processor_id()),
178  _my_n_processors (mesh.is_replicated() ? 1 : n_processors())
179 {
180 }
181 
183 {
184 }
185 
186 processor_id_type CheckpointIO::select_split_config(const std::string & input_name, header_id_type & data_size)
187 {
188  std::string header_name;
189 
190  // We'll read a header file from processor 0 and broadcast.
191  if (this->processor_id() == 0)
192  {
193  header_name = header_file(input_name, _my_n_processors);
194 
195  {
196  // look for header+splits with nprocs equal to _my_n_processors
197  std::ifstream in (header_name.c_str());
198  if (!in.good())
199  {
200  // otherwise fall back to a serial/single-split mesh
201  auto orig_header_name = header_name;
202  header_name = header_file(input_name, 1);
203  std::ifstream in2 (header_name.c_str());
204  if (!in2.good())
205  {
206  libmesh_error_msg("ERROR: Neither one of the following files can be located:\n\t'"
207  << orig_header_name << "' nor\n\t'" << input_name << "'\n"
208  << "If you are running a parallel job, double check that you've "
209  << "created a split for " << _my_n_processors << " ranks.\n"
210  << "Note: One of paths above may refer to a valid directory on your "
211  << "system, however we are attempting to read a valid header file.");
212  }
213  }
214  }
215 
216  Xdr io (header_name, this->binary() ? DECODE : READ);
217 
218  // read the version, but don't care about it
219  std::string input_version;
220  io.data(input_version);
221 
222  // read the data type
223  io.data (data_size);
224  }
225 
226  this->comm().broadcast(data_size);
227  this->comm().broadcast(header_name);
228 
229  // How many per-processor files are here?
230  largest_id_type input_n_procs;
231 
232  switch (data_size) {
233  case 2:
234  input_n_procs = this->read_header<uint16_t>(header_name);
235  break;
236  case 4:
237  input_n_procs = this->read_header<uint32_t>(header_name);
238  break;
239  case 8:
240  input_n_procs = this->read_header<uint64_t>(header_name);
241  break;
242  default:
243  libmesh_error();
244  }
245 
246  if (!input_n_procs)
247  input_n_procs = 1;
248  return cast_int<processor_id_type>(input_n_procs);
249 }
250 
251 void CheckpointIO::cleanup(const std::string & input_name, processor_id_type n_procs)
252 {
253  auto header = header_file(input_name, n_procs);
254  auto ret = std::remove(header.c_str());
255  if (ret != 0)
256  libmesh_warning("Failed to clean up checkpoint header '" << header << "': " << std::strerror(ret));
257 
258  for (processor_id_type i = 0; i < n_procs; i++)
259  {
260  auto split = split_file(input_name, n_procs, i);
261  ret = std::remove(split.c_str());
262  if (ret != 0)
263  libmesh_warning("Failed to clean up checkpoint split file '" << split << "': " << std::strerror(ret));
264  }
265 
266  auto dir = split_dir(input_name, n_procs);
267  ret = rmdir(dir.c_str());
268  if (ret != 0)
269  libmesh_warning("Failed to clean up checkpoint split dir '" << dir << "': " << std::strerror(ret));
270 
271  // We expect that this may fail if there are other split configurations still present in this
272  // directory - so don't bother to check/warn for failure.
273  rmdir(input_name.c_str());
274 }
275 
276 
278 {
279  return (this->version().find("1.5") != std::string::npos);
280 }
281 
282 
283 void CheckpointIO::write (const std::string & name)
284 {
285  LOG_SCOPE("write()", "CheckpointIO");
286 
287  // convenient reference to our mesh
289 
290  // FIXME: For backwards compatibility, we'll assume for now that we
291  // only want to write distributed meshes in parallel. Later we can
292  // do a gather_to_zero() and support that case too.
294 
295  processor_id_type use_n_procs = 1;
296  if (_parallel)
297  use_n_procs = _my_n_processors;
298 
299  std::string header_file_name = header_file(name, use_n_procs);
300  make_dir(name, use_n_procs);
301 
302  // We'll write a header file from processor 0 to make it easier to do unambiguous
303  // restarts later:
304  if (this->processor_id() == 0)
305  {
306  Xdr io (header_file_name, this->binary() ? ENCODE : WRITE);
307 
308  // write the version
309  io.data(_version, "# version");
310 
311  // write what kind of data type we're using
312  header_id_type data_size = sizeof(largest_id_type);
313  io.data(data_size, "# integer size");
314 
315  // Write out the max mesh dimension for backwards compatibility
316  // with code that sets it independently of element dimensions
317  {
318  uint16_t mesh_dimension = cast_int<uint16_t>(mesh.mesh_dimension());
319  io.data(mesh_dimension, "# dimensions");
320  }
321 
322  // Write out whether or not this is serial output
323  {
324  uint16_t parallel = _parallel;
325  io.data(parallel, "# parallel");
326  }
327 
328  // If we're writing out a parallel mesh then we need to write the number of processors
329  // so we can check it upon reading the file
330  if (_parallel)
331  {
333  io.data(n_procs, "# n_procs");
334  }
335 
336  // write subdomain names
337  this->write_subdomain_names(io);
338 
339  // write boundary id names
340  const BoundaryInfo & boundary_info = mesh.get_boundary_info();
341  write_bc_names(io, boundary_info, true); // sideset names
342  write_bc_names(io, boundary_info, false); // nodeset names
343 
344  // write extra integer names
345  const bool write_extra_integers = this->version_at_least_1_5();
346 
347  if (write_extra_integers)
348  {
349  largest_id_type n_node_integers = mesh.n_node_integers();
350  io.data(n_node_integers, "# n_extra_integers per node");
351 
352  std::vector<std::string> node_integer_names;
353  for (unsigned int i=0; i != n_node_integers; ++i)
354  node_integer_names.push_back(mesh.get_node_integer_name(i));
355 
356  io.data(node_integer_names);
357 
358  largest_id_type n_elem_integers = mesh.n_elem_integers();
359  io.data(n_elem_integers, "# n_extra_integers per elem");
360 
361  std::vector<std::string> elem_integer_names;
362  for (unsigned int i=0; i != n_elem_integers; ++i)
363  elem_integer_names.push_back(mesh.get_elem_integer_name(i));
364 
365  io.data(elem_integer_names);
366  }
367 
368 
369  }
370 
371  // If this is a serial mesh written to a serial file then we're only
372  // going to write local data from processor 0. If this is a mesh being
373  // written in parallel then we're going to write from every
374  // processor.
375  std::vector<processor_id_type> ids_to_write;
376 
377  // We're going to sort elements by pid in one pass, to avoid sending
378  // predicated iterators through the whole mesh N_p times
379  std::unordered_map<processor_id_type, std::vector<Elem *>> elements_on_pid;
380 
381  if (_parallel)
382  {
383  ids_to_write = _my_processor_ids;
384  for (processor_id_type p : ids_to_write)
385  elements_on_pid[p].clear();
386  auto eop_end = elements_on_pid.end();
387  for (auto & elem : mesh.element_ptr_range())
388  {
389  const processor_id_type p = elem->processor_id();
390  auto eop_it = elements_on_pid.find(p);
391  if (eop_it != eop_end)
392  eop_it->second.push_back(elem);
393  }
394  }
395  else if (mesh.is_serial())
396  {
397  if (mesh.processor_id() == 0)
398  {
399  // placeholder
400  ids_to_write.push_back(0);
401  }
402  }
403  else
404  {
405  libmesh_error_msg("Cannot write serial checkpoint from distributed mesh");
406  }
407 
408  // Call build_side_list() and build_node_list() just *once* to avoid
409  // redundant expensive sorts during mesh splitting.
410  const BoundaryInfo & boundary_info = mesh.get_boundary_info();
411  std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
412  bc_triples = boundary_info.build_side_list();
413  std::vector<std::tuple<dof_id_type, boundary_id_type>>
414  bc_tuples = boundary_info.build_node_list();
415 
416  for (const auto & my_pid : ids_to_write)
417  {
418  auto file_name = split_file(name, use_n_procs, my_pid);
419  Xdr io (file_name, this->binary() ? ENCODE : WRITE);
420 
421  std::set<const Elem *, CompareElemIdsByLevel> elements;
422 
423  // For serial files or for already-distributed meshs, we write
424  // everything we can see.
425  if (!_parallel || !mesh.is_serial())
426  elements.insert(mesh.elements_begin(), mesh.elements_end());
427  // For parallel files written from serial meshes we write what
428  // we'd be required to keep if we were to be deleting remote
429  // elements. This allows us to write proper parallel files even
430  // from a ReplicateMesh.
431  //
432  // WARNING: If we have a DistributedMesh which used
433  // "add_extra_ghost_elem" rather than ghosting functors to
434  // preserve elements and which is *also* currently serialized
435  // then we're not preserving those elements here. As a quick
436  // workaround user code should delete_remote_elements() before
437  // writing the checkpoint; as a long term workaround user code
438  // should use ghosting functors instead of extra_ghost_elem
439  // lists.
440  else
441  {
443  {
444  const auto elements_vec_it = elements_on_pid.find(p);
445  if (elements_vec_it != elements_on_pid.end())
446  {
447  const auto & p_elements = elements_vec_it->second;
448  Elem * const * elempp = p_elements.data();
449  Elem * const * elemend = elempp + p_elements.size();
450 
452  pid_elements_begin = MeshBase::const_element_iterator
453  (elempp, elemend, Predicates::NotNull<Elem * const *>()),
454  pid_elements_end = MeshBase::const_element_iterator
455  (elemend, elemend, Predicates::NotNull<Elem * const *>()),
456  active_pid_elements_begin = MeshBase::const_element_iterator
457  (elempp, elemend, Predicates::Active<Elem * const *>()),
458  active_pid_elements_end = MeshBase::const_element_iterator
459  (elemend, elemend, Predicates::Active<Elem * const *>());
460 
462  (mesh, p, active_pid_elements_begin,
463  active_pid_elements_end, elements);
464  connect_children(mesh, pid_elements_begin,
465  pid_elements_end, elements);
466  }
467  connect_families(elements);
468  }
469  }
470 
471  std::set<const Node *> connected_nodes;
472  reconnect_nodes(elements, connected_nodes);
473 
474  // write the nodal locations
475  this->write_nodes (io, connected_nodes);
476 
477  // write connectivity
478  this->write_connectivity (io, elements);
479 
480  // write remote_elem connectivity
481  this->write_remote_elem (io, elements);
482 
483  // write the boundary condition information
484  this->write_bcs (io, elements, bc_triples);
485 
486  // write the nodeset information
487  this->write_nodesets (io, connected_nodes, bc_tuples);
488 
489  // close it up
490  io.close();
491  }
492 
493  // this->comm().barrier();
494 }
495 
497 {
498  {
500 
501  const std::map<subdomain_id_type, std::string> & subdomain_map = mesh.get_subdomain_name_map();
502 
503  std::vector<largest_id_type> subdomain_ids; subdomain_ids.reserve(subdomain_map.size());
504  std::vector<std::string> subdomain_names; subdomain_names.reserve(subdomain_map.size());
505 
506  // We need to loop over the map and make sure that there aren't any invalid entries. Since we
507  // return writable references in mesh_base, it's possible for the user to leave some entity names
508  // blank. We can't write those to the XDA file.
509  largest_id_type n_subdomain_names = 0;
510  for (const auto & pr : subdomain_map)
511  if (!pr.second.empty())
512  {
513  n_subdomain_names++;
514  subdomain_ids.push_back(pr.first);
515  subdomain_names.push_back(pr.second);
516  }
517 
518  io.data(n_subdomain_names, "# subdomain id to name map");
519  // Write out the ids and names in two vectors
520  if (n_subdomain_names)
521  {
522  io.data(subdomain_ids);
523  io.data(subdomain_names);
524  }
525  }
526 }
527 
528 
529 
531  const std::set<const Node *> & nodeset) const
532 {
533  largest_id_type n_nodes_here = nodeset.size();
534 
535  io.data(n_nodes_here, "# n_nodes on proc");
536 
537  const bool write_extra_integers = this->version_at_least_1_5();
538  const unsigned int n_extra_integers =
539  write_extra_integers ? MeshOutput<MeshBase>::mesh().n_node_integers() : 0;
540 
541  // Will hold the node id and pid and extra integers
542  std::vector<largest_id_type> id_pid(2 + n_extra_integers);
543 
544  // For the coordinates
545  std::vector<Real> coords(LIBMESH_DIM);
546 
547  for (const auto & node : nodeset)
548  {
549  id_pid[0] = node->id();
550  id_pid[1] = node->processor_id();
551 
552  libmesh_assert_equal_to(n_extra_integers, node->n_extra_integers());
553  for (unsigned int i=0; i != n_extra_integers; ++i)
554  id_pid[2+i] = node->get_extra_integer(i);
555 
556  io.data_stream(id_pid.data(), 2 + n_extra_integers, 2 + n_extra_integers);
557 
558 #ifdef LIBMESH_ENABLE_UNIQUE_ID
559  largest_id_type unique_id = node->unique_id();
560 
561  io.data(unique_id, "# unique id");
562 #endif
563 
564  coords[0] = (*node)(0);
565 
566 #if LIBMESH_DIM > 1
567  coords[1] = (*node)(1);
568 #endif
569 
570 #if LIBMESH_DIM > 2
571  coords[2] = (*node)(2);
572 #endif
573 
574  io.data_stream(coords.data(), LIBMESH_DIM, 3);
575  }
576 }
577 
578 
579 
581  const std::set<const Elem *, CompareElemIdsByLevel> & elements) const
582 {
583  libmesh_assert (io.writing());
584 
585  const bool write_extra_integers = this->version_at_least_1_5();
586  const unsigned int n_extra_integers =
587  write_extra_integers ? MeshOutput<MeshBase>::mesh().n_elem_integers() : 0;
588 
589  // Put these out here to reduce memory churn
590  // id type pid subdomain_id parent_id extra_integer_0 ...
591  std::vector<largest_id_type> elem_data(6 + n_extra_integers);
592  std::vector<largest_id_type> conn_data;
593 
594  largest_id_type n_elems_here = elements.size();
595 
596  io.data(n_elems_here, "# number of elements");
597 
598  for (const auto & elem : elements)
599  {
600  unsigned int n_nodes = elem->n_nodes();
601 
602  elem_data[0] = elem->id();
603  elem_data[1] = elem->type();
604  elem_data[2] = elem->processor_id();
605  elem_data[3] = elem->subdomain_id();
606 
607 #ifdef LIBMESH_ENABLE_AMR
608  if (elem->parent() != nullptr)
609  {
610  elem_data[4] = elem->parent()->id();
611  elem_data[5] = elem->parent()->which_child_am_i(elem);
612  }
613  else
614 #endif
615  {
616  elem_data[4] = static_cast<largest_id_type>(-1);
617  elem_data[5] = static_cast<largest_id_type>(-1);
618  }
619 
620  for (unsigned int i=0; i != n_extra_integers; ++i)
621  elem_data[6+i] = elem->get_extra_integer(i);
622 
623  conn_data.resize(n_nodes);
624 
625  for (unsigned int i=0; i<n_nodes; i++)
626  conn_data[i] = elem->node_id(i);
627 
628  io.data_stream(elem_data.data(),
629  cast_int<unsigned int>(elem_data.size()),
630  cast_int<unsigned int>(elem_data.size()));
631 
632 #ifdef LIBMESH_ENABLE_UNIQUE_ID
633  largest_id_type unique_id = elem->unique_id();
634 
635  io.data(unique_id, "# unique id");
636 #endif
637 
638 #ifdef LIBMESH_ENABLE_AMR
639  uint16_t p_level = cast_int<uint16_t>(elem->p_level());
640  io.data(p_level, "# p_level");
641 
642  uint16_t rflag = elem->refinement_flag();
643  io.data(rflag, "# rflag");
644 
645  uint16_t pflag = elem->p_refinement_flag();
646  io.data(pflag, "# pflag");
647 #endif
648  io.data_stream(conn_data.data(),
649  cast_int<unsigned int>(conn_data.size()),
650  cast_int<unsigned int>(conn_data.size()));
651  }
652 }
653 
654 
656  const std::set<const Elem *, CompareElemIdsByLevel> & elements) const
657 {
658  libmesh_assert (io.writing());
659 
660  // Find the remote_elem neighbor and child links
661  std::vector<largest_id_type> elem_ids, parent_ids;
662  std::vector<uint16_t> elem_sides, child_numbers;
663 
664  for (const auto & elem : elements)
665  {
666  for (auto n : elem->side_index_range())
667  {
668  const Elem * neigh = elem->neighbor_ptr(n);
669  if (neigh == remote_elem ||
670  (neigh && !elements.count(neigh)))
671  {
672  elem_ids.push_back(elem->id());
673  elem_sides.push_back(n);
674  }
675  }
676 
677 #ifdef LIBMESH_ENABLE_AMR
678  if (elem->has_children())
679  {
680  for (unsigned short c = 0,
681  nc = cast_int<unsigned short>(elem->n_children());
682  c != nc; ++c)
683  {
684  const Elem * child = elem->child_ptr(c);
685  if (child == remote_elem ||
686  (child && !elements.count(child)))
687  {
688  parent_ids.push_back(elem->id());
689  child_numbers.push_back(c);
690  }
691  }
692  }
693 #endif
694  }
695 
696  io.data(elem_ids, "# remote neighbor elem_ids");
697  io.data(elem_sides, "# remote neighbor elem_sides");
698  io.data(parent_ids, "# remote child parent_ids");
699  io.data(child_numbers, "# remote child_numbers");
700 }
701 
702 
703 
705  const std::set<const Elem *, CompareElemIdsByLevel> & elements,
706  const std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> & bc_triples) const
707 {
708  libmesh_assert (io.writing());
709 
710  // Build a list of (elem, side, bc) tuples.
711  std::size_t bc_size = bc_triples.size();
712 
713  std::vector<largest_id_type> element_id_list;
714  std::vector<uint16_t> side_list;
715  std::vector<largest_id_type> bc_id_list;
716 
717  element_id_list.reserve(bc_size);
718  side_list.reserve(bc_size);
719  bc_id_list.reserve(bc_size);
720 
721  std::unordered_set<dof_id_type> elems;
722  for (auto & e : elements)
723  elems.insert(e->id());
724 
725  for (const auto & t : bc_triples)
726  if (elems.count(std::get<0>(t)))
727  {
728  element_id_list.push_back(std::get<0>(t));
729  side_list.push_back(std::get<1>(t));
730  bc_id_list.push_back(std::get<2>(t));
731  }
732 
733 
734  io.data(element_id_list, "# element ids for bcs");
735  io.data(side_list, "# sides of elements for bcs");
736  io.data(bc_id_list, "# bc ids");
737 }
738 
739 
740 
742  const std::set<const Node *> & nodeset,
743  const std::vector<std::tuple<dof_id_type, boundary_id_type>> & bc_tuples) const
744 {
745  libmesh_assert (io.writing());
746 
747  // convenient reference to our mesh
749 
750  // Build a list of (node, bc) tuples
751  std::size_t nodeset_size = bc_tuples.size();
752 
753  std::vector<largest_id_type> node_id_list;
754  std::vector<largest_id_type> bc_id_list;
755 
756  node_id_list.reserve(nodeset_size);
757  bc_id_list.reserve(nodeset_size);
758 
759  for (const auto & t : bc_tuples)
760  if (nodeset.count(mesh.node_ptr(std::get<0>(t))))
761  {
762  node_id_list.push_back(std::get<0>(t));
763  bc_id_list.push_back(std::get<1>(t));
764  }
765 
766  io.data(node_id_list, "# node id list");
767  io.data(bc_id_list, "# nodeset bc id list");
768 }
769 
770 
771 
772 void CheckpointIO::write_bc_names (Xdr & io, const BoundaryInfo & info, bool is_sideset) const
773 {
774  const std::map<boundary_id_type, std::string> & boundary_map = is_sideset ?
776 
777  std::vector<largest_id_type> boundary_ids; boundary_ids.reserve(boundary_map.size());
778  std::vector<std::string> boundary_names; boundary_names.reserve(boundary_map.size());
779 
780  // We need to loop over the map and make sure that there aren't any invalid entries. Since we
781  // return writable references in boundary_info, it's possible for the user to leave some entity names
782  // blank. We can't write those to the XDA file.
783  largest_id_type n_boundary_names = 0;
784  for (const auto & pr : boundary_map)
785  if (!pr.second.empty())
786  {
787  n_boundary_names++;
788  boundary_ids.push_back(pr.first);
789  boundary_names.push_back(pr.second);
790  }
791 
792  if (is_sideset)
793  io.data(n_boundary_names, "# sideset id to name map");
794  else
795  io.data(n_boundary_names, "# nodeset id to name map");
796  // Write out the ids and names in two vectors
797  if (n_boundary_names)
798  {
799  io.data(boundary_ids);
800  io.data(boundary_names);
801  }
802 }
803 
804 void CheckpointIO::read (const std::string & input_name)
805 {
806  LOG_SCOPE("read()","CheckpointIO");
807 
809 
811 
812  header_id_type data_size;
813  processor_id_type input_n_procs = select_split_config(input_name, data_size);
814  auto header_name = header_file(input_name, input_n_procs);
815  bool input_parallel = input_n_procs > 0;
816 
817  // If this is a serial read then we're going to only read the mesh
818  // on processor 0, then broadcast it
819  if ((input_parallel && !mesh.is_replicated()) || mesh.processor_id() == 0)
820  {
821  // If we're trying to read a parallel checkpoint file on a
822  // replicated mesh, we'll read every file on processor 0 so we
823  // can broadcast it later. If we're on a distributed mesh then
824  // we'll read every id to it's own processor and we'll "wrap
825  // around" with any ids that exceed our processor count.
826  const processor_id_type begin_proc_id =
827  (input_parallel && !mesh.is_replicated()) ?
828  mesh.processor_id() : 0;
829  const processor_id_type stride =
830  (input_parallel && !mesh.is_replicated()) ?
831  mesh.n_processors() : 1;
832 
833  for (processor_id_type proc_id = begin_proc_id; proc_id < input_n_procs;
834  proc_id = cast_int<processor_id_type>(proc_id + stride))
835  {
836  auto file_name = split_file(input_name, input_n_procs, proc_id);
837 
838  {
839  std::ifstream in (file_name.c_str());
840 
841  if (!in.good())
842  libmesh_error_msg("ERROR: cannot locate specified file:\n\t" << file_name);
843  }
844 
845  // Do we expect all our files' remote_elem entries to really
846  // be remote? Only if we're not reading multiple input
847  // files on the same processor.
848  const bool expect_all_remote =
849  (input_n_procs <= mesh.n_processors() &&
850  !mesh.is_replicated());
851 
852  Xdr io (file_name, this->binary() ? DECODE : READ);
853 
854  switch (data_size) {
855  case 2:
856  this->read_subfile<uint16_t>(io, expect_all_remote);
857  break;
858  case 4:
859  this->read_subfile<uint32_t>(io, expect_all_remote);
860  break;
861  case 8:
862  this->read_subfile<uint64_t>(io, expect_all_remote);
863  break;
864  default:
865  libmesh_error();
866  }
867 
868  io.close();
869  }
870  }
871 
872  // If the mesh was only read on processor 0 then we need to broadcast it
873  if (mesh.is_replicated())
875  // If the mesh is really distributed then we need to make sure it
876  // knows that
877  else if (mesh.n_processors() > 1)
879 }
880 
881 
882 
883 template <typename file_id_type>
884 file_id_type CheckpointIO::read_header (const std::string & name)
885 {
887 
888  // Hack for codes which don't look at all elem dimensions
889  uint16_t mesh_dimension;
890 
891  // Will this be a parallel input file? With how many processors? Stay tuned!
892  uint16_t input_parallel;
893  file_id_type input_n_procs;
894 
895  std::vector<std::string> node_integer_names, elem_integer_names;
896 
897  // We'll write a header file from processor 0 and broadcast.
898  if (this->processor_id() == 0)
899  {
900  Xdr io (name, this->binary() ? DECODE : READ);
901 
902  // read the version, but don't care about it
903  std::string input_version;
904  io.data(input_version);
905 
906  // read the data type, don't care about it this time
907  header_id_type data_size;
908  io.data (data_size);
909 
910  // read the dimension
911  io.data (mesh_dimension);
912 
913  // Read whether or not this is a parallel file
914  io.data(input_parallel);
915 
916  // With how many processors?
917  if (input_parallel)
918  io.data(input_n_procs);
919 
920  // read subdomain names
921  this->read_subdomain_names<file_id_type>(io);
922 
923  // read boundary names
924  BoundaryInfo & boundary_info = mesh.get_boundary_info();
925 
926  this->read_bc_names<file_id_type>(io, boundary_info, true); // sideset names
927  this->read_bc_names<file_id_type>(io, boundary_info, false); // nodeset names
928 
929  // read extra integer names?
930  std::swap(input_version, this->version());
931  const bool read_extra_integers = this->version_at_least_1_5();
932  std::swap(input_version, this->version());
933 
934  if (read_extra_integers)
935  this->read_integers_names<file_id_type>
936  (io, node_integer_names, elem_integer_names);
937  }
938 
939  // broadcast data from processor 0, set values everywhere
940  this->comm().broadcast(mesh_dimension);
941  mesh.set_mesh_dimension(cast_int<unsigned char>(mesh_dimension));
942 
943  this->comm().broadcast(input_parallel);
944 
945  if (input_parallel)
946  this->comm().broadcast(input_n_procs);
947  else
948  input_n_procs = 1;
949 
950  std::map<subdomain_id_type, std::string> & subdomain_map =
952  this->comm().broadcast(subdomain_map);
953 
954  BoundaryInfo & boundary_info = mesh.get_boundary_info();
955  this->comm().broadcast(boundary_info.set_sideset_name_map());
956  this->comm().broadcast(boundary_info.set_nodeset_name_map());
957 
958  this->comm().broadcast(node_integer_names);
959  this->comm().broadcast(elem_integer_names);
960 
961  for (auto & int_name : node_integer_names)
962  mesh.add_node_integer(int_name);
963 
964  for (auto & int_name : elem_integer_names)
965  mesh.add_elem_integer(int_name);
966 
967  return input_parallel ? input_n_procs : 0;
968 }
969 
970 
971 
972 template <typename file_id_type>
973 void CheckpointIO::read_subfile (Xdr & io, bool expect_all_remote)
974 {
975  // read the nodal locations
976  this->read_nodes<file_id_type> (io);
977 
978  // read connectivity
979  this->read_connectivity<file_id_type> (io);
980 
981  // read remote_elem connectivity
982  this->read_remote_elem<file_id_type> (io, expect_all_remote);
983 
984  // read the boundary conditions
985  this->read_bcs<file_id_type> (io);
986 
987  // read the nodesets
988  this->read_nodesets<file_id_type> (io);
989 }
990 
991 
992 
993 template <typename file_id_type>
995 {
997 
998  std::map<subdomain_id_type, std::string> & subdomain_map =
1000 
1001  std::vector<file_id_type> subdomain_ids;
1002  subdomain_ids.reserve(subdomain_map.size());
1003 
1004  std::vector<std::string> subdomain_names;
1005  subdomain_names.reserve(subdomain_map.size());
1006 
1007  file_id_type n_subdomain_names = 0;
1008  io.data(n_subdomain_names, "# subdomain id to name map");
1009 
1010  if (n_subdomain_names)
1011  {
1012  io.data(subdomain_ids);
1013  io.data(subdomain_names);
1014 
1015  for (auto i : index_range(subdomain_ids))
1016  subdomain_map[cast_int<subdomain_id_type>(subdomain_ids[i])] =
1017  subdomain_names[i];
1018  }
1019 }
1020 
1021 
1022 
1023 template <typename file_id_type>
1025 {
1026  // convenient reference to our mesh
1028 
1029  file_id_type n_nodes_here;
1030  io.data(n_nodes_here, "# n_nodes on proc");
1031 
1032  const bool read_extra_integers = this->version_at_least_1_5();
1033 
1034  const unsigned int n_extra_integers =
1035  read_extra_integers ? mesh.n_node_integers() : 0;
1036 
1037  // Will hold the node id and pid and extra integers
1038  std::vector<file_id_type> id_pid(2 + n_extra_integers);
1039 
1040  // For the coordinates
1041  std::vector<Real> coords(LIBMESH_DIM);
1042 
1043  for (unsigned int i=0; i<n_nodes_here; i++)
1044  {
1045  io.data_stream(id_pid.data(), 2 + n_extra_integers, 2 + n_extra_integers);
1046 
1047 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1048  file_id_type unique_id = 0;
1049  io.data(unique_id, "# unique id");
1050 #endif
1051 
1052  io.data_stream(coords.data(), LIBMESH_DIM, LIBMESH_DIM);
1053 
1054  Point p;
1055  p(0) = coords[0];
1056 
1057 #if LIBMESH_DIM > 1
1058  p(1) = coords[1];
1059 #endif
1060 
1061 #if LIBMESH_DIM > 2
1062  p(2) = coords[2];
1063 #endif
1064 
1065  const dof_id_type id = cast_int<dof_id_type>(id_pid[0]);
1066 
1067  // "Wrap around" if we see more processors than we're using.
1068  processor_id_type pid =
1069  cast_int<processor_id_type>(id_pid[1] % mesh.n_processors());
1070 
1071  // If we already have this node (e.g. from another file, when
1072  // reading multiple distributed CheckpointIO files into a
1073  // ReplicatedMesh) then we don't want to add it again (because
1074  // ReplicatedMesh can't handle that) but we do want to assert
1075  // consistency between what we're reading and what we have.
1076  const Node * old_node = mesh.query_node_ptr(id);
1077 
1078  if (old_node)
1079  {
1080  libmesh_assert_equal_to(pid, old_node->processor_id());
1081 
1082  libmesh_assert_equal_to(n_extra_integers, old_node->n_extra_integers());
1083 #ifndef NDEBUG
1084  for (unsigned int ei=0; ei != n_extra_integers; ++ei)
1085  {
1086  const dof_id_type extra_int = cast_int<dof_id_type>(id_pid[2+ei]);
1087  libmesh_assert_equal_to(extra_int, old_node->get_extra_integer(ei));
1088  }
1089 #endif
1090 
1091 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1092  libmesh_assert_equal_to(unique_id, old_node->unique_id());
1093 #endif
1094  }
1095  else
1096  {
1097  Node * node =
1098  mesh.add_point(p, id, pid);
1099 
1100 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1101  node->set_unique_id() = unique_id;
1102 #endif
1103 
1104  libmesh_assert_equal_to(n_extra_integers, node->n_extra_integers());
1105 
1106  for (unsigned int ei=0; ei != n_extra_integers; ++ei)
1107  {
1108  const dof_id_type extra_int = cast_int<dof_id_type>(id_pid[2+ei]);
1109  node->set_extra_integer(ei, extra_int);
1110  }
1111  }
1112  }
1113 }
1114 
1115 
1116 
1117 template <typename file_id_type>
1119 {
1120  // convenient reference to our mesh
1122 
1123  const bool read_extra_integers = this->version_at_least_1_5();
1124 
1125  const unsigned int n_extra_integers =
1126  read_extra_integers ? mesh.n_elem_integers() : 0;
1127 
1128  file_id_type n_elems_here;
1129  io.data(n_elems_here);
1130 
1131  // Keep track of the highest dimensional element we've added to the mesh
1132  unsigned int highest_elem_dim = 1;
1133 
1134  // RHS: Originally we used invalid_processor_id as a "no parent" tag
1135  // number, because I'm an idiot. Let's try to support broken files
1136  // as much as possible.
1137  bool file_is_broken = false;
1138 
1139  for (unsigned int i=0; i<n_elems_here; i++)
1140  {
1141  // id type pid subdomain_id parent_id
1142  std::vector<file_id_type> elem_data(6 + n_extra_integers);
1143  io.data_stream
1144  (elem_data.data(), cast_int<unsigned int>(elem_data.size()),
1145  cast_int<unsigned int>(elem_data.size()));
1146 
1147 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1148  file_id_type unique_id = 0;
1149  io.data(unique_id, "# unique id");
1150 #endif
1151 
1152 #ifdef LIBMESH_ENABLE_AMR
1153  uint16_t p_level = 0;
1154  io.data(p_level, "# p_level");
1155 
1156  uint16_t rflag, pflag;
1157  io.data(rflag, "# rflag");
1158  io.data(pflag, "# pflag");
1159 #endif
1160 
1161  unsigned int n_nodes = Elem::type_to_n_nodes_map[elem_data[1]];
1162 
1163  // Snag the node ids this element was connected to
1164  std::vector<file_id_type> conn_data(n_nodes);
1165  io.data_stream
1166  (conn_data.data(), cast_int<unsigned int>(conn_data.size()),
1167  cast_int<unsigned int>(conn_data.size()));
1168 
1169  const dof_id_type id =
1170  cast_int<dof_id_type> (elem_data[0]);
1171  const ElemType elem_type =
1172  static_cast<ElemType> (elem_data[1]);
1173  const processor_id_type proc_id =
1174  cast_int<processor_id_type>
1175  (elem_data[2] % mesh.n_processors());
1176  const subdomain_id_type subdomain_id =
1177  cast_int<subdomain_id_type>(elem_data[3]);
1178 
1179  // Old broken files used processsor_id_type(-1)...
1180  // But we *know* our first element will be level 0
1181  if (i == 0 && elem_data[4] == 65535)
1182  file_is_broken = true;
1183 
1184  // On a broken file we can't tell whether a parent of 65535 is a
1185  // null parent or an actual parent of 65535. Assuming the
1186  // former will cause less breakage.
1187  Elem * parent =
1188  (elem_data[4] == static_cast<largest_id_type>(-1) ||
1189  (file_is_broken && elem_data[4] == 65535)) ?
1190  nullptr : mesh.elem_ptr(cast_int<dof_id_type>(elem_data[4]));
1191 
1192  const unsigned short int child_num =
1193  (elem_data[5] == static_cast<largest_id_type>(-1) ||
1194  (file_is_broken && elem_data[5] == 65535)) ?
1195  static_cast<unsigned short>(-1) :
1196  cast_int<unsigned short>(elem_data[5]);
1197 
1198  if (!parent)
1199  libmesh_assert_equal_to
1200  (child_num, static_cast<unsigned short>(-1));
1201 
1202  Elem * old_elem = mesh.query_elem_ptr(id);
1203 
1204  // If we already have this element (e.g. from another file,
1205  // when reading multiple distributed CheckpointIO files into
1206  // a ReplicatedMesh) then we don't want to add it again
1207  // (because ReplicatedMesh can't handle that) but we do want
1208  // to assert consistency between what we're reading and what
1209  // we have.
1210  if (old_elem)
1211  {
1212  libmesh_assert_equal_to(elem_type, old_elem->type());
1213  libmesh_assert_equal_to(proc_id, old_elem->processor_id());
1214  libmesh_assert_equal_to(subdomain_id, old_elem->subdomain_id());
1215  if (parent)
1216  libmesh_assert_equal_to(parent, old_elem->parent());
1217  else
1218  libmesh_assert(!old_elem->parent());
1219 
1220  libmesh_assert_equal_to(n_extra_integers, old_elem->n_extra_integers());
1221 #ifndef NDEBUG
1222  for (unsigned int ei=0; ei != n_extra_integers; ++ei)
1223  {
1224  const dof_id_type extra_int = cast_int<dof_id_type>(elem_data[6+ei]);
1225  libmesh_assert_equal_to(extra_int, old_elem->get_extra_integer(ei));
1226  }
1227 #endif
1228 
1229  libmesh_assert_equal_to(old_elem->n_nodes(), conn_data.size());
1230 
1231  for (unsigned int n=0,
1232  n_conn = cast_int<unsigned int>(conn_data.size());
1233  n != n_conn; n++)
1234  libmesh_assert_equal_to
1235  (old_elem->node_id(n),
1236  cast_int<dof_id_type>(conn_data[n]));
1237  }
1238  else
1239  {
1240  // Create the element
1241  Elem * elem = Elem::build(elem_type, parent).release();
1242 
1243 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1244  elem->set_unique_id() = unique_id;
1245 #endif
1246 
1247  if (elem->dim() > highest_elem_dim)
1248  highest_elem_dim = elem->dim();
1249 
1250  elem->set_id() = id;
1251  elem->processor_id() = proc_id;
1252  elem->subdomain_id() = subdomain_id;
1253 
1254 #ifdef LIBMESH_ENABLE_AMR
1255  elem->hack_p_level(p_level);
1256 
1257  elem->set_refinement_flag (cast_int<Elem::RefinementState>(rflag));
1258  elem->set_p_refinement_flag(cast_int<Elem::RefinementState>(pflag));
1259 
1260  // Set parent connections
1261  if (parent)
1262  {
1263  // We must specify a child_num, because we will have
1264  // skipped adding any preceding remote_elem children
1265  parent->add_child(elem, child_num);
1266  }
1267 #else
1268  libmesh_ignore(child_num);
1269 #endif
1270 
1271  libmesh_assert(elem->n_nodes() == conn_data.size());
1272 
1273  // Connect all the nodes to this element
1274  for (unsigned int n=0,
1275  n_conn = cast_int<unsigned int>(conn_data.size());
1276  n != n_conn; n++)
1277  elem->set_node(n) =
1278  mesh.node_ptr(cast_int<dof_id_type>(conn_data[n]));
1279 
1280  mesh.add_elem(elem);
1281 
1282  libmesh_assert_equal_to(n_extra_integers, elem->n_extra_integers());
1283  for (unsigned int ei=0; ei != n_extra_integers; ++ei)
1284  {
1285  const dof_id_type extra_int = cast_int<dof_id_type>(elem_data[6+ei]);
1286  elem->set_extra_integer(ei, extra_int);
1287  }
1288  }
1289  }
1290 
1291  mesh.set_mesh_dimension(cast_int<unsigned char>(highest_elem_dim));
1292 }
1293 
1294 
1295 template <typename file_id_type>
1296 void CheckpointIO::read_remote_elem (Xdr & io, bool libmesh_dbg_var(expect_all_remote))
1297 {
1298  // convenient reference to our mesh
1300 
1301  // Find the remote_elem neighbor links
1302  std::vector<file_id_type> elem_ids;
1303  std::vector<uint16_t> elem_sides;
1304 
1305  io.data(elem_ids, "# remote neighbor elem_ids");
1306  io.data(elem_sides, "# remote neighbor elem_sides");
1307 
1308  libmesh_assert_equal_to(elem_ids.size(), elem_sides.size());
1309 
1310  for (auto i : index_range(elem_ids))
1311  {
1312  Elem & elem = mesh.elem_ref(cast_int<dof_id_type>(elem_ids[i]));
1313  if (!elem.neighbor_ptr(elem_sides[i]))
1314  elem.set_neighbor(elem_sides[i],
1315  const_cast<RemoteElem *>(remote_elem));
1316  else
1317  libmesh_assert(!expect_all_remote);
1318  }
1319 
1320  // Find the remote_elem children links
1321  std::vector<file_id_type> parent_ids;
1322  std::vector<uint16_t> child_numbers;
1323 
1324  io.data(parent_ids, "# remote child parent_ids");
1325  io.data(child_numbers, "# remote child_numbers");
1326 
1327 #ifdef LIBMESH_ENABLE_AMR
1328  for (auto i : index_range(parent_ids))
1329  {
1330  Elem & elem = mesh.elem_ref(cast_int<dof_id_type>(parent_ids[i]));
1331 
1332  // We'd like to assert that no child pointer already exists to
1333  // be overwritten by remote_elem, but Elem doesn't actually have
1334  // an API that will return a child pointer without asserting
1335  // that it isn't nullptr.
1336  const Elem * child = elem.raw_child_ptr(child_numbers[i]);
1337 
1338  if (!child)
1339  elem.add_child(const_cast<RemoteElem *>(remote_elem),
1340  child_numbers[i]);
1341  else
1342  libmesh_assert(!expect_all_remote);
1343  }
1344 #endif
1345 }
1346 
1347 
1348 
1349 template <typename file_id_type>
1351 {
1352  // convenient reference to our mesh
1354 
1355  // and our boundary info object
1356  BoundaryInfo & boundary_info = mesh.get_boundary_info();
1357 
1358  std::vector<file_id_type> element_id_list;
1359  std::vector<uint16_t> side_list;
1360  std::vector<file_id_type> bc_id_list;
1361 
1362  io.data(element_id_list, "# element ids for bcs");
1363  io.data(side_list, "# sides of elements for bcs");
1364  io.data(bc_id_list, "# bc ids");
1365 
1366  for (auto i : index_range(element_id_list))
1367  boundary_info.add_side
1368  (cast_int<dof_id_type>(element_id_list[i]), side_list[i],
1369  cast_int<boundary_id_type>(bc_id_list[i]));
1370 }
1371 
1372 
1373 
1374 template <typename file_id_type>
1376 {
1377  // convenient reference to our mesh
1379 
1380  // and our boundary info object
1381  BoundaryInfo & boundary_info = mesh.get_boundary_info();
1382 
1383  std::vector<file_id_type> node_id_list;
1384  std::vector<file_id_type> bc_id_list;
1385 
1386  io.data(node_id_list, "# node id list");
1387  io.data(bc_id_list, "# nodeset bc id list");
1388 
1389  for (auto i : index_range(node_id_list))
1390  boundary_info.add_node
1391  (cast_int<dof_id_type>(node_id_list[i]),
1392  cast_int<boundary_id_type>(bc_id_list[i]));
1393 }
1394 
1395 
1396 
1397 template <typename file_id_type>
1398 void CheckpointIO::read_bc_names(Xdr & io, BoundaryInfo & info, bool is_sideset)
1399 {
1400  std::map<boundary_id_type, std::string> & boundary_map = is_sideset ?
1402 
1403  std::vector<file_id_type> boundary_ids;
1404  std::vector<std::string> boundary_names;
1405 
1406  file_id_type n_boundary_names = 0;
1407 
1408  if (is_sideset)
1409  io.data(n_boundary_names, "# sideset id to name map");
1410  else
1411  io.data(n_boundary_names, "# nodeset id to name map");
1412 
1413  if (n_boundary_names)
1414  {
1415  io.data(boundary_ids);
1416  io.data(boundary_names);
1417  }
1418 
1419  // Add them back into the map
1420  for (auto i : index_range(boundary_ids))
1421  boundary_map[cast_int<boundary_id_type>(boundary_ids[i])] =
1422  boundary_names[i];
1423 }
1424 
1425 
1426 template <typename file_id_type>
1428  (Xdr & io,
1429  std::vector<std::string> & node_integer_names,
1430  std::vector<std::string> & elem_integer_names)
1431 {
1432  file_id_type n_node_integers, n_elem_integers;
1433 
1434  io.data(n_node_integers, "# n_extra_integers per node");
1435  io.data(node_integer_names);
1436  io.data(n_elem_integers, "# n_extra_integers per elem");
1437  io.data(elem_integer_names);
1438 }
1439 
1440 
1443 {
1444  unsigned int max_level = 0;
1445 
1446  for (const auto & elem : as_range(begin, end))
1447  max_level = std::max(elem->level(), max_level);
1448 
1449  return max_level + 1;
1450 }
1451 
1452 } // namespace libMesh
libMesh::connect_children
void connect_children(const MeshBase &mesh, MeshBase::const_element_iterator elem_it, MeshBase::const_element_iterator elem_end, std::set< const Elem *, CompareElemIdsByLevel > &connected_elements)
Definition: mesh_communication.C:169
libMesh::CheckpointIO::select_split_config
processor_id_type select_split_config(const std::string &input_name, header_id_type &data_size)
Definition: checkpoint_io.C:186
libMesh::CheckpointIO::read_bcs
void read_bcs(Xdr &io)
Read the boundary conditions for a parallel, distributed mesh.
Definition: checkpoint_io.C:1350
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::Elem::child_ptr
const Elem * child_ptr(unsigned int i) const
Definition: elem.h:2567
libMesh::BoundaryInfo
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
Definition: boundary_info.h:57
libMesh::CheckpointIO::write_nodesets
void write_nodesets(Xdr &io, const std::set< const Node * > &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.
Definition: checkpoint_io.C:741
libMesh::Elem::set_p_refinement_flag
void set_p_refinement_flag(const RefinementState pflag)
Sets the value of the p-refinement flag for the element.
Definition: elem.h:2638
libMesh::CheckpointIO::parallel
bool parallel() const
Get/Set the flag indicating if we should read/write binary.
Definition: checkpoint_io.h:151
libMesh::MeshBase::get_boundary_info
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:132
libMesh::MeshBase::is_serial
virtual bool is_serial() const
Definition: mesh_base.h:159
libMesh::Elem::n_nodes
virtual unsigned int n_nodes() const =0
libMesh::BoundaryInfo::add_node
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
Definition: boundary_info.C:636
libMesh::CheckpointIO::_my_processor_ids
std::vector< processor_id_type > _my_processor_ids
Definition: checkpoint_io.h:332
libMesh::MeshBase::n_elem
virtual dof_id_type n_elem() const =0
libMesh::DofObject::set_id
dof_id_type & set_id()
Definition: dof_object.h:776
libMesh::MeshBase::elem_ref
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:521
libMesh::index_range
IntRange< std::size_t > index_range(const std::vector< T > &vec)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:106
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::Elem::dim
virtual unsigned short dim() const =0
libMesh::Xdr
This class implements a C++ interface to the XDR (eXternal Data Representation) format.
Definition: xdr_cxx.h:65
libMesh::Elem::add_child
void add_child(Elem *elem)
Adds a child pointer to the array of children of this element.
Definition: elem.C:1384
libMesh::CheckpointIO::version
const std::string & version() const
Get/Set the version string.
Definition: checkpoint_io.h:157
libMesh::reconnect_nodes
void reconnect_nodes(const std::set< const Elem *, CompareElemIdsByLevel > &connected_elements, std::set< const Node * > &connected_nodes)
Definition: mesh_communication.C:259
end
IterBase * end
Also have a polymorphic pointer to the end object, this prevents iterating past the end.
Definition: variant_filter_iterator.h:343
libMesh::CheckpointIO::write_bc_names
void write_bc_names(Xdr &io, const BoundaryInfo &info, bool is_sideset) const
Write boundary names information (sideset and nodeset)
Definition: checkpoint_io.C:772
libMesh::ParallelObject::comm
const Parallel::Communicator & comm() const
Definition: parallel_object.h:94
libMesh::Elem::set_neighbor
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
Definition: elem.h:2105
libMesh::MeshBase::set_subdomain_name_map
std::map< subdomain_id_type, std::string > & set_subdomain_name_map()
Definition: mesh_base.h:1631
libMesh::BoundaryInfo::get_sideset_name_map
const std::map< boundary_id_type, std::string > & get_sideset_name_map() const
Definition: boundary_info.h:876
libMesh::CheckpointIO::read_subdomain_names
void read_subdomain_names(Xdr &io)
Read subdomain name information.
Definition: checkpoint_io.C:994
libMesh::MeshTools::max_level
unsigned int max_level(const MeshBase &mesh)
Find the maximum h-refinement level in a mesh.
libMesh::MeshBase::set_distributed
virtual void set_distributed()
Asserts that not all elements and nodes of the mesh necessarily exist on the current processor.
Definition: mesh_base.h:174
libMesh::WRITE
Definition: enum_xdr_mode.h:40
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::MeshBase::node_ptr
virtual const Node * node_ptr(const dof_id_type i) const =0
libMesh::MeshBase::mesh_dimension
unsigned int mesh_dimension() const
Definition: mesh_base.C:135
libMesh::DofObject::set_unique_id
unique_id_type & set_unique_id()
Definition: dof_object.h:797
libMesh::largest_id_type
uint64_t largest_id_type
Definition: id_types.h:148
libMesh::CheckpointIO::header_id_type
uint64_t header_id_type
Definition: checkpoint_io.h:69
libMesh::DofObject::processor_id
processor_id_type processor_id() const
Definition: dof_object.h:829
libMesh::MeshBase::elem_ptr
virtual const Elem * elem_ptr(const dof_id_type i) const =0
libMesh::MeshBase::elements_begin
virtual element_iterator elements_begin()=0
Iterate over all the elements in the Mesh.
libMesh::MeshBase::query_elem_ptr
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
libMesh::BoundaryInfo::build_side_list
void build_side_list(std::vector< dof_id_type > &element_id_list, std::vector< unsigned short int > &side_list, std::vector< boundary_id_type > &bc_id_list) const
Creates a list of element numbers, sides, and ids for those sides.
Definition: boundary_info.C:1976
libMesh::MeshBase::element_ptr_range
virtual SimpleRange< element_iterator > element_ptr_range()=0
libMesh::CheckpointIO::cleanup
static void cleanup(const std::string &input_name, processor_id_type n_procs)
Used to remove a checkpoint directory and its corresponding files.
Definition: checkpoint_io.C:251
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::MeshCommunication::broadcast
void broadcast(MeshBase &) const
Definition: mesh_communication.C:1084
libMesh::Xdr::writing
bool writing() const
Definition: xdr_cxx.h:116
libMesh::DofObject::n_extra_integers
unsigned int n_extra_integers() const
Returns how many extra integers are associated to the DofObject.
Definition: dof_object.h:1082
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
libMesh::Xdr::data
void data(T &a, const char *comment="")
Inputs or outputs a single value.
Definition: xdr_cxx.C:766
libMesh::ParallelObject::n_processors
processor_id_type n_processors() const
Definition: parallel_object.h:100
libMesh::DECODE
Definition: enum_xdr_mode.h:39
libMesh::CheckpointIO::write_nodes
void write_nodes(Xdr &io, const std::set< const Node * > &nodeset) const
Write the nodal locations for part of a mesh.
Definition: checkpoint_io.C:530
libMesh::CheckpointIO::read_nodes
void read_nodes(Xdr &io)
Read the nodal locations for a parallel, distributed mesh.
Definition: checkpoint_io.C:1024
libMesh::ParallelObject::processor_id
processor_id_type processor_id() const
Definition: parallel_object.h:106
libMesh::libmesh_ignore
void libmesh_ignore(const Args &...)
Definition: libmesh_common.h:526
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::processor_id_type
uint8_t processor_id_type
Definition: id_types.h:104
libMesh::CheckpointIO::binary
bool binary() const
Get/Set the flag indicating if we should read/write binary.
Definition: checkpoint_io.h:145
libMesh::MeshBase::add_elem_integer
unsigned int add_elem_integer(const std::string &name, bool allocate_data=true)
Register an integer datum (of type dof_id_type) to be added to each element in the mesh.
Definition: mesh_base.C:176
libMesh::CheckpointIO::version_at_least_1_5
bool version_at_least_1_5() const
Definition: checkpoint_io.C:277
libMesh::Node
A Node is like a Point, but with more information.
Definition: node.h:52
libMesh::Elem::raw_child_ptr
const Elem * raw_child_ptr(unsigned int i) const
Definition: elem.h:2558
libMesh::split_mesh
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.
Definition: checkpoint_io.C:134
libMesh::CheckpointIO::read_connectivity
void read_connectivity(Xdr &io)
Read the connectivity for a parallel, distributed mesh.
Definition: checkpoint_io.C:1118
libMesh::CheckpointIO::read_bc_names
void read_bc_names(Xdr &io, BoundaryInfo &info, bool is_sideset)
Read boundary names information (sideset and nodeset)
Definition: checkpoint_io.C:1398
libMesh::CheckpointIO::n_active_levels_in
unsigned int n_active_levels_in(MeshBase::const_element_iterator begin, MeshBase::const_element_iterator end) const
Definition: checkpoint_io.C:1441
libMesh::as_range
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
Definition: simple_range.h:57
libMesh::CheckpointIO::~CheckpointIO
virtual ~CheckpointIO()
Destructor.
Definition: checkpoint_io.C:182
libMesh::MeshBase::add_node_integer
unsigned int add_node_integer(const std::string &name, bool allocate_data=true)
Register an integer datum (of type dof_id_type) to be added to each node in the mesh.
Definition: mesh_base.C:247
libMesh::MeshBase::get_node_integer_name
const std::string & get_node_integer_name(unsigned int i) const
Definition: mesh_base.h:915
libMesh::CheckpointIO::read_nodesets
void read_nodesets(Xdr &io)
Read the nodeset conditions for a parallel, distributed mesh.
Definition: checkpoint_io.C:1375
n_nodes
const dof_id_type n_nodes
Definition: tecplot_io.C:68
libMesh::READ
Definition: enum_xdr_mode.h:41
libMesh::MeshBase::const_element_iterator
The definition of the const_element_iterator struct.
Definition: mesh_base.h:1891
libMesh::Xdr::data_stream
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:831
libMesh::MeshBase::get_subdomain_name_map
const std::map< subdomain_id_type, std::string > & get_subdomain_name_map() const
Definition: mesh_base.h:1633
libMesh::MeshBase::n_elem_integers
unsigned int n_elem_integers() const
Definition: mesh_base.h:829
libMesh::CheckpointIO::read
virtual void read(const std::string &input_name) override
This method implements reading a mesh from a specified file.
Definition: checkpoint_io.C:804
libMesh::query_ghosting_functors
void query_ghosting_functors(const MeshBase &mesh, processor_id_type pid, MeshBase::const_element_iterator elem_it, MeshBase::const_element_iterator elem_end, std::set< const Elem *, CompareElemIdsByLevel > &connected_elements)
Definition: mesh_communication.C:138
libMesh::CheckpointIO::_version
std::string _version
Definition: checkpoint_io.h:329
libMesh::Elem::set_node
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2059
libMesh::CheckpointIO::read_remote_elem
void read_remote_elem(Xdr &io, bool expect_all_remote)
Read the remote_elem neighbor and child links for a parallel, distributed mesh.
libMesh::Utility::mkdir
int mkdir(const char *pathname)
Create a directory.
Definition: utility.C:140
libMesh::MeshBase::n_node_integers
unsigned int n_node_integers() const
Definition: mesh_base.h:926
libMesh::Elem::parent
const Elem * parent() const
Definition: elem.h:2434
libMesh::CheckpointIO::write_remote_elem
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.
Definition: checkpoint_io.C:655
libMesh::connect_families
void connect_families(std::set< const Elem *, CompareElemIdsByLevel > &connected_elements)
Definition: mesh_communication.C:192
libMesh::ENCODE
Definition: enum_xdr_mode.h:38
libMesh::CheckpointIO::CheckpointIO
CheckpointIO(MeshBase &, const bool=false)
Constructor.
Definition: checkpoint_io.C:160
libMesh::MeshOutput
This class defines an abstract interface for Mesh output.
Definition: mesh_output.h:53
swap
void swap(Iterator &lhs, Iterator &rhs)
swap, used to implement op=
Definition: variant_filter_iterator.h:478
libMesh::Xdr::close
void close()
Closes the file if it is open.
Definition: xdr_cxx.C:273
libMesh::MeshOutput::mesh
const MT & mesh() const
Definition: mesh_output.h:247
libMesh::Elem::type_to_n_nodes_map
static const 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:576
libMesh::BoundaryInfo::set_nodeset_name_map
std::map< boundary_id_type, std::string > & set_nodeset_name_map()
Definition: boundary_info.h:882
libMesh::CheckpointIO::write_subdomain_names
void write_subdomain_names(Xdr &io) const
Write subdomain name information.
Definition: checkpoint_io.C:496
libMesh::DofObject::get_extra_integer
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...
Definition: dof_object.h:1026
libMesh::MeshBase::add_elem
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
libMesh::BoundaryInfo::build_node_list
void build_node_list(std::vector< dof_id_type > &node_id_list, std::vector< boundary_id_type > &bc_id_list) const
Creates a list of nodes and ids for those nodes.
Definition: boundary_info.C:1704
libMesh::Elem::subdomain_id
subdomain_id_type subdomain_id() const
Definition: elem.h:2069
libMesh::CheckpointIO::_my_n_processors
processor_id_type _my_n_processors
Definition: checkpoint_io.h:335
libMesh::MeshBase::elements_end
virtual element_iterator elements_end()=0
libMesh::CheckpointIO::read_header
file_id_type read_header(const std::string &name)
Read header data on processor 0, then broadcast.
Definition: checkpoint_io.C:884
libMesh::DofObject::invalid_processor_id
static const processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
Definition: dof_object.h:432
libMesh::CheckpointIO::write
virtual void write(const std::string &name) override
This method implements writing a mesh to a specified file.
Definition: checkpoint_io.C:283
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::CheckpointIO::_parallel
bool _parallel
Definition: checkpoint_io.h:328
libMesh::Threads::split
tbb::split split
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
Definition: threads_tbb.h:79
libMesh::MeshInput< MeshBase >::mesh
MeshBase & mesh()
Definition: mesh_input.h:169
libMesh::Elem::set_refinement_flag
void set_refinement_flag(const RefinementState rflag)
Sets the value of the refinement flag for the element.
Definition: elem.h:2622
libMesh::MeshBase::add_point
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.
libMesh::CheckpointIO::write_bcs
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.
Definition: checkpoint_io.C:704
libMesh::Elem::neighbor_ptr
const Elem * neighbor_ptr(unsigned int i) const
Definition: elem.h:2085
libMesh::TestClass
Definition: id_types.h:33
libMesh::Elem::node_id
dof_id_type node_id(const unsigned int i) const
Definition: elem.h:1977
libMesh::DofObject::set_extra_integer
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...
Definition: dof_object.h:1010
libMesh::CheckpointIO::write_connectivity
void write_connectivity(Xdr &io, const std::set< const Elem *, CompareElemIdsByLevel > &elements) const
Write the connectivity for part of a mesh.
Definition: checkpoint_io.C:580
libMesh::ParallelObject
An object whose state is distributed along a set of processors.
Definition: parallel_object.h:55
libMesh::MeshCommunication
This is the MeshCommunication class.
Definition: mesh_communication.h:50
libMesh::MeshBase::set_mesh_dimension
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition: mesh_base.h:218
libMesh::Elem::build
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:246
libMesh::MeshBase::query_node_ptr
virtual const Node * query_node_ptr(const dof_id_type i) const =0
libMesh::Predicates::Active
Used to iterate over non-nullptr, active entries in a container.
Definition: multi_predicates.h:152
libMesh::BoundaryInfo::add_side
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.
Definition: boundary_info.C:886
libMesh::Elem::hack_p_level
void hack_p_level(const unsigned int p)
Sets the value of the p-refinement level for the element without altering the p-level of its ancestor...
Definition: elem.h:2668
libMesh::BoundaryInfo::get_nodeset_name_map
const std::map< boundary_id_type, std::string > & get_nodeset_name_map() const
Definition: boundary_info.h:884
libMesh::BoundaryInfo::set_sideset_name_map
std::map< boundary_id_type, std::string > & set_sideset_name_map()
Definition: boundary_info.h:874
libMesh::Elem::type
virtual ElemType type() const =0
libMesh::remote_elem
const RemoteElem * remote_elem
Definition: remote_elem.C:57
libMesh::Quality::name
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
libMesh::MeshInput
This class defines an abstract interface for Mesh input.
Definition: mesh_base.h:60
libMesh::MeshBase::is_replicated
virtual bool is_replicated() const
Definition: mesh_base.h:181
libMesh::CheckpointIO::read_subfile
void read_subfile(Xdr &io, bool expect_all_remote)
Read a non-header file.
Definition: checkpoint_io.C:973
libMesh::MeshBase::get_elem_integer_name
const std::string & get_elem_integer_name(unsigned int i) const
Definition: mesh_base.h:818
libMesh::ElemType
ElemType
Defines an enum for geometric element types.
Definition: enum_elem_type.h:33
libMesh::Predicates::NotNull
Used to iterate over non-nullptr entries in a container.
Definition: multi_predicates.h:137
libMesh::CheckpointIO::read_integers_names
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.
Definition: checkpoint_io.C:1428
libMesh::MeshBase::partition
virtual void partition(const unsigned int n_parts)
Call the default partitioner (currently metis_partition()).
Definition: mesh_base.C:599