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"
54#include <unordered_map>
55#include <unordered_set>
56#ifdef LIBMESH_HAVE_DIRECT_H
59#ifdef LIBMESH_HAVE_UNISTD_H
71 if (nsplits % size == 0)
73 nchunks = nsplits / size;
74 first_chunk = libMesh::cast_int<libMesh::processor_id_type>(nchunks * rank);
81 nchunks = libMesh::cast_int<libMesh::processor_id_type>(nsplits / size + 1);
82 first_chunk = libMesh::cast_int<libMesh::processor_id_type>(nchunks * rank);
86 nchunks = nsplits / size;
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()));
94std::string_view extension(std::string_view s)
96 auto pos = s.rfind(
".");
97 if (pos == std::string::npos)
99 return s.substr(pos, s.size() - pos);
104 return input_name +
"/" + std::to_string(n_procs);
110 return (split_dir(input_name, n_procs) +
"/header").append(extension(input_name));
114split_file(
const std::string & input_name,
118 return (split_dir(input_name, n_procs) +
"/split-" + std::to_string(n_procs) +
"-" +
119 std::to_string(proc_id)).append(extension(input_name));
125std::string existing_splits(
const std::string & input_name)
128 if (!std::filesystem::is_directory(input_name, ec))
131 std::vector<std::string> splits;
132 for (
const auto & entry :
std::filesystem::directory_iterator(input_name, ec))
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);
139 std::sort(splits.begin(), splits.end());
142 for (
const auto & split : splits)
143 list += (list.empty() ?
"" :
", ") +
split;
152 (ret != 0 && ret != -1,
153 "Failed to create mesh split directory '" << input_name <<
"': " << std::strerror(ret));
155 auto dir_name = split_dir(input_name, n_procs);
158 libmesh_warning(
"In CheckpointIO::write, directory '"
159 << dir_name <<
"' already exists, overwriting contents.");
162 (ret != 0,
"Failed to create mesh split directory '" << dir_name <<
"': " << std::strerror(ret));
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;
202 _version (
"checkpoint-1.7"),
203 _my_processor_ids (1, processor_id()),
204 _my_n_processors (
mesh.is_replicated() ? 1 : n_processors())
214 _version (
"checkpoint-1.7"),
215 _my_processor_ids (1, processor_id()),
216 _my_n_processors (
mesh.is_replicated() ? 1 : n_processors())
224 std::string header_name;
233 std::ifstream in (header_name.c_str());
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 "
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"
249 ?
"No processor-count splits were found in '" + input_name +
"'."
250 :
"Splits that do exist in '" + input_name +
251 "': " + splits +
"."));
258 std::string input_version;
259 io.
data(input_version);
273 input_n_procs = this->read_header<uint16_t>(header_name);
276 input_n_procs = this->read_header<uint32_t>(header_name);
279 input_n_procs = this->read_header<uint64_t>(header_name);
287 return cast_int<processor_id_type>(input_n_procs);
292 auto header = header_file(input_name, n_procs);
293 auto ret = std::remove(header.c_str());
295 libmesh_warning(
"Failed to clean up checkpoint header '" << header <<
"': " << std::strerror(ret));
299 auto split = split_file(input_name, n_procs, i);
300 ret = std::remove(split.c_str());
302 libmesh_warning(
"Failed to clean up checkpoint split file '" << split <<
"': " << std::strerror(ret));
305 auto dir = split_dir(input_name, n_procs);
306 ret = rmdir(dir.c_str());
308 libmesh_warning(
"Failed to clean up checkpoint split dir '" << dir <<
"': " << std::strerror(ret));
312 rmdir(input_name.c_str());
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);
328 (this->
version().find(
"1.6") != std::string::npos) ||
329 (this->
version().find(
"1.7") != std::string::npos);
335 return (this->
version().find(
"1.7") != std::string::npos);
341 LOG_SCOPE(
"write()",
"CheckpointIO");
355 std::string header_file_name = header_file(name, use_n_procs);
356 make_dir(name, use_n_procs);
369 io.
data(data_size,
"# integer size");
375 io.
data(mesh_dimension,
"# dimensions");
389 io.
data(n_procs,
"# n_procs");
403 if (write_extra_integers)
406 io.
data(n_node_integers,
"# n_extra_integers per node");
408 std::vector<std::string> node_integer_names;
409 for (
unsigned int i=0; i != n_node_integers; ++i)
412 io.
data(node_integer_names);
415 io.
data(n_elem_integers,
"# n_extra_integers per elem");
417 std::vector<std::string> elem_integer_names;
418 for (
unsigned int i=0; i != n_elem_integers; ++i)
421 io.
data(elem_integer_names);
432 std::vector<processor_id_type> ids_to_write;
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;
447 elements_on_pid[p].clear();
448 auto eop_end = elements_on_pid.end();
449 for (
auto & elem :
mesh.element_ptr_range())
452 if (
auto eop_it = elements_on_pid.find(p);
454 eop_it->second.push_back(elem);
462 ids_to_write.push_back(0);
467 libmesh_error_msg(
"Cannot write serial checkpoint from distributed mesh");
473 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
475 std::vector<std::tuple<dof_id_type, boundary_id_type>>
478 for (
const auto & my_pid : ids_to_write)
480 auto file_name = split_file(name, use_n_procs, my_pid);
483 std::set<const Elem *, CompareElemIdsByLevel> elements;
488 elements.insert(
mesh.elements_begin(),
mesh.elements_end());
506 if (
const auto elements_vec_it = elements_on_pid.find(p);
507 elements_vec_it != elements_on_pid.end())
509 auto & p_elements = elements_vec_it->second;
515 v_t * elempp = p_elements.
data();
516 v_t * elemend = elempp + p_elements.size();
529 (
mesh, p, active_pid_elements_begin,
530 active_pid_elements_end, elements);
532 pid_elements_end, elements);
550 this->
write_bcs (io, elements, bc_triples);
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());
576 for (
const auto & [
id, name] : subdomain_map)
580 subdomain_ids.push_back(
id);
581 subdomain_names.push_back(name);
584 io.
data(n_subdomain_names,
"# subdomain id to name map");
586 if (n_subdomain_names)
588 io.
data(subdomain_ids);
589 io.
data(subdomain_names);
601 io.
data(n_nodes_here,
"# n_nodes on proc");
604 const unsigned int n_extra_integers =
608 std::vector<largest_id_type> id_pid(2 + n_extra_integers);
611 std::vector<Real> coords(LIBMESH_DIM);
613 for (
const auto & node : nodeset)
615 id_pid[0] = node->id();
616 id_pid[1] = node->processor_id();
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);
622 io.
data_stream(id_pid.data(), 2 + n_extra_integers, 2 + n_extra_integers);
624#ifdef LIBMESH_ENABLE_UNIQUE_ID
627 io.
data(unique_id,
"# unique id");
630 coords[0] = (*node)(0);
633 coords[1] = (*node)(1);
637 coords[2] = (*node)(2);
647 const std::set<const Elem *, CompareElemIdsByLevel> & elements)
const
653 const unsigned int n_extra_integers =
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;
664 io.
data(n_elems_here,
"# number of elements");
666 for (
const auto & elem : elements)
668 unsigned int n_nodes = elem->n_nodes();
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();
675#ifdef LIBMESH_ENABLE_AMR
676 if (elem->parent() !=
nullptr)
678 elem_data[4] = elem->parent()->id();
679 elem_data[5] = elem->parent()->which_child_am_i(elem);
688 for (
unsigned int i=0; i != n_extra_integers; ++i)
689 elem_data[6+i] = elem->get_extra_integer(i);
693 for (
unsigned int i=0; i<
n_nodes; i++)
694 conn_data[i] = elem->node_id(i);
697 cast_int<unsigned int>(elem_data.size()),
698 cast_int<unsigned int>(elem_data.size()));
700#ifdef LIBMESH_ENABLE_UNIQUE_ID
703 io.
data(unique_id,
"# unique id");
706#ifdef LIBMESH_ENABLE_AMR
707 uint16_t p_level = cast_int<uint16_t>(elem->p_level());
708 io.
data(p_level,
"# p_level");
710 uint16_t rflag = elem->refinement_flag();
711 io.
data(rflag,
"# rflag");
713 uint16_t pflag = elem->p_refinement_flag();
714 io.
data(pflag,
"# pflag");
717 if (elem->runtime_topology())
720 (!write_runtime_topology,
721 "Checkpoint format 1.6 or newer is required to write " <<
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())
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);
735 io.
data(runtime_topology,
"# runtime topology");
739 cast_int<unsigned int>(conn_data.size()),
740 cast_int<unsigned int>(conn_data.size()));
746 const std::set<const Elem *, CompareElemIdsByLevel> & elements)
const
751 std::vector<largest_id_type> elem_ids, parent_ids;
752 std::vector<uint16_t> elem_sides, child_numbers;
754 for (
const auto & elem : elements)
756 for (
auto n : elem->side_index_range())
760 (neigh && !elements.count(neigh)))
762 elem_ids.push_back(elem->id());
763 elem_sides.push_back(n);
767#ifdef LIBMESH_ENABLE_AMR
768 if (elem->has_children())
770 for (
unsigned short c = 0,
771 nc = cast_int<unsigned short>(elem->n_children());
776 (child && !elements.count(child)))
778 parent_ids.push_back(elem->id());
779 child_numbers.push_back(c);
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");
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
801 std::size_t bc_size = bc_triples.size();
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;
807 element_id_list.reserve(bc_size);
808 side_list.reserve(bc_size);
809 bc_id_list.reserve(bc_size);
811 std::unordered_set<dof_id_type> elems;
812 for (
auto & e : elements)
813 elems.insert(e->id());
815 for (
const auto & t : bc_triples)
816 if (elems.count(std::get<0>(t)))
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));
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");
833 const std::vector<std::tuple<dof_id_type, boundary_id_type>> & bc_tuples)
const
841 std::size_t nodeset_size = bc_tuples.size();
843 std::vector<largest_id_type> node_id_list;
844 std::vector<largest_id_type> bc_id_list;
846 node_id_list.reserve(nodeset_size);
847 bc_id_list.reserve(nodeset_size);
849 for (
const auto & t : bc_tuples)
852 node_id_list.push_back(std::get<0>(t));
853 bc_id_list.push_back(std::get<1>(t));
856 io.
data(node_id_list,
"# node id list");
857 io.
data(bc_id_list,
"# nodeset bc id list");
864 const std::map<boundary_id_type, std::string> & boundary_map = is_sideset ?
865 info.get_sideset_name_map() : info.get_nodeset_name_map();
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());
874 for (
const auto & [
id, name] : boundary_map)
878 boundary_ids.push_back(
id);
879 boundary_names.push_back(name);
883 io.
data(n_boundary_names,
"# sideset id to name map");
885 io.
data(n_boundary_names,
"# nodeset id to name map");
887 if (n_boundary_names)
889 io.
data(boundary_ids);
890 io.
data(boundary_names);
896 std::vector<largest_id_type> pair_ids;
897 std::vector<Real> translations;
899#ifdef LIBMESH_ENABLE_PERIODIC
905 for (
const auto & [
id, pb] : *db)
907 if (
id > pb->pairedboundary)
914 "CheckpointIO can only write translational disjoint neighbor "
917 pair_ids.push_back(
id);
918 pair_ids.push_back(pb->pairedboundary);
920 const Point translation = pb->get_corresponding_pos(
Point(0));
922 translations.push_back(translation(d));
927 io.
data(n_pairs,
"# disjoint neighbor boundary pairs");
934 cast_int<unsigned int>(translations.size()),
941 LOG_SCOPE(
"read()",
"CheckpointIO");
949 auto header_name = header_file(input_name, input_n_procs);
950 bool input_parallel = input_n_procs > 0;
969 proc_id = cast_int<processor_id_type>(proc_id + stride))
971 auto file_name = split_file(input_name, input_n_procs, proc_id);
974 std::ifstream in (file_name.c_str());
976 libmesh_error_msg_if(!in.good(),
"ERROR: cannot locate specified file:\n\t" << file_name);
982 const bool expect_all_remote =
990 this->read_subfile<uint16_t>(io, expect_all_remote);
993 this->read_subfile<uint32_t>(io, expect_all_remote);
996 this->read_subfile<uint64_t>(io, expect_all_remote);
1025template <
typename file_
id_type>
1031 uint16_t mesh_dimension;
1034 uint16_t input_parallel;
1035 file_id_type input_n_procs;
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;
1048 io.
data(input_version);
1052 io.
data (data_size);
1055 io.
data (mesh_dimension);
1058 io.
data(input_parallel);
1062 io.
data(input_n_procs);
1065 this->read_subdomain_names<file_id_type>(io);
1070 this->read_bc_names<file_id_type>(io, boundary_info,
true);
1071 this->read_bc_names<file_id_type>(io, boundary_info,
false);
1074 std::swap(input_version, this->
version());
1076 std::swap(input_version, this->
version());
1078 if (read_extra_integers)
1079 this->read_integers_names<file_id_type>
1080 (io, node_integer_names, elem_integer_names);
1082 std::swap(input_version, this->
version());
1084 std::swap(input_version, this->
version());
1086 if (read_disjoint_pairs)
1087 this->read_disjoint_neighbor_boundary_pairs<file_id_type>
1088 (io, disjoint_pair_ids, disjoint_translations);
1093 this->
version() = input_version;
1105 std::map<subdomain_id_type, std::string> & subdomain_map =
1116 for (
auto & int_name : node_integer_names)
1119 for (
auto & int_name : elem_integer_names)
1125#ifdef LIBMESH_ENABLE_PERIODIC
1132 for (
auto i :
make_range(disjoint_pair_ids.size() / 2))
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]),
1143 libmesh_error_msg_if(!disjoint_pair_ids.empty(),
1144 "Reading disjoint neighbor boundary pairs requires --enable-periodic");
1147 return input_parallel ? input_n_procs : 0;
1152template <
typename file_
id_type>
1156 this->read_nodes<file_id_type> (io);
1159 this->read_connectivity<file_id_type> (io);
1162 this->read_remote_elem<file_id_type> (io, expect_all_remote);
1165 this->read_bcs<file_id_type> (io);
1168 this->read_nodesets<file_id_type> (io);
1173template <
typename file_
id_type>
1178 std::map<subdomain_id_type, std::string> & subdomain_map =
1181 std::vector<file_id_type> subdomain_ids;
1182 subdomain_ids.reserve(subdomain_map.size());
1184 std::vector<std::string> subdomain_names;
1185 subdomain_names.reserve(subdomain_map.size());
1187 file_id_type n_subdomain_names = 0;
1188 io.
data(n_subdomain_names,
"# subdomain id to name map");
1190 if (n_subdomain_names)
1192 io.
data(subdomain_ids);
1193 io.
data(subdomain_names);
1196 subdomain_map[cast_int<subdomain_id_type>(subdomain_ids[i])] =
1203template <
typename file_
id_type>
1209 file_id_type n_nodes_here;
1210 io.
data(n_nodes_here,
"# n_nodes on proc");
1214 const unsigned int n_extra_integers =
1218 std::vector<file_id_type> id_pid(2 + n_extra_integers);
1221 std::vector<Real> coords(LIBMESH_DIM);
1223 for (
unsigned int i=0; i<n_nodes_here; i++)
1225 io.
data_stream(id_pid.data(), 2 + n_extra_integers, 2 + n_extra_integers);
1227#ifdef LIBMESH_ENABLE_UNIQUE_ID
1228 file_id_type unique_id = 0;
1229 io.
data(unique_id,
"# unique id");
1232 io.
data_stream(coords.data(), LIBMESH_DIM, LIBMESH_DIM);
1245 const dof_id_type id = cast_int<dof_id_type>(id_pid[0]);
1260 libmesh_assert_equal_to(pid, old_node->
processor_id());
1264 for (
unsigned int ei=0; ei != n_extra_integers; ++ei)
1266 const dof_id_type extra_int = cast_int<dof_id_type>(id_pid[2+ei]);
1271#ifdef LIBMESH_ENABLE_UNIQUE_ID
1272 libmesh_assert_equal_to(unique_id, old_node->
unique_id());
1280#ifdef LIBMESH_ENABLE_UNIQUE_ID
1286 for (
unsigned int ei=0; ei != n_extra_integers; ++ei)
1288 const dof_id_type extra_int = cast_int<dof_id_type>(id_pid[2+ei]);
1297template <
typename file_
id_type>
1306 const unsigned int n_extra_integers =
1309 file_id_type n_elems_here;
1310 io.
data(n_elems_here);
1318 bool file_is_broken =
false;
1320 for (
unsigned int i=0; i<n_elems_here; i++)
1323 std::vector<file_id_type> elem_data(6 + n_extra_integers);
1325 (elem_data.data(), cast_int<unsigned int>(elem_data.size()),
1326 cast_int<unsigned int>(elem_data.size()));
1328#ifdef LIBMESH_ENABLE_UNIQUE_ID
1329 file_id_type unique_id = 0;
1330 io.
data(unique_id,
"# unique id");
1333#ifdef LIBMESH_ENABLE_AMR
1334 uint16_t p_level = 0;
1335 io.
data(p_level,
"# p_level");
1337 uint16_t rflag, pflag;
1338 io.
data(rflag,
"# rflag");
1339 io.
data(pflag,
"# pflag");
1343 static_cast<ElemType>(elem_data[1]);
1344 const bool is_c0polygon = (elem_type ==
C0POLYGON);
1345 const bool is_c0polyhedron = (elem_type ==
C0POLYHEDRON);
1350 std::vector<std::vector<unsigned int>> nodes_on_sides;
1352 if (has_runtime_topology)
1354 libmesh_error_msg_if
1355 (!read_runtime_topology,
1356 "Checkpoint format 1.6 or newer is required to read " <<
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.");
1364 std::size_t topology_index = 0;
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);
1373 libmesh_error_msg_if
1374 (topology_index == runtime_topology.size(),
1375 "Incomplete runtime element checkpoint topology.");
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.");
1383 auto & side_nodes = nodes_on_sides[s];
1384 side_nodes.resize(n_side_nodes);
1387 const unsigned int local_node =
1388 cast_int<unsigned int>(runtime_topology[topology_index++]);
1389 libmesh_error_msg_if
1391 "Runtime element side checkpoint topology references "
1392 "an invalid local node.");
1393 side_nodes[n] = local_node;
1397 libmesh_error_msg_if
1398 (topology_index != runtime_topology.size(),
1399 "Extra data in runtime element checkpoint topology.");
1403 libmesh_error_msg_if
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.");
1411 else if (is_c0polyhedron)
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.");
1423 std::vector<file_id_type> conn_data(
n_nodes);
1425 (conn_data.data(), cast_int<unsigned int>(conn_data.size()),
1426 cast_int<unsigned int>(conn_data.size()));
1429 cast_int<dof_id_type> (elem_data[0]);
1431 cast_int<processor_id_type>
1434 restrict_int<subdomain_id_type>(elem_data[3]);
1438 if (i == 0 && elem_data[4] == 65535)
1439 file_is_broken =
true;
1446 (file_is_broken && elem_data[4] == 65535)) ?
1447 nullptr :
mesh.
elem_ptr(cast_int<dof_id_type>(elem_data[4]));
1449 const unsigned short int child_num =
1451 (file_is_broken && elem_data[5] == 65535)) ?
1452 static_cast<unsigned short>(-1) :
1453 cast_int<unsigned short>(elem_data[5]);
1456 libmesh_assert_equal_to
1457 (child_num,
static_cast<unsigned short>(-1));
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());
1473 libmesh_assert_equal_to(parent, old_elem->
parent());
1479 for (
unsigned int ei=0; ei != n_extra_integers; ++ei)
1481 const dof_id_type extra_int = cast_int<dof_id_type>(elem_data[6+ei]);
1486 libmesh_assert_equal_to(old_elem->
n_nodes(), conn_data.size());
1488 for (
unsigned int n=0,
1489 n_conn = cast_int<unsigned int>(conn_data.size());
1491 libmesh_assert_equal_to
1493 cast_int<dof_id_type>(conn_data[n]));
1495 if (has_runtime_topology)
1497 libmesh_assert_equal_to(old_elem->
n_sides(),
1498 nodes_on_sides.size());
1509 std::unique_ptr<Elem> elem;
1510 std::unique_ptr<Node> generated_mid_elem_node;
1513 elem = std::make_unique<C0Polygon>(
n_nodes, parent);
1514 else if (is_c0polyhedron)
1516 std::vector<std::shared_ptr<Polygon>> sides(nodes_on_sides.size());
1519 const auto & side_node_indices = nodes_on_sides[s];
1521 std::make_shared<C0Polygon>
1522 (cast_int<unsigned int>(side_node_indices.size()));
1526 (conn_data[side_node_indices[n]])));
1527 sides[s] = std::move(side);
1530 elem = std::make_unique<C0Polyhedron>
1531 (sides, generated_mid_elem_node, parent);
1533 libmesh_error_msg_if
1534 (elem->n_nodes() != conn_data.size(),
1535 "C0POLYHEDRON checkpoint topology is incompatible with "
1536 "this libMesh configuration.");
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.");
1548 if (has_runtime_topology)
1550 libmesh_error_msg_if
1551 (!elem->runtime_topology() ||
1552 elem->n_nodes() != conn_data.size() ||
1553 elem->n_sides() != nodes_on_sides.size(),
1555 " checkpoint topology is incompatible with this "
1556 "libMesh configuration.");
1559 libmesh_error_msg_if
1560 (elem->nodes_on_side(s) != nodes_on_sides[s],
1562 " checkpoint topology has inconsistent side ordering.");
1565#ifdef LIBMESH_ENABLE_UNIQUE_ID
1566 elem->set_unique_id(unique_id);
1569 if (elem->dim() > highest_elem_dim)
1570 highest_elem_dim = elem->dim();
1572 elem->set_id() = id;
1573 elem->processor_id() = proc_id;
1574 elem->subdomain_id() = subdomain_id;
1576#ifdef LIBMESH_ENABLE_AMR
1577 elem->hack_p_level(p_level);
1579 elem->set_refinement_flag (cast_int<Elem::RefinementState>(rflag));
1580 elem->set_p_refinement_flag(cast_int<Elem::RefinementState>(pflag));
1587 parent->
add_child(elem.get(), child_num);
1596 for (
unsigned int n=0,
1597 n_conn = cast_int<unsigned int>(conn_data.size());
1605 for (
unsigned int ei=0; ei != n_extra_integers; ++ei)
1607 const dof_id_type extra_int = cast_int<dof_id_type>(elem_data[6+ei]);
1617template <
typename file_
id_type>
1624 std::vector<file_id_type> elem_ids;
1625 std::vector<uint16_t> elem_sides;
1627 io.
data(elem_ids,
"# remote neighbor elem_ids");
1628 io.
data(elem_sides,
"# remote neighbor elem_sides");
1630 libmesh_assert_equal_to(elem_ids.size(), elem_sides.size());
1643 std::vector<file_id_type> parent_ids;
1644 std::vector<uint16_t> child_numbers;
1646 io.
data(parent_ids,
"# remote child parent_ids");
1647 io.
data(child_numbers,
"# remote child_numbers");
1649#ifdef LIBMESH_ENABLE_AMR
1671template <
typename file_
id_type>
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;
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");
1690 (cast_int<dof_id_type>(element_id_list[i]), side_list[i],
1691 cast_int<boundary_id_type>(bc_id_list[i]));
1696template <
typename file_
id_type>
1705 std::vector<file_id_type> node_id_list;
1706 std::vector<file_id_type> bc_id_list;
1708 io.
data(node_id_list,
"# node id list");
1709 io.
data(bc_id_list,
"# nodeset bc id list");
1713 (cast_int<dof_id_type>(node_id_list[i]),
1714 cast_int<boundary_id_type>(bc_id_list[i]));
1719template <
typename file_
id_type>
1722 std::map<boundary_id_type, std::string> & boundary_map = is_sideset ?
1723 info.set_sideset_name_map() : info.set_nodeset_name_map();
1725 std::vector<file_id_type> boundary_ids;
1726 std::vector<std::string> boundary_names;
1728 file_id_type n_boundary_names = 0;
1731 io.
data(n_boundary_names,
"# sideset id to name map");
1733 io.
data(n_boundary_names,
"# nodeset id to name map");
1735 if (n_boundary_names)
1737 io.
data(boundary_ids);
1738 io.
data(boundary_names);
1743 boundary_map[cast_int<boundary_id_type>(boundary_ids[i])] =
1748template <
typename file_
id_type>
1751 std::vector<file_id_type> & pair_ids,
1752 std::vector<Real> & translations)
1754 file_id_type n_pairs = 0;
1755 io.
data(n_pairs,
"# disjoint neighbor boundary pairs");
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());
1763 translations.resize(LIBMESH_DIM * n_pairs);
1765 cast_int<unsigned int>(translations.size()),
1772template <
typename file_
id_type>
1775 std::vector<std::string> & node_integer_names,
1776 std::vector<std::string> & elem_integer_names)
1778 file_id_type n_node_integers, n_elem_integers;
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);
1790 unsigned int max_level = 0;
1792 for (
const auto & elem :
as_range(begin, end))
1793 max_level = std::max(elem->level(), max_level);
1795 return max_level + 1;
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
unique_id_type unique_id() const
static constexpr processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
void set_unique_id(unique_id_type new_id)
Sets the unique_id for this DofObject.
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.
const Elem * raw_child_ptr(unsigned int i) const
virtual unsigned int n_nodes() const =0
const Elem * parent() const
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
const Elem * child_ptr(unsigned int i) const
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
subdomain_id_type subdomain_id() const
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...
void add_child(Elem *elem)
Adds a child pointer to the array of children of this element.
virtual ElemType type() const =0
virtual unsigned int n_sides() const =0
dof_id_type node_id(const unsigned int i) const
const Elem * neighbor_ptr(unsigned int i) const
This is the MeshBase class.
virtual bool is_serial() const
unsigned int n_elem_integers() const
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
virtual const Node * node_ptr(const dof_id_type i) const =0
unsigned int mesh_dimension() const
virtual dof_id_type n_elem() const =0
virtual bool is_replicated() const
unsigned int recalculate_n_partitions()
In a few (very rare) cases, the user may have manually tagged the elements with specific processor ID...
PeriodicBoundaries * get_disjoint_neighbor_boundary_pairs()
const std::map< subdomain_id_type, std::string > & get_subdomain_name_map() const
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.
const std::string & get_node_integer_name(unsigned int i) const
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.
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...
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.
const std::string & get_elem_integer_name(unsigned int i) const
virtual void set_distributed()
Asserts that not all elements and nodes of the mesh necessarily exist on the current processor.
unsigned int n_node_integers() const
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
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.
std::map< subdomain_id_type, std::string > & set_subdomain_name_map()
virtual void partition(const unsigned int n_parts)
Call the default partitioner (currently metis_partition()).
void skip_partitioning(bool skip)
If true is passed in then nothing on this mesh will be (re)partitioned.
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 output.
A Node is like a Point, but with more information.
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.
bool has_transformation_matrix() const
The definition of a periodic boundary.
A Point defines a location in LIBMESH_DIM dimensional Real space.
In parallel meshes where a ghost element has neighbors which do not exist on the local processor,...
This class implements a C++ interface to the XDR (eXternal Data Representation) format.
void data_stream(T *val, const unsigned int len, const unsigned int line_break=libMesh::invalid_uint)
Inputs or outputs a raw data stream.
void close()
Closes the file if it is open.
void data(T &a, std::string_view comment="")
Inputs or outputs a single value.
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.
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...
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 &...)
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
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.
const RemoteElem * remote_elem
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)
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
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...
The definition of the const_element_iterator struct.
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