18 #include "libmesh/checkpoint_io.h"
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"
49 #include <unordered_map>
50 #include <unordered_set>
60 if (nsplits % size == 0)
62 nchunks = nsplits / size;
63 first_chunk = libMesh::cast_int<libMesh::processor_id_type>(nchunks * rank);
70 nchunks = libMesh::cast_int<libMesh::processor_id_type>(nsplits / size + 1);
71 first_chunk = libMesh::cast_int<libMesh::processor_id_type>(nchunks * rank);
75 nchunks = nsplits / size;
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()));
83 std::string extension(
const std::string & s)
85 auto pos = s.rfind(
".");
86 if (pos == std::string::npos)
88 return s.substr(pos, s.size() - pos);
93 return input_name +
"/" + std::to_string(n_procs);
99 return split_dir(input_name, n_procs) +
"/header" + extension(input_name);
103 split_file(
const std::string & input_name,
107 return split_dir(input_name, n_procs) +
"/split-" + std::to_string(n_procs) +
"-" +
108 std::to_string(proc_id) + extension(input_name);
115 if (ret != 0 && ret != -1)
117 "Failed to create mesh split directory '" << input_name <<
"': " << std::strerror(ret));
119 auto dir_name = split_dir(input_name, n_procs);
122 libmesh_warning(
"In CheckpointIO::write, directory '"
123 << dir_name <<
"' already exists, overwriting contents.");
126 "Failed to create mesh split directory '" << dir_name <<
"': " << std::strerror(ret));
146 chunking(
mesh.
comm().size(),
mesh.
comm().rank(), nsplits, my_num_chunks, my_first_chunk);
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;
166 _version (
"checkpoint-1.5"),
167 _my_processor_ids (1, processor_id()),
168 _my_n_processors (
mesh.is_replicated() ? 1 : n_processors())
177 _my_processor_ids (1, processor_id()),
178 _my_n_processors (
mesh.is_replicated() ? 1 : n_processors())
188 std::string header_name;
197 std::ifstream in (header_name.c_str());
201 auto orig_header_name = header_name;
202 header_name = header_file(input_name, 1);
203 std::ifstream in2 (header_name.c_str());
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 "
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.");
219 std::string input_version;
220 io.
data(input_version);
226 this->
comm().broadcast(data_size);
227 this->
comm().broadcast(header_name);
234 input_n_procs = this->read_header<uint16_t>(header_name);
237 input_n_procs = this->read_header<uint32_t>(header_name);
240 input_n_procs = this->read_header<uint64_t>(header_name);
248 return cast_int<processor_id_type>(input_n_procs);
253 auto header = header_file(input_name, n_procs);
254 auto ret = std::remove(header.c_str());
256 libmesh_warning(
"Failed to clean up checkpoint header '" << header <<
"': " << std::strerror(ret));
260 auto split = split_file(input_name, n_procs, i);
261 ret = std::remove(
split.c_str());
263 libmesh_warning(
"Failed to clean up checkpoint split file '" <<
split <<
"': " << std::strerror(ret));
266 auto dir = split_dir(input_name, n_procs);
267 ret = rmdir(dir.c_str());
269 libmesh_warning(
"Failed to clean up checkpoint split dir '" << dir <<
"': " << std::strerror(ret));
273 rmdir(input_name.c_str());
279 return (this->
version().find(
"1.5") != std::string::npos);
285 LOG_SCOPE(
"write()",
"CheckpointIO");
299 std::string header_file_name = header_file(
name, use_n_procs);
300 make_dir(
name, use_n_procs);
313 io.
data(data_size,
"# integer size");
319 io.
data(mesh_dimension,
"# dimensions");
333 io.
data(n_procs,
"# n_procs");
347 if (write_extra_integers)
350 io.
data(n_node_integers,
"# n_extra_integers per node");
352 std::vector<std::string> node_integer_names;
353 for (
unsigned int i=0; i != n_node_integers; ++i)
356 io.
data(node_integer_names);
359 io.
data(n_elem_integers,
"# n_extra_integers per elem");
361 std::vector<std::string> elem_integer_names;
362 for (
unsigned int i=0; i != n_elem_integers; ++i)
365 io.
data(elem_integer_names);
375 std::vector<processor_id_type> ids_to_write;
379 std::unordered_map<processor_id_type, std::vector<Elem *>> elements_on_pid;
385 elements_on_pid[p].clear();
386 auto eop_end = elements_on_pid.end();
390 auto eop_it = elements_on_pid.find(p);
391 if (eop_it != eop_end)
392 eop_it->second.push_back(elem);
400 ids_to_write.push_back(0);
405 libmesh_error_msg(
"Cannot write serial checkpoint from distributed mesh");
411 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
413 std::vector<std::tuple<dof_id_type, boundary_id_type>>
416 for (
const auto & my_pid : ids_to_write)
418 auto file_name = split_file(
name, use_n_procs, my_pid);
421 std::set<const Elem *, CompareElemIdsByLevel> elements;
444 const auto elements_vec_it = elements_on_pid.find(p);
445 if (elements_vec_it != elements_on_pid.end())
447 const auto & p_elements = elements_vec_it->second;
448 Elem *
const * elempp = p_elements.data();
449 Elem *
const * elemend = elempp + p_elements.size();
462 (
mesh, p, active_pid_elements_begin,
463 active_pid_elements_end, elements);
465 pid_elements_end, elements);
471 std::set<const Node *> connected_nodes;
484 this->
write_bcs (io, elements, bc_triples);
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());
510 for (
const auto & pr : subdomain_map)
511 if (!pr.second.empty())
514 subdomain_ids.push_back(pr.first);
515 subdomain_names.push_back(pr.second);
518 io.
data(n_subdomain_names,
"# subdomain id to name map");
520 if (n_subdomain_names)
522 io.
data(subdomain_ids);
523 io.
data(subdomain_names);
531 const std::set<const Node *> & nodeset)
const
535 io.
data(n_nodes_here,
"# n_nodes on proc");
538 const unsigned int n_extra_integers =
542 std::vector<largest_id_type> id_pid(2 + n_extra_integers);
545 std::vector<Real> coords(LIBMESH_DIM);
547 for (
const auto & node : nodeset)
549 id_pid[0] = node->id();
550 id_pid[1] = node->processor_id();
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);
556 io.
data_stream(id_pid.data(), 2 + n_extra_integers, 2 + n_extra_integers);
558 #ifdef LIBMESH_ENABLE_UNIQUE_ID
561 io.
data(unique_id,
"# unique id");
564 coords[0] = (*node)(0);
567 coords[1] = (*node)(1);
571 coords[2] = (*node)(2);
581 const std::set<const Elem *, CompareElemIdsByLevel> & elements)
const
586 const unsigned int n_extra_integers =
591 std::vector<largest_id_type> elem_data(6 + n_extra_integers);
592 std::vector<largest_id_type> conn_data;
596 io.
data(n_elems_here,
"# number of elements");
598 for (
const auto & elem : elements)
600 unsigned int n_nodes = elem->n_nodes();
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();
607 #ifdef LIBMESH_ENABLE_AMR
608 if (elem->parent() !=
nullptr)
610 elem_data[4] = elem->parent()->id();
611 elem_data[5] = elem->parent()->which_child_am_i(elem);
616 elem_data[4] = static_cast<largest_id_type>(-1);
617 elem_data[5] = static_cast<largest_id_type>(-1);
620 for (
unsigned int i=0; i != n_extra_integers; ++i)
621 elem_data[6+i] = elem->get_extra_integer(i);
625 for (
unsigned int i=0; i<
n_nodes; i++)
626 conn_data[i] = elem->node_id(i);
629 cast_int<unsigned int>(elem_data.size()),
630 cast_int<unsigned int>(elem_data.size()));
632 #ifdef LIBMESH_ENABLE_UNIQUE_ID
635 io.
data(unique_id,
"# unique id");
638 #ifdef LIBMESH_ENABLE_AMR
639 uint16_t p_level = cast_int<uint16_t>(elem->p_level());
640 io.
data(p_level,
"# p_level");
642 uint16_t rflag = elem->refinement_flag();
643 io.
data(rflag,
"# rflag");
645 uint16_t pflag = elem->p_refinement_flag();
646 io.
data(pflag,
"# pflag");
649 cast_int<unsigned int>(conn_data.size()),
650 cast_int<unsigned int>(conn_data.size()));
656 const std::set<const Elem *, CompareElemIdsByLevel> & elements)
const
661 std::vector<largest_id_type> elem_ids, parent_ids;
662 std::vector<uint16_t> elem_sides, child_numbers;
664 for (
const auto & elem : elements)
666 for (
auto n : elem->side_index_range())
670 (neigh && !elements.count(neigh)))
672 elem_ids.push_back(elem->id());
673 elem_sides.push_back(n);
677 #ifdef LIBMESH_ENABLE_AMR
678 if (elem->has_children())
680 for (
unsigned short c = 0,
681 nc = cast_int<unsigned short>(elem->n_children());
686 (child && !elements.count(child)))
688 parent_ids.push_back(elem->id());
689 child_numbers.push_back(c);
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");
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
711 std::size_t bc_size = bc_triples.size();
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;
717 element_id_list.reserve(bc_size);
718 side_list.reserve(bc_size);
719 bc_id_list.reserve(bc_size);
721 std::unordered_set<dof_id_type> elems;
722 for (
auto & e : elements)
723 elems.insert(e->id());
725 for (
const auto & t : bc_triples)
726 if (elems.count(std::get<0>(t)))
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));
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");
742 const std::set<const Node *> & nodeset,
743 const std::vector<std::tuple<dof_id_type, boundary_id_type>> & bc_tuples)
const
751 std::size_t nodeset_size = bc_tuples.size();
753 std::vector<largest_id_type> node_id_list;
754 std::vector<largest_id_type> bc_id_list;
756 node_id_list.reserve(nodeset_size);
757 bc_id_list.reserve(nodeset_size);
759 for (
const auto & t : bc_tuples)
762 node_id_list.push_back(std::get<0>(t));
763 bc_id_list.push_back(std::get<1>(t));
766 io.
data(node_id_list,
"# node id list");
767 io.
data(bc_id_list,
"# nodeset bc id list");
774 const std::map<boundary_id_type, std::string> & boundary_map = is_sideset ?
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());
784 for (
const auto & pr : boundary_map)
785 if (!pr.second.empty())
788 boundary_ids.push_back(pr.first);
789 boundary_names.push_back(pr.second);
793 io.
data(n_boundary_names,
"# sideset id to name map");
795 io.
data(n_boundary_names,
"# nodeset id to name map");
797 if (n_boundary_names)
799 io.
data(boundary_ids);
800 io.
data(boundary_names);
806 LOG_SCOPE(
"read()",
"CheckpointIO");
814 auto header_name = header_file(input_name, input_n_procs);
815 bool input_parallel = input_n_procs > 0;
834 proc_id = cast_int<processor_id_type>(proc_id + stride))
836 auto file_name = split_file(input_name, input_n_procs, proc_id);
839 std::ifstream in (file_name.c_str());
842 libmesh_error_msg(
"ERROR: cannot locate specified file:\n\t" << file_name);
848 const bool expect_all_remote =
856 this->read_subfile<uint16_t>(io, expect_all_remote);
859 this->read_subfile<uint32_t>(io, expect_all_remote);
862 this->read_subfile<uint64_t>(io, expect_all_remote);
883 template <
typename file_
id_type>
889 uint16_t mesh_dimension;
892 uint16_t input_parallel;
893 file_id_type input_n_procs;
895 std::vector<std::string> node_integer_names, elem_integer_names;
903 std::string input_version;
904 io.
data(input_version);
911 io.
data (mesh_dimension);
914 io.
data(input_parallel);
918 io.
data(input_n_procs);
921 this->read_subdomain_names<file_id_type>(io);
926 this->read_bc_names<file_id_type>(io, boundary_info,
true);
927 this->read_bc_names<file_id_type>(io, boundary_info,
false);
934 if (read_extra_integers)
935 this->read_integers_names<file_id_type>
936 (io, node_integer_names, elem_integer_names);
940 this->
comm().broadcast(mesh_dimension);
943 this->
comm().broadcast(input_parallel);
946 this->
comm().broadcast(input_n_procs);
950 std::map<subdomain_id_type, std::string> & subdomain_map =
952 this->
comm().broadcast(subdomain_map);
958 this->
comm().broadcast(node_integer_names);
959 this->
comm().broadcast(elem_integer_names);
961 for (
auto & int_name : node_integer_names)
964 for (
auto & int_name : elem_integer_names)
967 return input_parallel ? input_n_procs : 0;
972 template <
typename file_
id_type>
976 this->read_nodes<file_id_type> (io);
979 this->read_connectivity<file_id_type> (io);
982 this->read_remote_elem<file_id_type> (io, expect_all_remote);
985 this->read_bcs<file_id_type> (io);
988 this->read_nodesets<file_id_type> (io);
993 template <
typename file_
id_type>
998 std::map<subdomain_id_type, std::string> & subdomain_map =
1001 std::vector<file_id_type> subdomain_ids;
1002 subdomain_ids.reserve(subdomain_map.size());
1004 std::vector<std::string> subdomain_names;
1005 subdomain_names.reserve(subdomain_map.size());
1007 file_id_type n_subdomain_names = 0;
1008 io.
data(n_subdomain_names,
"# subdomain id to name map");
1010 if (n_subdomain_names)
1012 io.
data(subdomain_ids);
1013 io.
data(subdomain_names);
1016 subdomain_map[cast_int<subdomain_id_type>(subdomain_ids[i])] =
1023 template <
typename file_
id_type>
1029 file_id_type n_nodes_here;
1030 io.
data(n_nodes_here,
"# n_nodes on proc");
1034 const unsigned int n_extra_integers =
1038 std::vector<file_id_type> id_pid(2 + n_extra_integers);
1041 std::vector<Real> coords(LIBMESH_DIM);
1043 for (
unsigned int i=0; i<n_nodes_here; i++)
1045 io.
data_stream(id_pid.data(), 2 + n_extra_integers, 2 + n_extra_integers);
1047 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1048 file_id_type unique_id = 0;
1049 io.
data(unique_id,
"# unique id");
1052 io.
data_stream(coords.data(), LIBMESH_DIM, LIBMESH_DIM);
1065 const dof_id_type id = cast_int<dof_id_type>(id_pid[0]);
1080 libmesh_assert_equal_to(pid, old_node->processor_id());
1082 libmesh_assert_equal_to(n_extra_integers, old_node->n_extra_integers());
1084 for (
unsigned int ei=0; ei != n_extra_integers; ++ei)
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));
1091 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1092 libmesh_assert_equal_to(unique_id, old_node->unique_id());
1100 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1106 for (
unsigned int ei=0; ei != n_extra_integers; ++ei)
1108 const dof_id_type extra_int = cast_int<dof_id_type>(id_pid[2+ei]);
1117 template <
typename file_
id_type>
1125 const unsigned int n_extra_integers =
1128 file_id_type n_elems_here;
1129 io.
data(n_elems_here);
1132 unsigned int highest_elem_dim = 1;
1137 bool file_is_broken =
false;
1139 for (
unsigned int i=0; i<n_elems_here; i++)
1142 std::vector<file_id_type> elem_data(6 + n_extra_integers);
1144 (elem_data.data(), cast_int<unsigned int>(elem_data.size()),
1145 cast_int<unsigned int>(elem_data.size()));
1147 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1148 file_id_type unique_id = 0;
1149 io.
data(unique_id,
"# unique id");
1152 #ifdef LIBMESH_ENABLE_AMR
1153 uint16_t p_level = 0;
1154 io.
data(p_level,
"# p_level");
1156 uint16_t rflag, pflag;
1157 io.
data(rflag,
"# rflag");
1158 io.
data(pflag,
"# pflag");
1164 std::vector<file_id_type> conn_data(
n_nodes);
1166 (conn_data.data(), cast_int<unsigned int>(conn_data.size()),
1167 cast_int<unsigned int>(conn_data.size()));
1170 cast_int<dof_id_type> (elem_data[0]);
1172 static_cast<ElemType> (elem_data[1]);
1174 cast_int<processor_id_type>
1177 cast_int<subdomain_id_type>(elem_data[3]);
1181 if (i == 0 && elem_data[4] == 65535)
1182 file_is_broken =
true;
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]));
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]);
1199 libmesh_assert_equal_to
1200 (child_num, static_cast<unsigned short>(-1));
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());
1216 libmesh_assert_equal_to(parent, old_elem->
parent());
1222 for (
unsigned int ei=0; ei != n_extra_integers; ++ei)
1224 const dof_id_type extra_int = cast_int<dof_id_type>(elem_data[6+ei]);
1229 libmesh_assert_equal_to(old_elem->
n_nodes(), conn_data.size());
1231 for (
unsigned int n=0,
1232 n_conn = cast_int<unsigned int>(conn_data.size());
1234 libmesh_assert_equal_to
1236 cast_int<dof_id_type>(conn_data[n]));
1243 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1247 if (elem->
dim() > highest_elem_dim)
1248 highest_elem_dim = elem->
dim();
1254 #ifdef LIBMESH_ENABLE_AMR
1274 for (
unsigned int n=0,
1275 n_conn = cast_int<unsigned int>(conn_data.size());
1283 for (
unsigned int ei=0; ei != n_extra_integers; ++ei)
1285 const dof_id_type extra_int = cast_int<dof_id_type>(elem_data[6+ei]);
1295 template <
typename file_
id_type>
1302 std::vector<file_id_type> elem_ids;
1303 std::vector<uint16_t> elem_sides;
1305 io.
data(elem_ids,
"# remote neighbor elem_ids");
1306 io.
data(elem_sides,
"# remote neighbor elem_sides");
1308 libmesh_assert_equal_to(elem_ids.size(), elem_sides.size());
1321 std::vector<file_id_type> parent_ids;
1322 std::vector<uint16_t> child_numbers;
1324 io.
data(parent_ids,
"# remote child parent_ids");
1325 io.
data(child_numbers,
"# remote child_numbers");
1327 #ifdef LIBMESH_ENABLE_AMR
1349 template <
typename file_
id_type>
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;
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");
1368 (cast_int<dof_id_type>(element_id_list[i]), side_list[i],
1369 cast_int<boundary_id_type>(bc_id_list[i]));
1374 template <
typename file_
id_type>
1383 std::vector<file_id_type> node_id_list;
1384 std::vector<file_id_type> bc_id_list;
1386 io.
data(node_id_list,
"# node id list");
1387 io.
data(bc_id_list,
"# nodeset bc id list");
1391 (cast_int<dof_id_type>(node_id_list[i]),
1392 cast_int<boundary_id_type>(bc_id_list[i]));
1397 template <
typename file_
id_type>
1400 std::map<boundary_id_type, std::string> & boundary_map = is_sideset ?
1403 std::vector<file_id_type> boundary_ids;
1404 std::vector<std::string> boundary_names;
1406 file_id_type n_boundary_names = 0;
1409 io.
data(n_boundary_names,
"# sideset id to name map");
1411 io.
data(n_boundary_names,
"# nodeset id to name map");
1413 if (n_boundary_names)
1415 io.
data(boundary_ids);
1416 io.
data(boundary_names);
1421 boundary_map[cast_int<boundary_id_type>(boundary_ids[i])] =
1426 template <
typename file_
id_type>
1429 std::vector<std::string> & node_integer_names,
1430 std::vector<std::string> & elem_integer_names)
1432 file_id_type n_node_integers, n_elem_integers;
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);