19 #include "libmesh/exodusII_io_helper.h" 22 #ifdef LIBMESH_HAVE_EXODUS_API 25 #include "libmesh/boundary_info.h" 26 #include "libmesh/enum_elem_type.h" 27 #include "libmesh/elem.h" 28 #include "libmesh/equation_systems.h" 29 #include "libmesh/fpe_disabler.h" 30 #include "libmesh/remote_elem.h" 31 #include "libmesh/system.h" 32 #include "libmesh/numeric_vector.h" 33 #include "libmesh/enum_to_string.h" 34 #include "libmesh/enum_elem_type.h" 35 #include "libmesh/int_range.h" 36 #include "libmesh/utility.h" 37 #include "libmesh/libmesh_logging.h" 40 #include "libmesh/mesh_tools.h" 43 #include <libmesh/ignore_warnings.h> 49 #include <libmesh/restore_warnings.h> 56 #include <unordered_map> 65 static constexpr
int libmesh_max_str_length = MAX_LINE_LENGTH;
72 const std::vector<int> trishell3_inverse_edge_map = {3, 4, 5};
73 const std::vector<int> quadshell4_inverse_edge_map = {3, 4, 5, 6};
79 const std::vector<int> hex27_node_map = {
81 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
83 21, 25, 24, 26, 23, 22, 20};
86 const std::vector<int> hex27_inverse_node_map = {
88 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
90 26, 20, 25, 24, 22, 21, 23};
93 const std::vector<int> prism20_node_map = {
97 6, 7, 8, 9, 10, 11, 12, 13, 14,
102 const std::vector<int> prism20_inverse_node_map = {
106 6, 7, 8, 9, 10, 11, 12, 13, 14,
111 const std::vector<int> prism21_node_map = {
115 6, 7, 8, 9, 10, 11, 12, 13, 14,
117 20, 18, 19, 16, 17, 15};
120 const std::vector<int> prism21_inverse_node_map = {
124 6, 7, 8, 9, 10, 11, 12, 13, 14,
126 20, 18, 19, 16, 17, 15};
129 const std::vector<int> tet14_node_map = {
131 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
136 const std::vector<int> tet14_inverse_node_map = {
138 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
145 const std::vector<int> tet_face_map = {1, 2, 3, 0};
146 const std::vector<int> hex_face_map = {1, 2, 3, 4, 0, 5};
147 const std::vector<int> prism_face_map = {1, 2, 3, 0, 4};
150 const std::vector<int> tet_inverse_face_map = {4, 1, 2, 3};
151 const std::vector<int> hex_inverse_face_map = {5, 1, 2, 3, 4, 6};
152 const std::vector<int> prism_inverse_face_map = {4, 1, 2, 3, 5};
173 float ret_float = 0.;
181 EX_CHECK_ERR(e2h.
ex_err, error_msg);
188 inline bool is_bezier_elem(
const char * elem_type_str)
191 #if EX_API_VERS_NODOT < 800 195 if (strlen(elem_type_str) <= 4)
197 return (std::string(elem_type_str, elem_type_str+4) ==
"BEX_");
202 std::map<subdomain_id_type, std::vector<unsigned int>>
205 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
211 std::set<subdomain_id_type> sbd_ids;
213 if (!sbd_ids.empty())
214 subdomain_id_end = *sbd_ids.rbegin()+1;
218 for (
const auto & elem :
mesh.active_element_ptr_range())
223 if (elem->infinite())
226 subdomain_map[ elem->subdomain_id() ].push_back(elem->id());
233 for (
auto s : elem->side_index_range())
239 subdomain_map[subdomain_id_end + elem->side_type(s)];
247 if (!add_sides && !subdomain_map.empty())
248 subdomain_id_end = subdomain_map.rbegin()->first + 1;
250 return subdomain_map;
264 bool run_only_on_proc0,
265 bool single_precision) :
270 title(header_info.title),
271 num_dim(header_info.num_dim),
272 num_nodes(header_info.num_nodes),
273 num_elem(header_info.num_elem),
274 num_elem_blk(header_info.num_elem_blk),
275 num_edge(header_info.num_edge),
276 num_edge_blk(header_info.num_edge_blk),
277 num_node_sets(header_info.num_node_sets),
278 num_side_sets(header_info.num_side_sets),
279 num_elem_sets(header_info.num_elem_sets),
284 num_elem_this_blk(0),
285 num_nodes_per_elem(0),
287 num_elem_all_sidesets(0),
288 num_elem_all_elemsets(0),
294 set_unique_ids_from_maps(false),
295 opened_for_writing(false),
296 opened_for_reading(false),
297 _run_only_on_proc0(run_only_on_proc0),
298 _opened_by_create(false),
299 _elem_vars_initialized(false),
300 _global_vars_initialized(false),
301 _nodal_vars_initialized(false),
302 _use_mesh_dimension_instead_of_spatial_dimension(false),
304 _max_name_length(32),
306 _write_as_dimension(0),
307 _single_precision(single_precision)
309 title.resize(MAX_LINE_LENGTH+1);
310 elem_type.resize(libmesh_max_str_length);
323 return EX_API_VERS_NODOT;
331 auto convert_type = [
this](
ElemType type,
332 std::string_view exodus_type,
333 const std::vector<int> * node_map =
nullptr,
334 const std::vector<int> * inverse_node_map =
nullptr,
335 const std::vector<int> * side_map =
nullptr,
336 const std::vector<int> * inverse_side_map =
nullptr,
337 const std::vector<int> * shellface_map =
nullptr,
338 const std::vector<int> * inverse_shellface_map =
nullptr,
339 size_t shellface_index_offset = 0)
343 conv.libmesh_type = type;
344 conv.exodus_type = exodus_type;
345 conv.node_map = node_map;
346 conv.inverse_node_map = inverse_node_map;
347 conv.side_map = side_map;
348 conv.inverse_side_map = inverse_side_map;
349 conv.shellface_map = shellface_map;
350 conv.inverse_shellface_map = inverse_shellface_map;
351 conv.shellface_index_offset = shellface_index_offset;
352 conv.n_nodes = elem->n_nodes();
353 for (
int d = elem->dim()+1; d <= 3; ++d)
358 convert_type(
EDGE2,
"EDGE2");
359 convert_type(
EDGE3,
"EDGE3");
360 convert_type(
EDGE4,
"EDGE4");
361 convert_type(
QUAD4,
"QUAD4");
362 convert_type(
QUAD8,
"QUAD8");
363 convert_type(
QUAD9,
"QUAD9");
364 convert_type(
QUADSHELL4,
"SHELL4",
nullptr,
nullptr,
nullptr,
365 &quadshell4_inverse_edge_map,
366 nullptr,
nullptr, 2);
367 convert_type(
QUADSHELL8,
"SHELL8",
nullptr,
nullptr,
nullptr,
368 &quadshell4_inverse_edge_map,
369 nullptr,
nullptr, 2);
370 convert_type(
QUADSHELL9,
"SHELL9",
nullptr,
nullptr,
nullptr,
371 &quadshell4_inverse_edge_map,
372 nullptr,
nullptr, 2);
374 convert_type(
TRI3,
"TRI3");
375 convert_type(
TRI6,
"TRI6");
376 convert_type(
TRI7,
"TRI7");
386 convert_type(
TRISHELL3,
"TRISHELL3",
nullptr,
nullptr,
nullptr,
387 &trishell3_inverse_edge_map,
388 nullptr,
nullptr, 2);
390 convert_type(
HEX8,
"HEX8",
nullptr,
nullptr,
391 &hex_face_map, &hex_inverse_face_map);
392 convert_type(
HEX20,
"HEX20",
nullptr,
nullptr,
393 &hex_face_map, &hex_inverse_face_map);
394 convert_type(
HEX27,
"HEX27", &hex27_node_map,
395 &hex27_inverse_node_map,
396 &hex_face_map, &hex_inverse_face_map);
397 convert_type(
TET4,
"TETRA4",
nullptr,
nullptr,
398 &tet_face_map, &tet_inverse_face_map);
399 convert_type(
TET10,
"TETRA10",
nullptr,
nullptr,
400 &tet_face_map, &tet_inverse_face_map);
401 convert_type(
TET14,
"TETRA14", &tet14_node_map,
402 &tet14_inverse_node_map,
403 &tet_face_map, &tet_inverse_face_map);
404 convert_type(
PRISM6,
"WEDGE",
nullptr,
nullptr,
405 &prism_face_map, &prism_inverse_face_map);
406 convert_type(
PRISM15,
"WEDGE15",
nullptr,
nullptr,
407 &prism_face_map, &prism_inverse_face_map);
408 convert_type(
PRISM18,
"WEDGE18",
nullptr,
nullptr,
409 &prism_face_map, &prism_inverse_face_map);
410 convert_type(
PRISM20,
"WEDGE20", &prism20_node_map,
411 &prism20_inverse_node_map,
412 &prism_face_map, &prism_inverse_face_map);
413 convert_type(
PRISM21,
"WEDGE21", &prism21_node_map,
414 &prism21_inverse_node_map,
415 &prism_face_map, &prism_inverse_face_map);
552 return libmesh_map_find(maps_for_dim, type);
559 std::transform(type_str.begin(), type_str.end(), type_str.begin(), ::toupper);
585 bool single_precision_in)
586 : our_data(our_data_in),
587 single_precision(single_precision_in)
591 if (
sizeof(
Real) !=
sizeof(
float))
600 else if (
sizeof(
Real) !=
sizeof(double))
612 if (single_precision)
614 if (
sizeof(
Real) !=
sizeof(
float))
615 return static_cast<void*
>(float_vec.data());
618 else if (
sizeof(
Real) !=
sizeof(double))
619 return static_cast<void*
>(double_vec.data());
622 return const_cast<void *
>(
static_cast<const void *
>(our_data.data()));
627 bool single_precision_in)
628 : our_data(our_data_in),
629 single_precision(single_precision_in)
634 if (
sizeof(
Real) !=
sizeof(
float))
637 else if (
sizeof(
Real) !=
sizeof(double))
644 if (single_precision)
646 if (
sizeof(
Real) !=
sizeof(
float))
647 our_data.assign(float_vec.begin(), float_vec.end());
649 else if (
sizeof(
Real) !=
sizeof(double))
650 our_data.assign(double_vec.begin(), double_vec.end());
656 if (single_precision)
658 if (
sizeof(
Real) !=
sizeof(
float))
659 return static_cast<void*
>(float_vec.data());
662 else if (
sizeof(
Real) !=
sizeof(double))
663 return static_cast<void*
>(double_vec.data());
666 return static_cast<void *
>(our_data.data());
672 float ex_version = 0.;
677 comp_ws = cast_int<int>(
sizeof(float));
682 comp_ws = cast_int<int>(std::min(
sizeof(
Real),
sizeof(
double)));
691 ex_id = exII::ex_open(filename,
692 read_only ? EX_READ : EX_WRITE,
698 std::string err_msg = std::string(
"Error opening ExodusII mesh file: ") + std::string(filename);
699 EX_CHECK_ERR(
ex_id, err_msg);
713 int max_name_length = exII::ex_inquire_int(
ex_id, exII::EX_INQ_DB_MAX_USED_NAME_LENGTH);
715 libmesh_error_msg_if(max_name_length > MAX_LINE_LENGTH,
716 "Unexpected maximum name length of " <<
717 max_name_length <<
" in file " << filename <<
718 " exceeds expected " << MAX_LINE_LENGTH);
722 max_name_length_to_set = std::max(max_name_length, 32);
727 ex_err = exII::ex_set_max_name_length(
ex_id, max_name_length_to_set);
728 EX_CHECK_ERR(
ex_err,
"Error setting max ExodusII name length.");
743 exII::ex_init_params params = {};
744 int err_flag = exII::ex_get_init_ext(
ex_id, ¶ms);
745 EX_CHECK_ERR(err_flag,
"Error retrieving header info.");
749 h.
title.assign(params.title, params.title + MAX_LINE_LENGTH);
777 EX_CHECK_ERR(
ex_err,
"Error reading number of nodal variables.");
780 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
783 EX_CHECK_ERR(
ex_err,
"Error reading number of global variables.");
786 EX_CHECK_ERR(
ex_err,
"Error reading number of sideset variables.");
789 EX_CHECK_ERR(
ex_err,
"Error reading number of nodeset variables.");
792 EX_CHECK_ERR(
ex_err,
"Error reading number of elemset variables.");
794 message(
"Exodus header info retrieved successfully.");
804 inquire(*
this, exII::EX_INQ_QA,
"Error retrieving number of QA records");
809 <<
" QA record(s) in the Exodus file." 818 std::vector<std::vector<std::vector<char>>> qa_storage(num_qa_rec);
821 qa_storage[i].resize(4);
823 qa_storage[i][j].resize(libmesh_max_str_length+1);
827 typedef char * inner_array_t[4];
834 auto qa_record = std::make_unique<inner_array_t[]>(num_qa_rec);
840 qa_record[i][j] = qa_storage[i][j].data();
843 EX_CHECK_ERR(
ex_err,
"Error reading the QA records.");
865 <<
"Mesh Dimension: \t" <<
num_dim << std::endl
866 <<
"Number of Nodes: \t" <<
num_nodes << std::endl
867 <<
"Number of elements: \t" <<
num_elem << std::endl
868 <<
"Number of elt blocks: \t" <<
num_elem_blk << std::endl
878 LOG_SCOPE(
"read_nodes()",
"ExodusII_IO_Helper");
886 ex_err = exII::ex_get_coord
892 EX_CHECK_ERR(
ex_err,
"Error retrieving nodal data.");
893 message(
"Nodal data retrieved successfully.");
898 int n_nodal_attr = 0;
899 ex_err = exII::ex_get_attr_param(
ex_id, exII::EX_NODAL, 0, & n_nodal_attr);
900 EX_CHECK_ERR(
ex_err,
"Error getting number of nodal attributes.");
902 if (n_nodal_attr > 0)
904 std::vector<std::vector<char>> attr_name_data
905 (n_nodal_attr, std::vector<char>(libmesh_max_str_length + 1));
906 std::vector<char *> attr_names(n_nodal_attr);
908 attr_names[i] = attr_name_data[i].data();
910 ex_err = exII::ex_get_attr_names(
ex_id, exII::EX_NODAL, 0, attr_names.data());
911 EX_CHECK_ERR(
ex_err,
"Error getting nodal attribute names.");
914 if (std::string(
"bex_weight") == attr_names[i])
918 exII::ex_get_one_attr (
ex_id, exII::EX_NODAL, 0, i+1,
920 EX_CHECK_ERR(
ex_err,
"Error getting Bezier Extraction nodal weights");
935 ex_err = exII::ex_get_node_num_map
938 EX_CHECK_ERR(
ex_err,
"Error retrieving nodal number map.");
939 message(
"Nodal numbering map retrieved successfully.");
944 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_nodes-1)); ++i)
957 #if EX_API_VERS_NODOT >= 800 958 int n_blobs = exII::ex_inquire_int(
ex_id, exII::EX_INQ_BLOB);
962 std::vector<exII::ex_blob> blobs(n_blobs);
963 std::vector<std::vector<char>> blob_names(n_blobs);
966 blob_names[i].resize(libmesh_max_str_length+1);
967 blobs[i].name = blob_names[i].data();
971 EX_CHECK_ERR(
ex_err,
"Error getting blobs.");
973 bool found_blob =
false;
974 const exII::ex_blob * my_blob = &blobs[0];
975 for (
const auto & blob : blobs)
977 if (std::string(
"bex_cv_blob") == blob.name)
985 libmesh_error_msg(
"Found no bex_cv_blob for bezier elements");
987 const int n_blob_attr =
988 exII::ex_get_attribute_count(
ex_id, exII::EX_BLOB,
991 std::vector<exII::ex_attribute> attributes(n_blob_attr);
992 ex_err = exII::ex_get_attribute_param(
ex_id, exII::EX_BLOB,
995 EX_CHECK_ERR(
ex_err,
"Error getting bex blob attribute parameters.");
997 int bex_num_dense_cv_blocks = 0;
998 std::vector<int> bex_dense_cv_info;
999 for (
auto & attr : attributes)
1001 if (std::string(
"bex_dense_cv_info") == attr.name)
1003 const std::size_t value_count = attr.value_count;
1004 if (value_count % 2)
1005 libmesh_error_msg(
"Found odd number of bex_dense_cv_info");
1007 bex_dense_cv_info.resize(value_count);
1008 attr.values = bex_dense_cv_info.data();
1009 exII::ex_get_attribute(
ex_id, &attr);
1011 bex_num_dense_cv_blocks = value_count / 2;
1013 libmesh_error_msg_if(bex_num_dense_cv_blocks > 1,
1014 "Found more than 1 dense bex CV block; unsure how to handle that");
1018 if (bex_dense_cv_info.empty())
1019 libmesh_error_msg(
"No bex_dense_cv_info found");
1022 exII::ex_get_variable_param(
ex_id, exII::EX_BLOB, &n_blob_vars);
1023 std::vector<char> var_name (libmesh_max_str_length + 1);
1024 for (
auto v_id :
make_range(1,n_blob_vars+1))
1026 ex_err = exII::ex_get_variable_name(
ex_id, exII::EX_BLOB, v_id, var_name.data());
1027 EX_CHECK_ERR(
ex_err,
"Error reading bex blob var name.");
1029 if (std::string(
"bex_dense_cv_blocks") == var_name.data())
1031 std::vector<double> bex_dense_cv_blocks(my_blob->num_entry);
1033 ex_err = exII::ex_get_var(
ex_id, 1, exII::EX_BLOB, v_id,
1034 my_blob->id, my_blob->num_entry,
1035 bex_dense_cv_blocks.data());
1036 EX_CHECK_ERR(
ex_err,
"Error reading bex_dense_cv_blocks.");
1041 std::size_t offset = 0;
1045 const int vecsize = bex_dense_cv_info[2*i+1];
1048 vec.resize(vecsize);
1049 std::copy(
std::next(bex_dense_cv_blocks.begin(), offset),
1050 std::next(bex_dense_cv_blocks.begin(), offset + vecsize),
1059 #endif // EX_API_VERS_NODOT >= 800 1066 out_stream <<
"(" <<
x[i] <<
", " <<
y[i] <<
", " <<
z[i] <<
")" << std::endl;
1078 exII::EX_ELEM_BLOCK,
1081 EX_CHECK_ERR(
ex_err,
"Error getting block IDs.");
1082 message(
"All block IDs retrieved successfully.");
1084 char name_buffer[libmesh_max_str_length+1];
1087 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_BLOCK,
1089 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
1092 message(
"All block names retrieved successfully.");
1100 exII::EX_EDGE_BLOCK,
1103 EX_CHECK_ERR(
ex_err,
"Error getting edge block IDs.");
1104 message(
"All edge block IDs retrieved successfully.");
1107 char name_buffer[libmesh_max_str_length+1];
1110 ex_err = exII::ex_get_name(
ex_id, exII::EX_EDGE_BLOCK,
1112 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
1115 message(
"All edge block names retrieved successfully.");
1123 libmesh_assert_less (index,
block_ids.size());
1132 libmesh_assert_less (index,
block_ids.size());
1141 libmesh_assert_less (index,
ss_ids.size());
1150 libmesh_assert_less (index,
ss_ids.size());
1178 LOG_SCOPE(
"read_elem_in_block()",
"ExodusII_IO_Helper");
1180 libmesh_assert_less (block,
block_ids.size());
1183 int num_edges_per_elem = 0;
1184 int num_faces_per_elem = 0;
1185 int num_node_data_per_elem = 0;
1187 exII::EX_ELEM_BLOCK,
1191 &num_node_data_per_elem,
1192 &num_edges_per_elem,
1193 &num_faces_per_elem,
1196 EX_CHECK_ERR(
ex_err,
"Error getting block info.");
1197 message(
"Info retrieved successfully for block: ", block);
1202 if (!(num_edges_per_elem == 0) && !(num_edges_per_elem == -1))
1203 libmesh_warning(
"Exodus files with extended edge connectivity not currently supported.");
1204 if (!(num_faces_per_elem == 0) && !(num_faces_per_elem == -1))
1205 libmesh_warning(
"Exodus files with extended face connectivity not currently supported.");
1210 const bool is_bezier = is_bezier_elem(
elem_type.data());
1223 <<
" nodes per element." << std::endl;
1233 exII::EX_ELEM_BLOCK,
1239 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
1240 message(
"Connectivity retrieved successfully for block: ", block);
1248 #if EX_API_VERS_NODOT >= 800 1249 int real_n_attr = exII::ex_get_attribute_count(
ex_id, exII::EX_ELEM_BLOCK,
block_ids[block]);
1250 EX_CHECK_ERR(real_n_attr,
"Error getting number of element block attributes.");
1252 if (real_n_attr > 0)
1254 std::vector<exII::ex_attribute> attributes(real_n_attr);
1256 ex_err = exII::ex_get_attribute_param(
ex_id, exII::EX_ELEM_BLOCK,
block_ids[block], attributes.data());
1257 EX_CHECK_ERR(
ex_err,
"Error getting element block attribute parameters.");
1259 ex_err = exII::ex_get_attributes(
ex_id, real_n_attr, attributes.data());
1260 EX_CHECK_ERR(
ex_err,
"Error getting element block attribute values.");
1262 for (
auto attr : attributes)
1264 if (std::string(
"bex_elem_degrees") == attr.name)
1266 if (attr.type != exII::EX_INTEGER)
1267 libmesh_error_msg(
"Found non-integer bex_elem_degrees");
1269 if (attr.value_count > 3)
1270 libmesh_error_msg(
"Looking for at most 3 bex_elem_degrees; found " << attr.value_count);
1274 std::vector<int> bex_elem_degrees(3);
1276 const int * as_int =
static_cast<int *
>(attr.values);
1277 std::copy(as_int, as_int+attr.value_count, bex_elem_degrees.begin());
1287 libmesh_assert_equal_to(bex_elem_degrees[d], 2);
1313 auto src = old_connect.data();
1329 #endif // EX_API_VERS_NODOT >= 800 1336 LOG_SCOPE(
"read_edge_blocks()",
"ExodusII_IO_Helper");
1352 typedef std::pair<dof_id_type, unsigned int> ElemEdgePair;
1353 std::unordered_map<dof_id_type, std::vector<ElemEdgePair>> edge_map;
1354 std::unique_ptr<Elem> edge_ptr;
1355 for (
const auto & elem :
mesh.element_ptr_range())
1356 for (
auto e : elem->edge_index_range())
1358 elem->build_edge_ptr(edge_ptr, e);
1362 auto & vec = edge_map[edge_key];
1363 vec.emplace_back(elem->id(), e);
1370 if (edge_ptr->default_order() !=
FIRST)
1373 auto low_order_edge =
1377 for (
unsigned int v=0; v<edge_ptr->n_vertices(); ++v)
1378 low_order_edge->set_node(v, edge_ptr->node_ptr(v));
1381 dof_id_type low_order_edge_key = low_order_edge->key();
1385 auto & low_order_vec = edge_map[low_order_edge_key];
1386 low_order_vec.emplace_back(elem->id(), e);
1399 int num_edge_this_blk = 0;
1400 int num_nodes_per_edge = 0;
1401 int num_edges_per_edge = 0;
1402 int num_faces_per_edge = 0;
1403 int num_attr_per_edge = 0;
1405 exII::EX_EDGE_BLOCK,
1409 &num_nodes_per_edge,
1410 &num_edges_per_edge,
1411 &num_faces_per_edge,
1412 &num_attr_per_edge);
1414 EX_CHECK_ERR(
ex_err,
"Error getting edge block info.");
1415 message(
"Info retrieved successfully for block: ", edge_block_id);
1420 connect.resize(num_nodes_per_edge * num_edge_this_blk);
1425 exII::EX_EDGE_BLOCK,
1431 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
1432 message(
"Connectivity retrieved successfully for block: ", edge_block_id);
1441 for (
auto [i, sz] = std::make_tuple(0u,
connect.size()); i<sz; i+=num_nodes_per_edge)
1443 auto edge =
Elem::build(conv.libmesh_elem_type());
1444 for (
int n=0; n<num_nodes_per_edge; ++n)
1446 auto exodus_node_id = this->
connect[i+n];
1457 auto & elem_edge_pair_vec =
1458 libmesh_map_find(edge_map, edge_key);
1460 for (
const auto & elem_edge_pair : elem_edge_pair_vec)
1472 build_edge_ptr(edge_ptr, elem_edge_pair.second);
1481 ((edge_ptr->node_id(0) == edge->node_id(0)) && (edge_ptr->node_id(1) == edge->node_id(1))) ||
1482 ((edge_ptr->node_id(0) == edge->node_id(1)) && (edge_ptr->node_id(1) == edge->node_id(0)));
1488 elem_edge_pair.second,
1510 ex_err = exII::ex_get_elem_num_map
1513 EX_CHECK_ERR(
ex_err,
"Error retrieving element number map.");
1514 message(
"Element numbering map retrieved successfully.");
1533 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_elem-1)); ++i)
1549 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset information.");
1550 message(
"All sideset information retrieved successfully.");
1557 num_elem_all_sidesets = inquire(*
this, exII::EX_INQ_SS_ELEM_LEN,
"Error retrieving length of the concatenated side sets element list!");
1564 char name_buffer[libmesh_max_str_length+1];
1567 ex_err = exII::ex_get_name(
ex_id, exII::EX_SIDE_SET,
1569 EX_CHECK_ERR(
ex_err,
"Error getting side set name.");
1572 message(
"All side set names retrieved successfully.");
1584 EX_CHECK_ERR(
ex_err,
"Error retrieving nodeset information.");
1585 message(
"All nodeset information retrieved successfully.");
1592 char name_buffer[libmesh_max_str_length+1];
1595 ex_err = exII::ex_get_name(
ex_id, exII::EX_NODE_SET,
1597 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1600 message(
"All node set names retrieved successfully.");
1613 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset information.");
1614 message(
"All elemset information retrieved successfully.");
1622 inquire(*
this, exII::EX_INQ_ELS_LEN,
1623 "Error retrieving length of the concatenated elem sets element list!");
1632 char name_buffer[libmesh_max_str_length+1];
1635 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_SET,
1637 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1640 message(
"All elem set names retrieved successfully.");
1647 LOG_SCOPE(
"read_sideset()",
"ExodusII_IO_Helper");
1649 libmesh_assert_less (
id,
ss_ids.size());
1652 libmesh_assert_less_equal (offset,
elem_list.size());
1653 libmesh_assert_less_equal (offset,
side_list.size());
1660 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset parameters.");
1661 message(
"Parameters retrieved successfully for sideset: ",
id);
1667 if (static_cast<unsigned int>(offset) ==
elem_list.size() ||
1668 static_cast<unsigned int>(offset) ==
side_list.size() )
1682 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset data.");
1683 message(
"Data retrieved successfully for sideset: ",
id);
1694 LOG_SCOPE(
"read_elemset()",
"ExodusII_IO_Helper");
1699 libmesh_assert_less_equal (offset,
elemset_list.size());
1706 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset parameters.");
1707 message(
"Parameters retrieved successfully for elemset: ",
id);
1713 if (static_cast<unsigned int>(offset) ==
elemset_list.size())
1726 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset data.");
1727 message(
"Data retrieved successfully for elemset: ",
id);
1739 LOG_SCOPE(
"read_all_nodesets()",
"ExodusII_IO_Helper");
1745 (*
this, exII::EX_INQ_NODE_SETS,
1746 "Error retrieving number of node sets");
1749 int total_nodes_in_all_sets =
1751 (*
this, exII::EX_INQ_NS_NODE_LEN,
1752 "Error retrieving number of nodes in all node sets.");
1755 int total_df_in_all_sets =
1757 (*
this, exII::EX_INQ_NS_DF_LEN,
1758 "Error retrieving number of distribution factors in all node sets.");
1778 exII::ex_set_specs set_specs = {};
1785 set_specs.sets_extra_list =
nullptr;
1786 set_specs.sets_dist_fact = total_df_in_all_sets ? mapped_node_sets_dist_fact.
data() :
nullptr;
1788 ex_err = exII::ex_get_concat_sets(
ex_id, exII::EX_NODE_SET, &set_specs);
1789 EX_CHECK_ERR(
ex_err,
"Error reading concatenated nodesets");
1792 char name_buffer[libmesh_max_str_length+1];
1795 ex_err = exII::ex_get_name
1800 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1831 message(
"Error closing Exodus file.");
1833 message(
"Exodus file closed successfully.");
1854 ex_err = exII::ex_get_all_times
1857 EX_CHECK_ERR(
ex_err,
"Error reading timesteps!");
1866 inquire(*
this, exII::EX_INQ_TIME,
"Error retrieving number of time steps");
1873 LOG_SCOPE(
"read_nodal_var_values()",
"ExodusII_IO_Helper");
1879 unsigned int var_index = 0;
1896 libmesh_error_msg(
"Unable to locate variable named: " << nodal_var_name);
1902 std::vector<Real> unmapped_nodal_var_values(
num_nodes);
1905 ex_err = exII::ex_get_var
1913 EX_CHECK_ERR(
ex_err,
"Error reading nodal variable values!");
1958 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
1966 std::vector<std::string> & result)
1969 ex_err = exII::ex_get_var_param(
ex_id, var_type, &count);
1970 EX_CHECK_ERR(
ex_err,
"Error reading number of variables.");
1977 NamesData names_table(count, libmesh_max_str_length);
1984 EX_CHECK_ERR(
ex_err,
"Error reading variable names!");
1988 libMesh::out <<
"Read the variable(s) from the file:" << std::endl;
1989 for (
int i=0; i<count; i++)
1994 result.resize(count);
1997 for (
int i=0; i<count; i++)
2006 const std::vector<std::string> & names)
2038 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
2047 const std::vector<std::string> & names)
2050 count = cast_int<int>(names.size());
2053 ex_err = exII::ex_put_var_param(
ex_id, var_type, count);
2054 EX_CHECK_ERR(
ex_err,
"Error setting number of vars.");
2066 for (
int i=0; i != count; ++i)
2070 "*** Warning, Exodus variable name \"" <<
2071 names[i] <<
"\" too long (current max " <<
2073 " characters). Name will be truncated. ");
2079 libMesh::out <<
"Writing variable name(s) to file: " << std::endl;
2080 for (
int i=0; i != count; ++i)
2090 EX_CHECK_ERR(
ex_err,
"Error writing variable names.");
2098 std::map<dof_id_type, Real> & elem_var_value_map)
2100 LOG_SCOPE(
"read_elemental_var_values()",
"ExodusII_IO_Helper");
2105 unsigned int var_index = 0;
2122 libmesh_error_msg(
"Unable to locate variable named: " << elemental_var_name);
2126 unsigned ex_el_num = 0;
2132 for (
unsigned i=0; i<static_cast<unsigned>(
num_elem_blk); i++)
2135 exII::EX_ELEM_BLOCK,
2143 EX_CHECK_ERR(
ex_err,
"Error getting number of elements in block.");
2156 ex_err = exII::ex_get_var
2159 exII::EX_ELEM_BLOCK,
2164 EX_CHECK_ERR(
ex_err,
"Error getting elemental values.");
2171 auto libmesh_elem_id =
2175 elem_var_value_map[libmesh_elem_id] = block_elem_var_values[j];
2197 const std::vector<int> & num_map)
2202 auto exodus_id_zero_based =
2203 cast_int<dof_id_type>(exodus_id - 1);
2209 libmesh_error_msg_if(exodus_id_zero_based >= num_map.size(),
2210 "Cannot get LibMesh id for Exodus id: " << exodus_id);
2220 cast_int<dof_id_type>(exodus_id_zero_based) :
2221 cast_int<dof_id_type>(num_map[exodus_id_zero_based] - 1);
2246 int exodus_mapped_id)
2253 auto exodus_mapped_id_zero_based =
2254 cast_int<dof_id_type>(exodus_mapped_id - 1);
2257 dof_object->
set_unique_id(cast_int<unique_id_type>(exodus_mapped_id_zero_based));
2267 #ifdef LIBMESH_ENABLE_UNIQUE_ID 2269 mesh.
set_next_unique_id(std::max(next_unique_id, static_cast<unique_id_type>(exodus_mapped_id_zero_based + 1)));
2293 comp_ws = cast_int<int>(
sizeof(float));
2294 io_ws = cast_int<int>(
sizeof(float));
2300 comp_ws = cast_int<int>
2301 (std::min(
sizeof(
Real),
sizeof(
double)));
2302 io_ws = cast_int<int>
2303 (std::min(
sizeof(
Real),
sizeof(
double)));
2309 int mode = EX_CLOBBER;
2314 #ifdef LIBMESH_HAVE_HDF5 2318 mode |= EX_NOCLASSIC;
2324 ex_id = exII::ex_create(filename.c_str(), mode, &comp_ws, &io_ws);
2327 EX_CHECK_ERR(
ex_id,
"Error creating ExodusII/Nemesis mesh file.");
2334 EX_CHECK_ERR(
ex_err,
"Error setting max ExodusII name length.");
2337 libMesh::out <<
"File created successfully." << std::endl;
2352 libmesh_parallel_only(
mesh.
comm());
2360 auto subdomain_map = build_subdomain_map(
mesh,
_add_sides, subdomain_id_end);
2375 for (
const auto & elem :
mesh.active_local_element_ptr_range())
2377 for (
auto s : elem->side_index_range())
2383 num_local_side_nodes += elem->nodes_on_side(s).size();
2401 mesh.local_nodes_end()));
2406 const dof_id_type n_gaps = max_nn - n_total_nodes;
2407 const dof_id_type gaps_per_processor = n_gaps / n_proc;
2408 const dof_id_type remainder_gaps = n_gaps % n_proc;
2410 n_local_nodes = n_local_nodes +
2411 gaps_per_processor +
2431 if (!use_discontinuous)
2441 for (
const auto & elem :
mesh.active_element_ptr_range())
2445 std::set<boundary_id_type> unique_side_boundaries;
2446 std::vector<boundary_id_type> unique_node_boundaries;
2451 std::vector<boundary_id_type> side_boundaries;
2453 unique_side_boundaries.insert(side_boundaries.begin(), side_boundaries.end());
2457 std::vector<boundary_id_type> shellface_boundaries;
2459 unique_side_boundaries.insert(shellface_boundaries.begin(), shellface_boundaries.end());
2463 unique_side_boundaries.insert(pr.first);
2472 if (std::find(unique_node_boundaries.begin(),
2473 unique_node_boundaries.end(), id)
2474 == unique_node_boundaries.end())
2475 unique_node_boundaries.push_back(
id);
2478 num_side_sets = cast_int<int>(unique_side_boundaries.size());
2479 num_node_sets = cast_int<int>(unique_node_boundaries.size());
2483 if (str_title.size() > MAX_LINE_LENGTH)
2485 libMesh::err <<
"Warning, Exodus files cannot have titles longer than " 2487 <<
" characters. Your title will be truncated." 2489 str_title.resize(MAX_LINE_LENGTH);
2526 exII::ex_init_params params = {};
2527 params.title[str_title.copy(params.title, MAX_LINE_LENGTH)] =
'\0';
2539 EX_CHECK_ERR(
ex_err,
"Error initializing new Exodus file.");
2562 auto push_node = [
this](
const Point & p) {
2606 if (!use_discontinuous)
2608 for (
const auto & node_ptr :
mesh.node_ptr_range())
2610 const Node & node = *node_ptr;
2638 for (
const auto & elem :
mesh.active_element_ptr_range())
2639 for (
const Node & node : elem->node_ref_range())
2657 std::vector<std::vector<const Elem *>>
2660 for (
const auto & elem :
mesh.active_element_ptr_range())
2661 elems_by_pid[elem->processor_id()].push_back(elem);
2664 for (
const Elem * elem : elems_by_pid[p])
2665 for (
auto s : elem->side_index_range())
2670 const std::vector<unsigned int> side_nodes =
2671 elem->nodes_on_side(s);
2673 for (
auto n : side_nodes)
2674 push_node(elem->point(n));
2683 ex_err = exII::ex_put_coord
2689 EX_CHECK_ERR(
ex_err,
"Error writing coordinates to Exodus file.");
2695 EX_CHECK_ERR(
ex_err,
"Error writing node_num_map");
2703 LOG_SCOPE(
"write_elements()",
"ExodusII_IO_Helper");
2708 auto subdomain_map = build_subdomain_map(
mesh,
_add_sides, subdomain_id_end);
2717 std::vector<int> elem_blk_id;
2718 std::vector<int> num_elem_this_blk_vec;
2719 std::vector<int> num_nodes_per_elem_vec;
2720 std::vector<int> num_edges_per_elem_vec;
2721 std::vector<int> num_faces_per_elem_vec;
2722 std::vector<int> num_attr_vec;
2734 unsigned int counter = 0;
2735 for (
auto & [subdomain_id, element_id_vec] : subdomain_map)
2739 const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
2740 ElemType(subdomain_id - subdomain_id_end) :
2743 if (subdomain_id >= subdomain_id_end)
2747 num_elem_this_blk_vec.push_back
2748 (cast_int<int>(element_id_vec[0]));
2750 (Utility::enum_to_string<ElemType>(elem_t));
2755 num_elem_this_blk_vec.push_back
2756 (cast_int<int>(element_id_vec.size()));
2761 num_elem += num_elem_this_blk_vec.back();
2769 libmesh_not_implemented_msg(
"Support for Polygons/Polyhedra not yet implemented");
2771 elem_blk_id.push_back(subdomain_id);
2774 num_attr_vec.push_back(0);
2775 num_edges_per_elem_vec.push_back(0);
2776 num_faces_per_elem_vec.push_back(0);
2790 std::map<std::pair<dof_id_type, unsigned int>,
dof_id_type> discontinuous_node_indices;
2792 if (use_discontinuous)
2794 for (
const auto & elem :
mesh.active_element_ptr_range())
2795 for (
auto n : elem->node_index_range())
2796 discontinuous_node_indices[std::make_pair(elem->id(),n)] =
2804 for (
const Elem * elem :
mesh.active_element_ptr_range())
2808 unsigned int local_node_index = elem->n_nodes();
2810 for (
auto s : elem->side_index_range())
2815 const std::vector<unsigned int> side_nodes =
2816 elem->nodes_on_side(s);
2821 discontinuous_node_indices
2822 [std::make_pair(elem->id(),local_node_index++)] =
2833 std::vector<BoundaryInfo::BCTuple> edge_tuples = bi.
build_edge_list();
2841 std::map<boundary_id_type, std::vector<int>> edge_id_to_conn;
2842 std::map<boundary_id_type, std::pair<ElemType, unsigned int>> edge_id_to_elem_type;
2844 std::unique_ptr<const Elem> edge;
2845 for (
const auto & t : edge_tuples)
2848 unsigned int edge_id = std::get<1>(t);
2856 if (
const auto check_it = edge_id_to_elem_type.find(b_id);
2857 check_it == edge_id_to_elem_type.end())
2860 edge_id_to_elem_type[b_id] = std::make_pair(edge->type(), edge->n_nodes());
2865 const auto & val_pair = check_it->second;
2866 libmesh_error_msg_if(val_pair.first != edge->type() || val_pair.second != edge->n_nodes(),
2867 "All edges in a block must have same geometric type.");
2871 auto & conn = edge_id_to_conn[b_id];
2877 for (
auto n : edge->node_index_range())
2881 int exodus_node_id = -1;
2883 if (!use_discontinuous)
2885 dof_id_type libmesh_node_id = edge->node_ptr(n)->id();
2886 exodus_node_id = libmesh_map_find
2895 exodus_node_id = libmesh_map_find
2896 (discontinuous_node_indices, std::make_pair(elem_id, pn));
2899 conn.push_back(exodus_node_id);
2909 std::vector<int> edge_blk_id;
2911 std::vector<int> num_edge_this_blk_vec;
2912 std::vector<int> num_nodes_per_edge_vec;
2913 std::vector<int> num_attr_edge_vec;
2920 for (
const auto & pr : edge_id_to_conn)
2924 edge_blk_id.push_back(
id);
2927 const auto & elem_type_node_count = edge_id_to_elem_type[id];
2930 num_nodes_per_edge_vec.push_back(elem_type_node_count.second);
2934 num_edge_this_blk_vec.push_back(pr.second.size() / elem_type_node_count.second);
2937 num_attr_edge_vec.push_back(0);
2954 exII::ex_block_params params = {};
2957 params.elem_blk_id = elem_blk_id.data();
2959 params.num_elem_this_blk = num_elem_this_blk_vec.data();
2960 params.num_nodes_per_elem = num_nodes_per_elem_vec.data();
2961 params.num_edges_per_elem = num_edges_per_elem_vec.data();
2962 params.num_faces_per_elem = num_faces_per_elem_vec.data();
2963 params.num_attr_elem = num_attr_vec.data();
2964 params.define_maps = 0;
2969 params.edge_blk_id = edge_blk_id.data();
2971 params.num_edge_this_blk = num_edge_this_blk_vec.data();
2972 params.num_nodes_per_edge = num_nodes_per_edge_vec.data();
2973 params.num_attr_edge = num_attr_edge_vec.data();
2976 ex_err = exII::ex_put_concat_all_blocks(
ex_id, ¶ms);
2977 EX_CHECK_ERR(
ex_err,
"Error writing element blocks.");
2980 unsigned libmesh_elem_num_to_exodus_counter = 0;
2984 auto num_elem_this_blk_it = num_elem_this_blk_vec.begin();
2991 #ifdef LIBMESH_ENABLE_UNIQUE_ID 2996 for (
auto & [subdomain_id, element_id_vec] : subdomain_map)
3002 const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
3003 ElemType(subdomain_id - subdomain_id_end) :
3009 libmesh_not_implemented_msg(
"Support for Polygons/Polyhedra not yet implemented");
3013 if (subdomain_id < subdomain_id_end)
3019 unsigned int elem_id = element_id_vec[i];
3034 libmesh_error_msg_if(elem.
type() != conv.libmesh_elem_type(),
3035 "Error: Exodus requires all elements with a given subdomain ID to be the same type.\n" 3036 <<
"Can't write both " 3040 <<
" in the same block!");
3045 unsigned elem_node_index = conv.get_inverse_node_map(j);
3046 if (!use_discontinuous)
3056 cast_int<int>(libmesh_node_id));
3062 libmesh_map_find(discontinuous_node_indices,
3063 std::make_pair(elem_id, elem_node_index));
3083 libmesh_assert(num_elem_this_blk_it != num_elem_this_blk_vec.end());
3088 std::size_t connect_index = 0;
3089 for (
const auto & elem :
mesh.active_element_ptr_range())
3091 unsigned int local_node_index = elem->n_nodes();
3093 for (
auto s : elem->side_index_range())
3098 if (elem->side_type(s) != elem_t)
3101 const std::vector<unsigned int> side_nodes =
3102 elem->nodes_on_side(s);
3107 const int exodus_node_id = libmesh_map_find
3108 (discontinuous_node_indices,
3109 std::make_pair(elem->id(), local_node_index++));
3110 libmesh_assert_less(connect_index,
connect.size());
3111 connect[connect_index++] = exodus_node_id;
3123 ++num_elem_this_blk_it;
3125 ex_err = exII::ex_put_conn
3127 exII::EX_ELEM_BLOCK,
3132 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
3137 EX_CHECK_ERR(
ex_err,
"Error writing element map");
3143 EX_CHECK_ERR(
ex_err,
"Error writing element block names");
3147 for (
const auto & pr : edge_id_to_conn)
3149 ex_err = exII::ex_put_conn
3151 exII::EX_EDGE_BLOCK,
3156 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
3162 ex_err = exII::ex_put_names
3164 exII::EX_EDGE_BLOCK,
3166 EX_CHECK_ERR(
ex_err,
"Error writing edge block names");
3175 LOG_SCOPE(
"write_sidesets()",
"ExodusII_IO_Helper");
3181 std::map<int, std::vector<int>> elem_lists;
3182 std::map<int, std::vector<int>> side_lists;
3183 std::set<boundary_id_type> side_boundary_ids;
3190 std::vector<const Elem *> family;
3191 #ifdef LIBMESH_ENABLE_AMR 3201 for (
const auto & f : family)
3208 side_lists[std::get<2>(t)].push_back(conv.get_inverse_side_map(std::get<1>(t)));
3212 std::vector<boundary_id_type> tmp;
3214 side_boundary_ids.insert(tmp.begin(), tmp.end());
3223 std::vector<const Elem *> family;
3224 #ifdef LIBMESH_ENABLE_AMR 3234 for (
const auto & f : family)
3241 side_lists[std::get<2>(t)].push_back(conv.get_inverse_shellface_map(std::get<1>(t)));
3245 std::vector<boundary_id_type> tmp;
3247 side_boundary_ids.insert(tmp.begin(), tmp.end());
3252 side_boundary_ids.insert(pr.first);
3255 if (side_boundary_ids.size() > 0)
3259 std::vector<exII::ex_set> sets(side_boundary_ids.size());
3262 for (
auto [i, it] = std::tuple{0u, side_boundary_ids.begin()}; i<sets.size(); ++i, ++it)
3268 sets[i].type = exII::EX_SIDE_SET;
3269 sets[i].num_distribution_factor = 0;
3270 sets[i].distribution_factor_list =
nullptr;
3272 if (
const auto elem_it = elem_lists.find(ss_id);
3273 elem_it == elem_lists.end())
3275 sets[i].num_entry = 0;
3276 sets[i].entry_list =
nullptr;
3277 sets[i].extra_list =
nullptr;
3281 sets[i].num_entry = elem_it->second.size();
3282 sets[i].entry_list = elem_it->second.data();
3283 sets[i].extra_list = libmesh_map_find(side_lists, ss_id).data();
3287 ex_err = exII::ex_put_sets(
ex_id, side_boundary_ids.size(), sets.data());
3288 EX_CHECK_ERR(
ex_err,
"Error writing sidesets");
3290 ex_err = exII::ex_put_names(
ex_id, exII::EX_SIDE_SET, names_table.get_char_star_star());
3291 EX_CHECK_ERR(
ex_err,
"Error writing sideset names");
3299 LOG_SCOPE(
"write_nodesets()",
"ExodusII_IO_Helper");
3316 std::stable_sort(bc_tuples.begin(), bc_tuples.end(),
3319 {
return std::get<1>(t1) < std::get<1>(t2); });
3321 std::vector<boundary_id_type> node_boundary_ids;
3329 if (std::find(node_boundary_ids.begin(),
3330 node_boundary_ids.end(), id)
3331 == node_boundary_ids.end())
3332 node_boundary_ids.push_back(
id);
3336 if (node_boundary_ids.size() > 0)
3356 std::map<boundary_id_type, unsigned int> nodeset_counts;
3357 for (
auto id : node_boundary_ids)
3358 nodeset_counts[id] = 0;
3360 for (
const auto & t : bc_tuples)
3365 nodeset_counts[nodeset_id] += 1;
3369 unsigned int running_sum = 0;
3370 for (
const auto & pr : nodeset_counts)
3376 running_sum += pr.second;
3381 exII::ex_set_specs set_data = {};
3390 ex_err = exII::ex_put_concat_sets(
ex_id, exII::EX_NODE_SET, &set_data);
3391 EX_CHECK_ERR(
ex_err,
"Error writing concatenated nodesets");
3394 ex_err = exII::ex_put_names(
ex_id, exII::EX_NODE_SET, names_table.get_char_star_star());
3395 EX_CHECK_ERR(
ex_err,
"Error writing nodeset names");
3402 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
3408 if (names.size() == 0)
3431 for (
auto var_num :
index_range(vars_active_subdomains))
3435 std::set<subdomain_id_type> current_set;
3436 if (vars_active_subdomains[var_num].empty())
3438 current_set.insert(restrict_int<subdomain_id_type>(block_id));
3440 current_set = vars_active_subdomains[var_num];
3443 for (
auto block_id : current_set)
3446 libmesh_error_msg_if(it ==
block_ids.end(),
3447 "ExodusII_IO_Helper: block id " << block_id <<
" not found in block_ids.");
3449 std::size_t block_index =
3452 std::size_t truth_tab_index = block_index*
num_elem_vars + var_num;
3453 truth_tab[truth_tab_index] = 1;
3457 ex_err = exII::ex_put_truth_table
3459 exII::EX_ELEM_BLOCK,
3463 EX_CHECK_ERR(
ex_err,
"Error writing element truth table.");
3474 if (names.size() == 0)
3502 if (names.size() == 0)
3523 std::vector<std::string> & names,
3524 std::vector<std::string> & names_from_file)
3538 std::equal(names.begin(), names.end(),
3539 names_from_file.begin(),
3540 [
this](
const std::string & a,
3541 const std::string &
b) ->
bool 3548 libMesh::err <<
"Error! The Exodus file already contains the variables:" << std::endl;
3549 for (
const auto &
name : names_from_file)
3552 libMesh::err <<
"And you asked to write:" << std::endl;
3553 for (
const auto &
name : names)
3556 libmesh_error_msg(
"Cannot overwrite existing variables in Exodus II file.");
3569 float cast_time = float(time);
3570 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
3574 double cast_time = double(time);
3575 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
3577 EX_CHECK_ERR(
ex_err,
"Error writing timestep.");
3587 LOG_SCOPE(
"write_elemsets()",
"ExodusII_IO_Helper");
3599 std::map<elemset_id_type, std::vector<int>> exodus_elemsets;
3601 unsigned int elemset_index =
3606 for (
const auto & elem :
mesh.element_ptr_range())
3609 elem->get_extra_integer(elemset_index);
3621 for (
const auto & set_id : set_ids)
3635 if (!exodus_elemsets.empty())
3641 std::vector<exII::ex_set> sets;
3642 sets.reserve(exodus_elemsets.size());
3644 for (
auto & [elem_set_id, ids_vec] : exodus_elemsets)
3649 exII::ex_set & current_set = sets.emplace_back();
3650 current_set.id = elem_set_id;
3651 current_set.type = exII::EX_ELEM_SET;
3652 current_set.num_entry = ids_vec.size();
3653 current_set.num_distribution_factor = 0;
3654 current_set.entry_list = ids_vec.data();
3655 current_set.extra_list =
nullptr;
3656 current_set.distribution_factor_list =
nullptr;
3661 libmesh_assert_msg(
num_elem_sets == cast_int<int>(exodus_elemsets.size()),
3662 "Mesh has " << exodus_elemsets.size()
3663 <<
" elemsets, but header was written with num_elem_sets == " <<
num_elem_sets);
3666 <<
", but header was written with num_elem_sets == " <<
num_elem_sets);
3668 ex_err = exII::ex_put_sets(
ex_id, exodus_elemsets.size(), sets.data());
3669 EX_CHECK_ERR(
ex_err,
"Error writing elemsets");
3684 const std::vector<std::string> & var_names,
3685 const std::vector<std::set<boundary_id_type>> & side_ids,
3686 const std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
3688 LOG_SCOPE(
"write_sideset_data()",
"ExodusII_IO_Helper");
3714 std::vector<int> sset_var_tab(
num_side_sets * var_names.size());
3733 if (!side_ids[var].count(
ss_ids[ss]))
3737 sset_var_tab[ss*var_names.size() + var] = 1;
3743 const auto & data_map = bc_vals[var];
3766 libmesh_error_msg_if
3768 cast_int<dof_id_type>(
elem_list[i + offset]),
3769 "Error mapping Exodus elem id to libmesh elem id.");
3787 sset_var_vals[i] = libmesh_map_find(data_map, key);
3793 if (sset_var_vals.size() > 0)
3795 ex_err = exII::ex_put_var
3803 EX_CHECK_ERR(
ex_err,
"Error writing sideset vars.");
3810 exII::ex_put_truth_table(
ex_id,
3813 cast_int<int>(var_names.size()),
3814 sset_var_tab.data());
3815 EX_CHECK_ERR(
ex_err,
"Error writing sideset var truth table.");
3824 std::vector<std::string> & var_names,
3825 std::vector<std::set<boundary_id_type>> & side_ids,
3826 std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
3828 LOG_SCOPE(
"read_sideset_data()",
"ExodusII_IO_Helper");
3838 ex_err = exII::ex_get_truth_table
3843 sset_var_tab.data());
3844 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable truth table.");
3873 side_ids[var].insert(
ss_ids[ss]);
3879 ex_err = exII::ex_get_var
3887 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable.");
3892 unsigned int exodus_side_id =
side_list[i + offset];
3897 dof_id_type converted_elem_id = exodus_elem_id - 1;
3906 unsigned int converted_side_id = conv.
get_side_map(exodus_side_id - 1);
3915 bc_vals[var].emplace(key, sset_var_vals[i]);
3927 std::map<BoundaryInfo::BCTuple, unsigned int> & bc_array_indices)
3930 bc_array_indices.clear();
3944 unsigned int exodus_side_id =
side_list[i + offset];
3949 dof_id_type converted_elem_id = exodus_elem_id - 1;
3957 unsigned int converted_side_id = conv.
get_side_map(exodus_side_id - 1);
3966 bc_array_indices.emplace(key, cast_int<unsigned int>(i));
3975 const std::vector<std::string> & var_names,
3976 const std::vector<std::set<boundary_id_type>> & node_boundary_ids,
3977 const std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals)
3979 LOG_SCOPE(
"write_nodeset_data()",
"ExodusII_IO_Helper");
4003 std::vector<int> nset_var_tab(
num_node_sets * var_names.size());
4015 if (!node_boundary_ids[var].count(
nodeset_ids[ns]))
4019 nset_var_tab[ns*var_names.size() + var] = 1;
4025 const auto & data_map = bc_vals[var];
4039 std::make_tuple(libmesh_node_id,
nodeset_ids[ns]);
4046 nset_var_vals[i] = libmesh_map_find(data_map, key);
4050 if (nset_var_vals.size() > 0)
4052 ex_err = exII::ex_put_var
4060 EX_CHECK_ERR(
ex_err,
"Error writing nodeset vars.");
4067 exII::ex_put_truth_table(
ex_id,
4070 cast_int<int>(var_names.size()),
4071 nset_var_tab.data());
4072 EX_CHECK_ERR(
ex_err,
"Error writing nodeset var truth table.");
4080 const std::vector<std::string> & var_names,
4081 const std::vector<std::set<elemset_id_type>> & elemset_ids_in,
4082 const std::vector<std::map<std::pair<dof_id_type, elemset_id_type>,
Real>> & elemset_vals)
4084 LOG_SCOPE(
"write_elemset_data()",
"ExodusII_IO_Helper");
4113 std::vector<int> elemset_var_tab(
num_elem_sets * var_names.size());
4139 elemset_var_tab[es*var_names.size() + var] = 1;
4145 const auto & data_map = elemset_vals[var];
4158 std::pair<dof_id_type, elemset_id_type> key =
4169 elemset_var_vals[i] = libmesh_map_find(data_map, key);
4173 if (elemset_var_vals.size() > 0)
4175 ex_err = exII::ex_put_var
4183 EX_CHECK_ERR(
ex_err,
"Error writing elemset vars.");
4190 exII::ex_put_truth_table(
ex_id,
4193 cast_int<int>(var_names.size()),
4194 elemset_var_tab.data());
4195 EX_CHECK_ERR(
ex_err,
"Error writing elemset var truth table.");
4203 std::vector<std::string> & var_names,
4204 std::vector<std::set<elemset_id_type>> & elemset_ids_in,
4205 std::vector<std::map<std::pair<dof_id_type, elemset_id_type>,
Real>> & elemset_vals)
4207 LOG_SCOPE(
"read_elemset_data()",
"ExodusII_IO_Helper");
4228 exII::ex_get_truth_table(
ex_id,
4232 elemset_var_tab.data());
4233 EX_CHECK_ERR(
ex_err,
"Error reading elemset variable truth table.");
4276 ex_err = exII::ex_get_var
4284 EX_CHECK_ERR(
ex_err,
"Error reading elemset variable.");
4293 dof_id_type converted_elem_id = exodus_elem_id - 1;
4296 auto key = std::make_pair(converted_elem_id,
4300 elemset_vals[var].emplace(key, elemset_var_vals[i]);
4314 elemset_array_indices.clear();
4338 dof_id_type converted_elem_id = exodus_elem_id - 1;
4342 auto key = std::make_pair(converted_elem_id,
4346 elemset_array_indices.emplace(key, cast_int<unsigned int>(i));
4355 std::vector<std::string> & var_names,
4356 std::vector<std::set<boundary_id_type>> & node_boundary_ids,
4357 std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals)
4359 LOG_SCOPE(
"read_nodeset_data()",
"ExodusII_IO_Helper");
4369 ex_err = exII::ex_get_truth_table
4374 nset_var_tab.data());
4375 EX_CHECK_ERR(
ex_err,
"Error reading nodeset variable truth table.");
4411 ex_err = exII::ex_get_var
4419 EX_CHECK_ERR(
ex_err,
"Error reading nodeset variable.");
4434 dof_id_type converted_node_id = exodus_node_id - 1;
4441 bc_vals[var].emplace(key, nset_var_vals[i]);
4456 bc_array_indices.clear();
4485 dof_id_type converted_node_id = exodus_node_id - 1;
4492 bc_array_indices.emplace(key, cast_int<unsigned int>(i));
4499 const std::vector<Real> & values,
4501 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
4503 LOG_SCOPE(
"write_element_values()",
"ExodusII_IO_Helper");
4510 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
4515 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
4516 for (
const auto & elem :
mesh.active_element_ptr_range())
4517 subdomain_map[elem->subdomain_id()].push_back(elem->id());
4526 libmesh_assert_equal_to
4527 (vars_active_subdomains.size(),
4533 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
4536 auto it = subdomain_map.begin();
4539 const auto & active_subdomains
4540 = vars_active_subdomains[var_id];
4542 for (
unsigned int j=0; it!=subdomain_map.end(); ++it, ++j)
4547 if (!(active_subdomains.empty() || active_subdomains.count(it->first)))
4553 const auto & elem_nums = it->second;
4554 const unsigned int num_elems_this_block =
4555 cast_int<unsigned int>(elem_nums.size());
4556 std::vector<Real> data(num_elems_this_block);
4561 for (
unsigned int k=0; k<num_elems_this_block; ++k)
4562 data[k] = values[var_id*
n_elem + elem_nums[k]];
4564 ex_err = exII::ex_put_var
4567 exII::EX_ELEM_BLOCK,
4570 num_elems_this_block,
4573 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
4584 const std::vector<Real> & values,
4586 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
4587 const std::vector<std::string> & derived_var_names,
4588 const std::map<
subdomain_id_type, std::vector<std::string>> & subdomain_to_var_names)
4595 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
4602 std::map<subdomain_id_type, unsigned int> subdomain_to_n_elem;
4603 for (
const auto & elem :
mesh.active_element_ptr_range())
4604 subdomain_to_n_elem[elem->subdomain_id()] += 1;
4608 libmesh_assert_equal_to
4609 (vars_active_subdomains.size(),
4613 auto subdomain_to_n_elem_iter = subdomain_to_n_elem.begin();
4619 (
mesh.active_elements_begin(),
4620 mesh.active_elements_end());
4622 for (
unsigned int sbd_idx=0;
4623 subdomain_to_n_elem_iter != subdomain_to_n_elem.end();
4624 ++subdomain_to_n_elem_iter, ++sbd_idx)
4625 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
4628 const auto & active_subdomains
4629 = vars_active_subdomains[var_id];
4636 if (!active_subdomains.count(subdomain_to_n_elem_iter->first))
4640 std::vector<Real> data;
4641 data.reserve(subdomain_to_n_elem_iter->second);
4643 unsigned int values_offset = 0;
4644 for (
auto & elem : elem_range)
4651 auto subdomain_to_var_names_iter =
4652 subdomain_to_var_names.find(sbd_id);
4660 if (subdomain_to_var_names_iter == subdomain_to_var_names.end())
4663 const auto & var_names_this_sbd
4664 = subdomain_to_var_names_iter->second;
4667 if (sbd_id == subdomain_to_n_elem_iter->first)
4675 std::find(var_names_this_sbd.begin(),
4676 var_names_this_sbd.end(),
4677 derived_var_names[var_id]);
4679 libmesh_error_msg_if(pos == var_names_this_sbd.end(),
4680 "Derived name " << derived_var_names[var_id] <<
" not found!");
4687 data.push_back(values[values_offset + true_index]);
4692 auto true_offset = var_names_this_sbd.size();
4695 values_offset += true_offset;
4701 ex_err = exII::ex_put_var
4704 exII::EX_ELEM_BLOCK,
4710 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
4721 const std::vector<Real> & values,
4727 if (!values.empty())
4729 libmesh_assert_equal_to(values.size(), std::size_t(
num_nodes));
4731 ex_err = exII::ex_put_var
4740 EX_CHECK_ERR(
ex_err,
"Error writing nodal values.");
4757 int num_info = inquire(*
this, exII::EX_INQ_INFO,
"Error retrieving the number of information records from file!");
4760 libMesh::err <<
"Warning! The Exodus file already contains information records.\n" 4761 <<
"Exodus does not support writing additional records in this situation." 4766 int num_records = cast_int<int>(records.size());
4768 if (num_records > 0)
4774 for (
const auto & record : records)
4775 info.push_back_entry(record);
4777 ex_err = exII::ex_put_info(
ex_id, num_records,
info.get_char_star_star());
4778 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
4791 if (!values.empty())
4793 ex_err = exII::ex_put_var
4802 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
4813 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
4825 ex_err = exII::ex_get_var
4834 EX_CHECK_ERR(
ex_err,
"Error reading global values.");
4854 libmesh_error_msg_if (max_length > libmesh_max_str_length,
4855 "Exodus maximum name length is limited to " <<
4856 libmesh_max_str_length <<
" characters");
4878 std::vector<std::string>
4880 bool write_complex_abs)
const 4882 std::vector<std::string> complex_names;
4886 for (
const auto &
name : names)
4888 complex_names.push_back(
"r_" +
name);
4889 complex_names.push_back(
"i_" +
name);
4890 if (write_complex_abs)
4891 complex_names.push_back(
"a_" +
name);
4894 return complex_names;
4899 std::vector<std::set<subdomain_id_type>>
4902 (
const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
4903 bool write_complex_abs)
const 4905 std::vector<std::set<subdomain_id_type>> complex_vars_active_subdomains;
4907 for (
auto & s : vars_active_subdomains)
4911 complex_vars_active_subdomains.push_back(s);
4912 complex_vars_active_subdomains.push_back(s);
4913 if (write_complex_abs)
4914 complex_vars_active_subdomains.push_back(s);
4917 return complex_vars_active_subdomains;
4922 std::map<subdomain_id_type, std::vector<std::string>>
4926 bool write_complex_abs)
const 4929 std::map<subdomain_id_type, std::vector<std::string>> ret;
4931 unsigned int num_complex_outputs = write_complex_abs ? 3 : 2;
4933 for (
const auto & pr : subdomain_to_var_names)
4936 auto & vec = ret[pr.first];
4939 const auto & varnames = pr.second;
4942 vec.reserve(num_complex_outputs * varnames.size());
4947 for (
const auto & varname : varnames)
4949 vec.push_back(
"r_" + varname);
4950 vec.push_back(
"i_" + varname);
4951 if (write_complex_abs)
4952 vec.push_back(
"a_" + varname);
4965 libmesh_assert_less (i, node_map->size());
4966 return (*node_map)[i];
4973 if (!inverse_node_map)
4976 libmesh_assert_less (i, inverse_node_map->size());
4977 return (*inverse_node_map)[i];
4989 if (static_cast<size_t>(i) >= side_map->size())
4992 return (*side_map)[i];
5000 if (!inverse_side_map)
5003 libmesh_assert_less (i, inverse_side_map->size());
5004 return (*inverse_side_map)[i];
5018 libmesh_assert_less (i, shellface_map->size());
5019 return (*shellface_map)[i];
5026 if (!inverse_shellface_map)
5029 libmesh_assert_less (i, inverse_shellface_map->size());
5030 return (*inverse_shellface_map)[i];
5037 return libmesh_type;
5054 return shellface_index_offset;
5058 data_table(n_strings),
5059 data_table_pointers(n_strings),
5061 table_size(n_strings)
5063 for (
size_t i=0; i<n_strings; ++i)
5079 libmesh_assert_less (counter, table_size);
5082 size_t num_copied =
name.copy(data_table[counter].data(), data_table[counter].size()-1);
5085 data_table[counter][num_copied] =
'\0';
5095 return data_table_pointers.data();
5102 libmesh_error_msg_if(static_cast<unsigned>(i) >= table_size,
5103 "Requested char * " << i <<
" but only have " << table_size <<
"!");
5105 return data_table[i].data();
5114 #endif // #ifdef LIBMESH_HAVE_EXODUS_API std::vector< int > elemset_list
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
virtual void write_sidesets(const MeshBase &mesh)
Writes the sidesets contained in "mesh".
std::vector< int > num_elems_per_set
void write_sideset_data(const MeshBase &mesh, int timestep, const std::vector< std::string > &var_names, const std::vector< std::set< boundary_id_type >> &side_ids, const std::vector< std::map< BoundaryInfo::BCTuple, Real >> &bc_vals)
Write sideset data for the requested timestep.
void use_mesh_dimension_instead_of_spatial_dimension(bool val)
Sets the underlying value of the boolean flag _use_mesh_dimension_instead_of_spatial_dimension.
std::vector< int > id_list
void write_var_names(ExodusVarType type, const std::vector< std::string > &names)
Wraps calls to exII::ex_put_var_names() and exII::ex_put_var_param().
The FPEDisabler class puts Floating-Point Exception (FPE) trapping on hold during its lifetime...
std::tuple< dof_id_type, unsigned short int, boundary_id_type > BCTuple
Create a list of (element_id, side_id, boundary_id) tuples for relevant sides.
This class facilitates inline conversion of an input data vector to a different precision level...
ElemType
Defines an enum for geometric element types.
std::vector< std::string > sideset_var_names
std::vector< int > node_num_map
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
void read_node_num_map()
Reads the optional node_num_map from the ExodusII mesh file.
bool _elem_vars_initialized
std::vector< int > num_sides_per_set
void set_max_name_length(unsigned int max_length)
Set how many characters to use in names when opening a file for writing.
const char * get_elem_type() const
std::vector< BCTuple > build_shellface_list() const
Create a list of (element_id, shellface_id, boundary_id) tuples for all relevant shellfaces.
void get_elemset_data_indices(std::map< std::pair< dof_id_type, elemset_id_type >, unsigned int > &elemset_array_indices)
Similar to read_elemset_data(), but instead of creating one std::map per elemset per variable...
void read_elemset(int id, int offset)
Reads information about elemset id and inserts it into the global elemset array at the position offse...
std::vector< std::string > elem_var_names
void active_family_tree_by_side(std::vector< const Elem *> &family, unsigned int side, bool reset=true) const
Same as the active_family_tree() member, but only adds elements which are next to side...
virtual dof_id_type n_active_elem() const =0
A Node is like a Point, but with more information.
void read_elemset_data(int timestep, std::vector< std::string > &var_names, std::vector< std::set< elemset_id_type >> &elemset_ids_in, std::vector< std::map< std::pair< dof_id_type, elemset_id_type >, Real >> &elemset_vals)
Read elemset variables, if any, into the provided data structures.
ExodusHeaderInfo read_header() const
Reads an ExodusII mesh file header, leaving this object's internal data structures unchanged...
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
std::map< int, std::string > id_to_ss_names
std::vector< std::string > get_complex_names(const std::vector< std::string > &names, bool write_complex_abs) const
virtual ~ExodusII_IO_Helper()
std::string get_block_name(int index)
Get the block name for the given block index if supplied in the mesh file.
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
std::map< int, std::string > id_to_edge_block_names
void read_sideset_info()
Reads information about all of the sidesets in the ExodusII mesh file.
void read_nodal_var_values(std::string nodal_var_name, int time_step)
Reads the nodal values for the variable 'nodal_var_name' at the specified time into the 'nodal_var_va...
std::size_t n_edge_conds() const
ExodusII_IO_Helper(const ParallelObject &parent, bool v=false, bool run_only_on_proc0=true, bool single_precision=false)
Constructor.
void write_information_records(const std::vector< std::string > &records)
Writes the vector of information records.
virtual void read_var_names_impl(const char *var_type, int &count, std::vector< std::string > &result)
read_var_names() dispatches to this function.
static const int invalid_id
An invalid_id that can be returned to signal failure in case something goes wrong.
void write_as_dimension(unsigned dim)
Sets the value of _write_as_dimension.
std::map< dof_id_type, Real > nodal_var_values
const boundary_id_type side_id
std::string get_side_set_name(int index)
Get the side set name for the given side set index if supplied in the mesh file.
const std::map< boundary_id_type, std::string > & get_sideset_name_map() const
bool has_elem_integer(std::string_view name) const
This is the base class from which all geometric element types are derived.
bool _global_vars_initialized
unique_id_type unique_id() const
void get_sideset_data_indices(const MeshBase &mesh, std::map< BoundaryInfo::BCTuple, unsigned int > &bc_array_indices)
Similar to read_sideset_data(), but instead of creating one std::map per sideset per variable...
const Parallel::Communicator & comm() const
dof_id_type get_libmesh_id(int exodus_id, const std::vector< int > &num_map)
Internal implementation for the two sets of functions above.
std::vector< int > block_ids
std::vector< int > side_list
virtual void write_nodesets(const MeshBase &mesh)
Writes the nodesets contained in "mesh".
void build_side_boundary_ids(std::vector< boundary_id_type > &b_ids) const
Builds the list of unique side boundary ids.
void read_bex_cv_blocks()
Reads the optional bex_cv_blocks from the ExodusII mesh file.
void read_nodeset_data(int timestep, std::vector< std::string > &var_names, std::vector< std::set< boundary_id_type >> &node_boundary_ids, std::vector< std::map< BoundaryInfo::NodeBCTuple, Real >> &bc_vals)
Read nodeset variables, if any, into the provided data structures.
The StoredRange class defines a contiguous, divisible set of objects.
virtual void set_next_unique_id(unique_id_type id)=0
Sets the next available unique id to be used.
std::vector< Real > time_steps
MappedOutputVector(const std::vector< Real > &vec_in, bool single_precision_in)
virtual void write_elements(const MeshBase &mesh, bool use_discontinuous=false)
Writes the elements contained in "mesh".
std::vector< std::set< subdomain_id_type > > get_complex_vars_active_subdomains(const std::vector< std::set< subdomain_id_type >> &vars_active_subdomains, bool write_complex_abs) const
returns a "tripled" copy of vars_active_subdomains, which is necessary in the complex-valued case...
unique_id_type next_unique_id() const
void write_elemsets(const MeshBase &mesh)
Write elemsets stored on the Mesh to the exo file.
const ExodusII_IO_Helper::Conversion & get_conversion(const ElemType type) const
void print_nodes(std::ostream &out_stream=libMesh::out)
Prints the nodal information, by default to libMesh::out.
The libMesh namespace provides an interface to certain functionality in the library.
std::vector< std::vector< char > > data_table
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
void read_time_steps()
Reads and stores the timesteps in the 'time_steps' array.
std::vector< int > node_sets_node_index
std::vector< char > & title
ExodusHeaderInfo header_info
void write_nodal_values(int var_id, const std::vector< Real > &values, int timestep)
Writes the vector of values to a nodal variable.
bool _add_sides
Set to true iff we want to write separate "side" elements too.
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
void message(std::string_view msg)
Prints the message defined in msg.
void check_existing_vars(ExodusVarType type, std::vector< std::string > &names, std::vector< std::string > &names_from_file)
When appending: during initialization, check that variable names in the file match those you attempt ...
Real distance(const Point &p)
void read_nodes()
Reads the nodal data (x,y,z coordinates) from the ExodusII mesh file.
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...
std::vector< std::string > nodeset_var_names
std::map< dof_id_type, dof_id_type > libmesh_node_num_to_exodus
uint8_t processor_id_type
This is the MeshBase class.
void close() noexcept
Closes the ExodusII mesh file.
void write_element_values(const MeshBase &mesh, const std::vector< Real > &values, int timestep, const std::vector< std::set< subdomain_id_type >> &vars_active_subdomains)
Writes the vector of values to the element variables.
void write_timestep(int timestep, Real time)
Writes the time for the timestep.
void get_elemsets(dof_id_type elemset_code, MeshBase::elemset_type &id_set_to_fill) const
Look up the element sets for a given elemset code and vice-versa.
bool _use_mesh_dimension_instead_of_spatial_dimension
void read_edge_blocks(MeshBase &mesh)
Read in edge blocks, storing information in the BoundaryInfo object.
std::tuple< dof_id_type, boundary_id_type > NodeBCTuple
Create a list of (node_id, boundary_id) tuples for all relevant nodes.
virtual void initialize_element_variables(std::vector< std::string > names, const std::vector< std::set< subdomain_id_type >> &vars_active_subdomains)
Sets up the nodal variables.
std::vector< float > float_vec
void open(const char *filename, bool read_only)
Opens an ExodusII mesh file named filename.
unsigned int get_elem_integer_index(std::string_view name) const
processor_id_type n_processors() const
void libmesh_ignore(const Args &...)
char * get_char_star(int i)
Provide access to the i'th underlying char *.
const std::map< boundary_id_type, std::string > & get_nodeset_name_map() const
const std::string & get_edgeset_name(boundary_id_type id) const
std::vector< int > nodeset_ids
bool set_unique_ids_from_maps
void set_dof_object_unique_id(MeshBase &mesh, DofObject *dof_object, int exodus_mapped_id)
void update()
Uses ex_update() to flush buffers to file.
void push_back_entry(const std::string &name)
Adds another name to the current data table.
void read_all_nodesets()
New API that reads all nodesets simultaneously.
void read_global_values(std::vector< Real > &values, int timestep)
Reads the vector of global variables.
std::vector< int > elem_list
std::vector< double > double_vec
std::vector< std::string > global_var_names
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
void read_var_names(ExodusVarType type)
void write_nodeset_data(int timestep, const std::vector< std::string > &var_names, const std::vector< std::set< boundary_id_type >> &node_boundary_ids, const std::vector< std::map< BoundaryInfo::NodeBCTuple, Real >> &bc_vals)
Write nodeset data for the requested timestep.
std::vector< int > connect
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const =0
Similar to Elem::local_side_node(), but instead of a side id, takes an edge id and a node id on that ...
virtual dof_id_type max_elem_id() const =0
void subdomain_ids(std::set< subdomain_id_type > &ids, const bool global=true) const
Constructs a list of all subdomain identifiers in the local mesh if global == false, and in the global mesh if global == true (default).
void read_elemset_info()
Reads information about all of the elemsets in the ExodusII mesh file.
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
std::vector< int > elemset_ids
std::vector< BCTuple > build_edge_list() const
Create a list of (element_id, edge_id, boundary_id) tuples for all relevant edges.
void write_elemset_data(int timestep, const std::vector< std::string > &var_names, const std::vector< std::set< elemset_id_type >> &elemset_ids_in, const std::vector< std::map< std::pair< dof_id_type, elemset_id_type >, Real >> &elemset_vals)
Write elemset data for the requested timestep.
std::vector< int > ss_ids
int get_inverse_shellface_map(int i) const
void write_element_values_element_major(const MeshBase &mesh, const std::vector< Real > &values, int timestep, const std::vector< std::set< subdomain_id_type >> &vars_active_subdomains, const std::vector< std::string > &derived_var_names, const std::map< subdomain_id_type, std::vector< std::string >> &subdomain_to_var_names)
Same as the function above, but assume the input 'values' vector is in element-major order...
unsigned int n_elemsets() const
Returns the number of unique elemset ids which have been added via add_elemset_code(), which is the size of the _all_elemset_ids set.
void read_nodeset_info()
Reads information about all of the nodesets in the ExodusII mesh file.
This is the ExodusII_IO_Helper class.
void set_coordinate_offset(Point p)
Allows you to set a vector that is added to the coordinates of all of the nodes.
std::string & subdomain_name(subdomain_id_type id)
void write_global_values(const std::vector< Real > &values, int timestep)
Writes the vector of global variables.
int get_inverse_node_map(int i) const
std::vector< dof_id_type > _true_node_offsets
If we're adding "fake" sides to visualize SIDE_DISCONTINUOUS variables, we also need to know how many...
An object whose state is distributed along a set of processors.
void read_elem_in_block(int block)
Reads all of the element connectivity for block block in the ExodusII mesh file.
const std::string & get_nodeset_name(boundary_id_type id) const
std::size_t get_shellface_index_offset() const
std::map< dof_id_type, dof_id_type > libmesh_elem_num_to_exodus
unsigned int _max_name_length
int get_node_map(int i) const
int num_elem_all_elemsets
void initialize_global_variables(std::vector< std::string > names)
Sets up the global variables.
void read_sideset_data(const MeshBase &mesh, int timestep, std::vector< std::string > &var_names, std::vector< std::set< boundary_id_type >> &side_ids, std::vector< std::map< BoundaryInfo::BCTuple, Real >> &bc_vals)
Read sideset variables, if any, into the provided data structures.
unsigned _write_as_dimension
std::vector< char * > data_table_pointers
std::string enum_to_string(const T e)
unsigned int bex_num_elem_cvs
std::vector< int > num_node_df_per_set
char ** get_char_star_star()
Provide access to the underlying C data table.
int get_node_set_id(int index)
Get the node set id for the given node set index.
virtual const Elem * elem_ptr(const dof_id_type i) const =0
void build_node_boundary_ids(std::vector< boundary_id_type > &b_ids) const
Builds the list of unique node boundary ids.
ExodusVarType
Wraps calls to exII::ex_get_var_names() and exII::ex_get_var_param().
std::map< std::string, ElemType > element_equivalence_map
Defines equivalence classes of Exodus element types that map to libmesh ElemTypes.
const std::vector< Real > & our_data
std::set< elemset_id_type > elemset_type
Typedef for the "set" container used to store elemset ids.
virtual void initialize(std::string title, const MeshBase &mesh, bool use_discontinuous=false)
Initializes the Exodus file.
void set_unique_id(unique_id_type new_id)
Sets the unique_id for this DofObject.
virtual void create(std::string filename)
Opens an ExodusII mesh file named filename for writing.
std::vector< int > node_sets_node_list
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void read_num_time_steps()
Reads the number of timesteps currently stored in the Exodus file and stores it in the num_time_steps...
void read_block_info()
Reads information for all of the blocks in the ExodusII mesh file.
void read_elem_num_map()
Reads the optional node_num_map from the ExodusII mesh file.
ElemType libmesh_elem_type() const
void read_and_store_header_info()
Reads an ExodusII mesh file header, and stores required information on this object.
unsigned int spatial_dimension() const
void read_sideset(int id, int offset)
Reads information about sideset id and inserts it into the global sideset array at the position offse...
std::vector< dof_id_type > _added_side_node_offsets
If we're adding "fake" sides to visualize SIDE_DISCONTINUOUS variables, _added_side_node_offsets[p] g...
int get_inverse_side_map(int i) const
NamesData(size_t n_strings, size_t string_length)
Constructor.
const std::set< boundary_id_type > & get_edge_boundary_ids() const
void init_element_equivalence_map()
const std::string & get_sideset_name(boundary_id_type id) const
virtual const Elem & elem_ref(const dof_id_type i) const
void set_hdf5_writing(bool write_hdf5)
Set to true (the default) to write files in an HDF5-based file format (when HDF5 is available)...
std::map< int, std::string > id_to_block_names
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...
void conditionally_set_elem_unique_id(MeshBase &mesh, Elem *elem, int zero_based_elem_num_map_index)
The DofObject defines an abstract base class for objects that have degrees of freedom associated with...
unsigned int mesh_dimension() const
std::vector< int > elem_num_map
dof_id_type get_libmesh_node_id(int exodus_node_id)
Helper function that takes a (1-based) Exodus node/elem id and determines the corresponding libMesh N...
std::string & edgeset_name(boundary_id_type id)
int get_side_set_id(int index)
Get the side set id for the given side set index.
std::vector< std::string > elemset_var_names
void print_header()
Prints the ExodusII mesh file header, which includes the mesh title, the number of nodes...
std::map< int, std::string > id_to_ns_names
void initialize_nodal_variables(std::vector< std::string > names)
Sets up the nodal variables.
std::vector< int > num_nodes_per_set
std::string exodus_elem_type() const
std::vector< NodeBCTuple > build_node_list(NodeBCTupleSortBy sort_by=NodeBCTupleSortBy::NODE_ID) const
std::vector< std::string > nodal_var_names
std::string get_node_set_name(int index)
Get the node set name for the given node set index if supplied in the mesh file.
void init_conversion_map()
std::string current_filename
std::map< int, std::string > id_to_elemset_names
virtual dof_id_type max_node_id() const =0
virtual dof_id_type n_elem() const =0
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i)=0
virtual const Node * node_ptr(const dof_id_type i) const =0
std::vector< int > edge_block_ids
processor_id_type processor_id() const
void conditionally_set_node_unique_id(MeshBase &mesh, Node *node, int zero_based_node_num_map_index)
Helper function that conditionally sets the unique_id of the passed-in Node/Elem. ...
void read_qa_records()
Reads the QA records from an ExodusII file.
This class is useful for managing anything that requires a char ** input/output in ExodusII file...
void read_elemental_var_values(std::string elemental_var_name, int time_step, std::map< dof_id_type, Real > &elem_var_value_map)
Reads elemental values for the variable 'elemental_var_name' at the specified timestep into the 'elem...
std::vector< char > elem_type
static ElemType first_order_equivalent_type(const ElemType et)
std::vector< Real > node_sets_dist_fact
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
dof_id_type node_id(const unsigned int i) const
void get_nodeset_data_indices(std::map< BoundaryInfo::NodeBCTuple, unsigned int > &bc_array_indices)
Similar to read_nodeset_data(), but instead of creating one std::map per nodeset per variable...
int get_block_id(int index)
Get the block number for the given block index.
dof_id_type get_libmesh_elem_id(int exodus_elem_id)
std::map< subdomain_id_type, std::vector< std::string > > get_complex_subdomain_to_var_names(const std::map< subdomain_id_type, std::vector< std::string >> &subdomain_to_var_names, bool write_complex_abs) const
Takes a map from subdomain id -> vector of active variable names as input and returns a corresponding...
std::vector< int > num_df_per_set
std::map< int, std::map< ElemType, ExodusII_IO_Helper::Conversion > > conversion_map
Associates libMesh ElemTypes with node/face/edge/etc.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
std::vector< int > node_sets_dist_index
int get_shellface_map(int i) const
std::vector< int > elemset_id_list
void build_shellface_boundary_ids(std::vector< boundary_id_type > &b_ids) const
Builds the list of unique shellface boundary ids.
int num_elem_all_sidesets
virtual void write_nodal_coordinates(const MeshBase &mesh, bool use_discontinuous=false)
Writes the nodal coordinates contained in "mesh".
std::vector< int > num_elem_df_per_set
static int get_exodus_version()
void write_var_names_impl(const char *var_type, int &count, const std::vector< std::string > &names)
write_var_names() dispatches to this function.
std::vector< std::vector< long unsigned int > > bex_cv_conn
int get_side_map(int i) const
void add_edge(const dof_id_type elem, const unsigned short int edge, const boundary_id_type id)
Add edge edge of element number elem with boundary id id to the boundary information data structure...
static bool redundant_added_side(const Elem &elem, unsigned int side)
std::vector< std::vector< std::vector< Real > > > bex_dense_constraint_vecs
bool _nodal_vars_initialized