23 #include "libmesh/distributed_mesh.h"
24 #include "libmesh/elem.h"
25 #include "libmesh/exodusII_io.h"
26 #include "libmesh/libmesh_logging.h"
27 #include "libmesh/nemesis_io.h"
28 #include "libmesh/nemesis_io_helper.h"
29 #include "libmesh/node.h"
30 #include "libmesh/parallel.h"
31 #include "libmesh/utility.h"
32 #include "libmesh/boundary_info.h"
33 #include "libmesh/mesh_communication.h"
34 #include "libmesh/fe_type.h"
35 #include "libmesh/equation_systems.h"
36 #include "libmesh/numeric_vector.h"
37 #include "libmesh/int_range.h"
38 #include "libmesh/auto_ptr.h"
47 struct CompareGlobalIdxMappings
51 bool operator()(
const std::pair<unsigned int, unsigned int> & a,
52 const std::pair<unsigned int, unsigned int> & b)
const
53 {
return a.first < b.first; }
57 bool operator()(
const std::pair<unsigned int, unsigned int> & a,
58 const unsigned int b)
const
59 {
return a.first < b; }
67 inline unsigned int to_uint (
const T & t )
69 libmesh_assert_equal_to (t, static_cast<T>(static_cast<unsigned int>(t)));
71 return static_cast<unsigned int>(t);
76 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API) && !defined(NDEBUG)
77 inline bool global_idx_mapping_equality (
const std::pair<unsigned int, unsigned int> & a,
78 const std::pair<unsigned int, unsigned int> & b)
80 return a.first == b.first;
91 #
if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
100 #
if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
101 nemhelper(libmesh_make_unique<
Nemesis_IO_Helper>(*this, false, single_precision)),
106 _allow_empty_variables(false)
124 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
149 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
165 LOG_SCOPE (
"read()",
"Nemesis_IO");
168 parallel_object_only();
178 std::string nemesis_filename =
nemhelper->construct_nemesis_filename(base_filename);
181 libMesh::out <<
"Opening file: " << nemesis_filename << std::endl;
184 nemhelper->open(nemesis_filename.c_str(),
true);
215 libmesh_error_msg(
"ERROR: there should be no external nodes in an element-based partitioning!");
217 libmesh_assert_equal_to (
nemhelper->num_nodes,
221 libmesh_assert_equal_to (
nemhelper->num_elem,
255 libmesh_assert_equal_to (to_uint(
nemhelper->num_node_cmaps),
nemhelper->node_cmap_node_cnts.size());
256 libmesh_assert_equal_to (to_uint(
nemhelper->num_node_cmaps),
nemhelper->node_cmap_node_ids.size());
257 libmesh_assert_equal_to (to_uint(
nemhelper->num_node_cmaps),
nemhelper->node_cmap_proc_ids.size());
265 std::vector<unsigned char> pid_send_partner (this->
n_processors(), 0);
271 for (
unsigned int cmap=0; cmap<to_uint(
nemhelper->num_node_cmaps); cmap++)
273 libmesh_assert_less (
nemhelper->node_cmap_ids[cmap], this->n_processors());
275 pid_send_partner[
nemhelper->node_cmap_ids[cmap]] = 1;
280 const std::vector<unsigned char> pid_recv_partner (pid_send_partner);
282 this->
comm().alltoall (pid_send_partner);
292 std::vector<processor_id_type> node_ownership (
nemhelper->num_internal_nodes +
294 this->processor_id());
297 std::map<unsigned int, unsigned int> pid_to_cmap_map;
300 for (
unsigned int cmap=0; cmap<to_uint(
nemhelper->num_node_cmaps); cmap++)
303 libmesh_assert_equal_to (to_uint(
nemhelper->node_cmap_node_cnts[cmap]),
304 nemhelper->node_cmap_node_ids[cmap].size());
306 libmesh_assert_equal_to (to_uint(
nemhelper->node_cmap_node_cnts[cmap]),
307 nemhelper->node_cmap_proc_ids[cmap].size());
312 cast_int<processor_id_type>(
nemhelper->node_cmap_ids[cmap]);
314 libmesh_assert_less (adjcnt_pid_idx, this->
n_processors());
315 libmesh_assert_not_equal_to (adjcnt_pid_idx, this->
processor_id());
320 pid_to_cmap_map[adjcnt_pid_idx] = cmap;
326 libmesh_assert_equal_to
328 cast_int<processor_id_type>(
nemhelper->node_cmap_proc_ids[cmap][
idx]));
331 const unsigned int local_node_idx =
nemhelper->node_cmap_node_ids[cmap][
idx]-1;
333 libmesh_assert_less (local_node_idx, node_ownership.size());
337 node_ownership[local_node_idx] =
338 std::min(node_ownership[local_node_idx], adjcnt_pid_idx);
344 unsigned int num_nodes_i_must_number = 0;
346 for (
const auto & pid : node_ownership)
348 num_nodes_i_must_number++;
351 libmesh_assert_greater_equal (num_nodes_i_must_number,
nemhelper->num_internal_nodes);
356 <<
"num_nodes_i_must_number="
357 << num_nodes_i_must_number
364 std::vector<int> all_loadbal_data ( 8 );
365 all_loadbal_data[0] =
nemhelper->num_internal_nodes;
366 all_loadbal_data[1] =
nemhelper->num_border_nodes;
367 all_loadbal_data[2] =
nemhelper->num_external_nodes;
368 all_loadbal_data[3] =
nemhelper->num_internal_elems;
369 all_loadbal_data[4] =
nemhelper->num_border_elems;
370 all_loadbal_data[5] =
nemhelper->num_node_cmaps;
371 all_loadbal_data[6] =
nemhelper->num_elem_cmaps;
372 all_loadbal_data[7] = num_nodes_i_must_number;
374 this->
comm().allgather (all_loadbal_data,
true);
380 Parallel::MessageTag nodes_tag =
mesh.
comm().get_unique_tag();
382 std::vector<std::vector<int>>
383 needed_node_idxs (
nemhelper->num_node_cmaps);
385 std::vector<Parallel::Request>
386 needed_nodes_requests (
nemhelper->num_node_cmaps);
388 for (
unsigned int cmap=0; cmap<to_uint(
nemhelper->num_node_cmaps); cmap++)
394 needed_node_idxs[cmap].reserve (
nemhelper->node_cmap_node_cnts[cmap]);
396 const unsigned int adjcnt_pid_idx =
nemhelper->node_cmap_ids[cmap];
402 local_node_idx =
nemhelper->node_cmap_node_ids[cmap][
idx]-1,
403 owning_pid_idx = node_ownership[local_node_idx];
406 if (owning_pid_idx == adjcnt_pid_idx)
409 global_node_idx =
nemhelper->node_num_map[local_node_idx]-1;
410 needed_node_idxs[cmap].push_back(global_node_idx);
414 this->
comm().send (adjcnt_pid_idx,
415 needed_node_idxs[cmap],
416 needed_nodes_requests[cmap],
424 std::vector<unsigned int>
428 all_num_nodes_i_must_number[pid] = all_loadbal_data[8*pid + 7];
431 libmesh_assert (std::accumulate(all_num_nodes_i_must_number.begin(),
432 all_num_nodes_i_must_number.end(),
435 unsigned int my_next_node = 0;
437 my_next_node += all_num_nodes_i_must_number[pid];
439 const unsigned int my_node_offset = my_next_node;
449 for (
unsigned int i=0; i<to_uint(
nemhelper->num_internal_nodes); ++i)
451 const unsigned int local_node_idx =
nemhelper->node_mapi[i]-1;
453 const unsigned int owning_pid_idx = node_ownership[local_node_idx];
457 libmesh_assert_equal_to (owning_pid_idx, this->
processor_id());
458 libmesh_assert_less (my_next_node,
nemhelper->num_nodes_global);
467 this->processor_id());
470 if (added_node->
id() != my_next_node)
473 <<
", but we wanted ID " << my_next_node << std::endl;
478 nemhelper->node_num_map[local_node_idx] = my_next_node++;
486 typedef std::vector<std::pair<unsigned int, unsigned int>> global_idx_mapping_type;
487 global_idx_mapping_type old_global_to_new_global_map;
488 old_global_to_new_global_map.reserve (num_nodes_i_must_number
491 CompareGlobalIdxMappings global_idx_mapping_comp;
493 for (
unsigned int i=0; i<to_uint(
nemhelper->num_border_nodes); ++i)
496 local_node_idx =
nemhelper->node_mapb[i]-1,
497 owning_pid_idx = node_ownership[local_node_idx];
503 global_node_idx =
nemhelper->node_num_map[local_node_idx]-1;
507 old_global_to_new_global_map.push_back(std::make_pair(global_node_idx,
517 this->processor_id());
520 if (added_node->
id() != my_next_node)
523 <<
", but we wanted ID " << my_next_node << std::endl;
528 nemhelper->node_num_map[local_node_idx] = my_next_node++;
532 libmesh_assert_equal_to (num_nodes_i_must_number, (my_next_node - my_node_offset));
535 std::sort (old_global_to_new_global_map.begin(),
536 old_global_to_new_global_map.end(),
537 global_idx_mapping_comp);
540 libmesh_assert (std::unique (old_global_to_new_global_map.begin(),
541 old_global_to_new_global_map.end(),
542 global_idx_mapping_equality) ==
543 old_global_to_new_global_map.end());
547 std::map<unsigned int, std::vector<int>> requested_node_idxs;
549 std::vector<Parallel::Request> requested_nodes_requests(
nemhelper->num_node_cmaps);
558 std::vector<bool> processed_cmap (
nemhelper->num_node_cmaps,
false);
560 for (
unsigned int comm_step=0; comm_step<2*to_uint(
nemhelper->num_node_cmaps); comm_step++)
563 const Parallel::Status
564 status (this->
comm().probe (Parallel::any_source,
567 requesting_pid_idx = status.source(),
568 source_pid_idx = status.source();
574 const unsigned int cmap = pid_to_cmap_map[source_pid_idx];
576 if (!processed_cmap[cmap])
578 processed_cmap[cmap] =
true;
585 std::vector<int> & xfer_buf (requested_node_idxs[requesting_pid_idx]);
588 this->
comm().receive (requesting_pid_idx, xfer_buf, nodes_tag);
594 const unsigned int old_global_node_idx = xfer_buf[i];
599 const global_idx_mapping_type::const_iterator it =
600 std::lower_bound (old_global_to_new_global_map.begin(),
601 old_global_to_new_global_map.end(),
603 global_idx_mapping_comp);
606 libmesh_assert_equal_to (it->first, old_global_node_idx);
607 libmesh_assert_greater_equal (it->second, my_node_offset);
608 libmesh_assert_less (it->second, my_next_node);
611 xfer_buf[i] = it->second;
615 this->
comm().send (requesting_pid_idx,
617 requested_nodes_requests[cmap],
633 libmesh_assert_equal_to (to_uint(
nemhelper->node_cmap_ids[cmap]), source_pid_idx);
636 this->
comm().receive (source_pid_idx,
637 needed_node_idxs[cmap],
640 libmesh_assert_less_equal (needed_node_idxs[cmap].size(),
641 nemhelper->node_cmap_node_ids[cmap].size());
643 for (std::size_t i=0, j=0, ncnis=
nemhelper->node_cmap_node_ids[cmap].size(); i < ncnis; i++)
646 local_node_idx =
nemhelper->node_cmap_node_ids[cmap][i]-1,
647 owning_pid_idx = node_ownership[local_node_idx];
651 if (owning_pid_idx == source_pid_idx)
653 libmesh_assert_less (j, needed_node_idxs[cmap].size());
656 global_node_idx = needed_node_idxs[cmap][j++];
664 cast_int<dof_id_type>(global_node_idx),
665 cast_int<processor_id_type>(source_pid_idx));
668 if (added_node->
id() != global_node_idx)
671 <<
", but we wanted ID " << global_node_idx << std::endl;
676 nemhelper->node_num_map[local_node_idx] = global_node_idx;
688 libmesh_assert_equal_to ((my_next_node - my_node_offset), to_uint(
nemhelper->num_nodes));
708 Parallel::wait (needed_nodes_requests);
709 Parallel::wait (requested_nodes_requests);
710 requested_node_idxs.clear();
738 int sum_internal_elems=0, sum_border_elems=0;
739 for (
unsigned int j=3,c=0; c<this->
n_processors(); j+=8,++c)
740 sum_internal_elems += all_loadbal_data[j];
742 for (
unsigned int j=4,c=0; c<this->
n_processors(); j+=8,++c)
743 sum_border_elems += all_loadbal_data[j];
748 libMesh::out <<
"sum_internal_elems=" << sum_internal_elems << std::endl;
751 libMesh::out <<
"sum_border_elems=" << sum_border_elems << std::endl;
754 libmesh_assert_equal_to (sum_internal_elems+sum_border_elems,
nemhelper->num_elems_global);
770 unsigned int my_next_elem = 0;
772 my_next_elem += (all_loadbal_data[8*pid + 3]+
773 all_loadbal_data[8*pid + 4]);
774 const unsigned int my_elem_offset = my_next_elem;
778 <<
"my_elem_offset=" << my_elem_offset << std::endl;
812 for (
unsigned int i=0; i<to_uint(
nemhelper->num_elem_blk); i++)
824 if (!
nemhelper->num_elem_this_blk)
continue;
828 cast_int<subdomain_id_type>(
nemhelper->block_ids[i]);
831 const std::string type_str (
nemhelper->elem_type.data() );
834 const auto & conv =
nemhelper->get_conversion(type_str);
837 libMesh::out <<
"Reading a block of " << type_str <<
" elements." << std::endl;
840 for (
unsigned int j=0; j<to_uint(
nemhelper->num_elem_this_blk); j++)
851 elem->
set_id() = my_next_elem++;
852 #ifdef LIBMESH_ENABLE_UNIQUE_ID
867 if (elem->
id() != my_next_elem-1)
868 libmesh_error_msg(
"Unexpected ID " \
870 <<
" set by parallel mesh. (expecting " \
877 <<
"Setting nodes for Elem " << elem->
id() << std::endl;
879 for (
unsigned int k=0; k<to_uint(
nemhelper->num_nodes_per_elem); k++)
883 conv.get_node_map(k)),
884 local_node_idx =
nemhelper->connect[gi]-1,
885 global_node_idx =
nemhelper->node_num_map[local_node_idx];
893 libmesh_assert_equal_to ((my_next_elem - my_elem_offset), to_uint(
nemhelper->num_elem));
904 unsigned char max_dim_seen = 0;
907 max_dim_seen = static_cast<unsigned char>(i);
912 this->
comm().max(max_dim_seen);
918 <<
"max_dim_seen=" << +max_dim_seen << std::endl;
926 libmesh_error_msg(
"Cannot open dimension " \
928 <<
" mesh file when configured without " \
940 <<
"Read global sideset parameter information." << std::endl;
944 <<
"Number of global sideset IDs: " <<
nemhelper->global_sideset_ids.size() << std::endl;
961 <<
"nemhelper->num_side_sets = " <<
nemhelper->num_side_sets << std::endl;
964 <<
"nemhelper->num_elem_all_sidesets = " <<
nemhelper->num_elem_all_sidesets << std::endl;
969 for (
const auto & pr :
nemhelper->id_to_ss_names)
970 libMesh::out <<
"(" << pr.first <<
"," << pr.second <<
") ";
981 int sum_num_global_side_counts = std::accumulate(
nemhelper->num_global_side_counts.begin(),
986 int sum_num_elem_all_sidesets =
nemhelper->num_elem_all_sidesets;
987 this->
comm().sum(sum_num_elem_all_sidesets);
989 if (sum_num_global_side_counts != sum_num_elem_all_sidesets)
990 libmesh_error_msg(
"Error! global side count reported by Nemesis does not " \
991 <<
"match the side count reported by the individual files!");
998 for (
int offset=0, i=0; i<
nemhelper->num_side_sets; i++)
1000 offset += (i > 0 ?
nemhelper->num_sides_per_set[i-1] : 0);
1046 const auto & conv =
nemhelper->get_conversion(elem->
type());
1052 cast_int<unsigned short>(conv.get_side_map(
nemhelper->side_list[e]-1)),
1053 cast_int<boundary_id_type>(
nemhelper->id_list[e]));
1063 if (nbcs !=
nemhelper->elem_list.size())
1064 libmesh_error_msg(
"[" << this->
processor_id() <<
"] " \
1065 <<
"BoundaryInfo contains " \
1067 <<
" boundary conditions, while the Exodus file had " \
1085 for (
const auto & pr :
nemhelper->id_to_ns_names)
1086 libMesh::out <<
"(" << pr.first <<
"," << pr.second <<
") ";
1100 for (
int nodeset=0; nodeset<
nemhelper->num_node_sets; nodeset++)
1103 int nodeset_id =
nemhelper->nodeset_ids[nodeset];
1108 libMesh::out <<
"nemhelper->nodeset_ids[" << nodeset <<
"]=" << nodeset_id << std::endl;
1119 libmesh_error_msg(
"Error, index is past the end of node_num_map array!");
1128 <<
"nodeset " << nodeset
1129 <<
", local node number: " <<
nemhelper->node_list[node]-1
1130 <<
", global node id: " << global_node_id
1136 (cast_int<dof_id_type>(global_node_id),
1137 cast_int<boundary_id_type>(nodeset_id));
1172 libmesh_error_msg(
"ERROR, Nemesis API is not defined!");
1175 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1181 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1189 std::string nemesis_filename =
nemhelper->construct_nemesis_filename(base_filename);
1196 libmesh_warning(
"Warning: Appending in Nemesis_IO::write() does not make sense.\n"
1197 "Creating a new file instead!");
1225 libmesh_warning(
"Warning: Mesh contains edge boundary IDs, but these "
1226 "are not supported by the Nemesis format.");
1233 libmesh_error_msg(
"ERROR, Nemesis API is not defined!");
1236 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1239 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1249 nemhelper->write_timestep(timestep, time);
1259 libmesh_error_msg(
"ERROR, Nemesis API is not defined!");
1262 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1266 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1269 const std::vector<std::string> & names)
1273 std::string nemesis_filename =
nemhelper->construct_nemesis_filename(fname);
1282 nemhelper->open(nemesis_filename.c_str(),
false);
1299 libmesh_warning(
"Warning: Mesh contains edge boundary IDs, but these "
1300 "are not supported by the ExodusII format.");
1308 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1309 std::vector<std::string> complex_names =
nemhelper->get_complex_names(names);
1310 nemhelper->initialize_nodal_variables(complex_names);
1312 nemhelper->initialize_nodal_variables(names);
1319 const std::vector<std::string> &)
1321 libmesh_error_msg(
"ERROR, Nemesis API is not defined.");
1328 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1332 const std::vector<std::string> & names)
1334 LOG_SCOPE(
"write_nodal_data(parallel)",
"Nemesis_IO");
1339 std::vector<std::string> output_names;
1344 output_names = names;
1357 const std::set<std::string> * system_names)
1359 LOG_SCOPE(
"write_nodal_data(parallel)",
"Nemesis_IO");
1364 std::vector<std::string> output_names;
1373 std::vector<std::pair<unsigned int, unsigned int>> var_nums =
1383 const std::vector<std::string> &)
1385 libmesh_error_msg(
"ERROR, Nemesis API is not defined.");
1389 const EquationSystems &,
1390 const std::set<std::string> *)
1392 libmesh_error_msg(
"ERROR, Nemesis API is not defined.");
1399 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1404 libmesh_error_msg(
"ERROR, Nemesis file must be initialized before outputting elemental variables.");
1407 std::vector<std::string> names;
1416 std::vector<std::string> monomials;
1423 for (
const auto & var : monomials)
1425 names.push_back(var);
1430 std::vector<std::pair<unsigned int, unsigned int>> var_nums =
1436 if (var_nums.empty())
1439 libMesh::out <<
"No CONSTANT, MONOMIAL data to be written." << std::endl;
1446 std::vector<std::set<subdomain_id_type>> vars_active_subdomains;
1456 nemhelper->initialize_element_variables(names, vars_active_subdomains);
1467 vars_active_subdomains);
1474 libmesh_not_implemented();
1481 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1484 const std::vector<Number> & soln,
1485 const std::vector<std::string> & names)
1487 LOG_SCOPE(
"write_nodal_data(serialized)",
"Nemesis_IO");
1497 const std::vector<Number> &,
1498 const std::vector<std::string> &)
1500 libmesh_error_msg(
"ERROR, Nemesis API is not defined.");
1508 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1511 const std::vector<std::string> & names)
1514 libmesh_error_msg(
"ERROR, Nemesis file must be initialized before outputting global variables.");
1516 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1518 std::vector<std::string> complex_names =
nemhelper->get_complex_names(names);
1520 nemhelper->initialize_global_variables(complex_names);
1522 unsigned int num_values = soln.size();
1523 unsigned int num_vars = names.size();
1524 unsigned int num_elems = num_values / num_vars;
1528 std::vector<Real> complex_soln(3*num_values);
1530 for (
unsigned i=0; i<num_vars; ++i)
1532 for (
unsigned int j=0; j<num_elems; ++j)
1535 complex_soln[3*i*num_elems + j] =
value.real();
1537 for (
unsigned int j=0; j<num_elems; ++j)
1540 complex_soln[3*i*num_elems + num_elems +j] =
value.imag();
1542 for (
unsigned int j=0; j<num_elems; ++j)
1545 complex_soln[3*i*num_elems + 2*num_elems + j] =
std::abs(
value);
1554 nemhelper->initialize_global_variables( names );
1564 const std::vector<std::string> &)
1566 libmesh_error_msg(
"ERROR, Nemesis API is not defined.");
1569 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1573 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
1578 libmesh_error_msg(
"ERROR, Nemesis file must be initialized before outputting information records.");
1581 nemhelper->write_information_records( records );
1589 libmesh_error_msg(
"ERROR, Nemesis API is not defined.");
1592 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)