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> 67 const std::vector<int> trishell3_inverse_edge_map = {3, 4, 5};
68 const std::vector<int> quadshell4_inverse_edge_map = {3, 4, 5, 6};
74 const std::vector<int> hex27_node_map = {
76 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
78 21, 25, 24, 26, 23, 22, 20};
81 const std::vector<int> hex27_inverse_node_map = {
83 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
85 26, 20, 25, 24, 22, 21, 23};
88 const std::vector<int> prism20_node_map = {
92 6, 7, 8, 9, 10, 11, 12, 13, 14,
97 const std::vector<int> prism20_inverse_node_map = {
101 6, 7, 8, 9, 10, 11, 12, 13, 14,
106 const std::vector<int> prism21_node_map = {
110 6, 7, 8, 9, 10, 11, 12, 13, 14,
112 20, 18, 19, 16, 17, 15};
115 const std::vector<int> prism21_inverse_node_map = {
119 6, 7, 8, 9, 10, 11, 12, 13, 14,
121 20, 18, 19, 16, 17, 15};
124 const std::vector<int> tet14_node_map = {
126 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
131 const std::vector<int> tet14_inverse_node_map = {
133 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
140 const std::vector<int> tet_face_map = {1, 2, 3, 0};
141 const std::vector<int> hex_face_map = {1, 2, 3, 4, 0, 5};
142 const std::vector<int> prism_face_map = {1, 2, 3, 0, 4};
145 const std::vector<int> tet_inverse_face_map = {4, 1, 2, 3};
146 const std::vector<int> hex_inverse_face_map = {5, 1, 2, 3, 4, 6};
147 const std::vector<int> prism_inverse_face_map = {4, 1, 2, 3, 5};
168 float ret_float = 0.;
176 EX_CHECK_ERR(e2h.
ex_err, error_msg);
183 inline bool is_bezier_elem(
const char * elem_type_str)
186 #if EX_API_VERS_NODOT < 800 190 if (strlen(elem_type_str) <= 4)
192 return (std::string(elem_type_str, elem_type_str+4) ==
"BEX_");
197 std::map<subdomain_id_type, std::vector<unsigned int>>
200 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
206 std::set<subdomain_id_type> sbd_ids;
208 if (!sbd_ids.empty())
209 subdomain_id_end = *sbd_ids.rbegin()+1;
213 for (
const auto & elem :
mesh.active_element_ptr_range())
218 if (elem->infinite())
221 subdomain_map[ elem->subdomain_id() ].push_back(elem->id());
228 for (
auto s : elem->side_index_range())
234 subdomain_map[subdomain_id_end + elem->side_type(s)];
242 if (!add_sides && !subdomain_map.empty())
243 subdomain_id_end = subdomain_map.rbegin()->first + 1;
245 return subdomain_map;
259 bool run_only_on_proc0,
260 bool single_precision) :
265 title(header_info.title),
266 num_dim(header_info.num_dim),
267 num_nodes(header_info.num_nodes),
268 num_elem(header_info.num_elem),
269 num_elem_blk(header_info.num_elem_blk),
270 num_edge(header_info.num_edge),
271 num_edge_blk(header_info.num_edge_blk),
272 num_node_sets(header_info.num_node_sets),
273 num_side_sets(header_info.num_side_sets),
274 num_elem_sets(header_info.num_elem_sets),
279 num_elem_this_blk(0),
280 num_nodes_per_elem(0),
282 num_elem_all_sidesets(0),
283 num_elem_all_elemsets(0),
289 opened_for_writing(false),
290 opened_for_reading(false),
291 _run_only_on_proc0(run_only_on_proc0),
292 _opened_by_create(false),
293 _elem_vars_initialized(false),
294 _global_vars_initialized(false),
295 _nodal_vars_initialized(false),
296 _use_mesh_dimension_instead_of_spatial_dimension(false),
299 _write_as_dimension(0),
300 _single_precision(single_precision)
302 title.resize(MAX_LINE_LENGTH+1);
316 return EX_API_VERS_NODOT;
324 auto convert_type = [
this](
ElemType type,
325 std::string_view exodus_type,
326 const std::vector<int> * node_map =
nullptr,
327 const std::vector<int> * inverse_node_map =
nullptr,
328 const std::vector<int> * side_map =
nullptr,
329 const std::vector<int> * inverse_side_map =
nullptr,
330 const std::vector<int> * shellface_map =
nullptr,
331 const std::vector<int> * inverse_shellface_map =
nullptr,
332 size_t shellface_index_offset = 0)
336 conv.libmesh_type = type;
337 conv.exodus_type = exodus_type;
338 conv.node_map = node_map;
339 conv.inverse_node_map = inverse_node_map;
340 conv.side_map = side_map;
341 conv.inverse_side_map = inverse_side_map;
342 conv.shellface_map = shellface_map;
343 conv.inverse_shellface_map = inverse_shellface_map;
344 conv.shellface_index_offset = shellface_index_offset;
345 conv.n_nodes = elem->n_nodes();
346 for (
int d = elem->dim()+1; d <= 3; ++d)
351 convert_type(
EDGE2,
"EDGE2");
352 convert_type(
EDGE3,
"EDGE3");
353 convert_type(
EDGE4,
"EDGE4");
354 convert_type(
QUAD4,
"QUAD4");
355 convert_type(
QUAD8,
"QUAD8");
356 convert_type(
QUAD9,
"QUAD9");
357 convert_type(
QUADSHELL4,
"SHELL4",
nullptr,
nullptr,
nullptr,
358 &quadshell4_inverse_edge_map,
359 nullptr,
nullptr, 2);
360 convert_type(
QUADSHELL8,
"SHELL8",
nullptr,
nullptr,
nullptr,
361 &quadshell4_inverse_edge_map,
362 nullptr,
nullptr, 2);
363 convert_type(
QUADSHELL9,
"SHELL9",
nullptr,
nullptr,
nullptr,
364 &quadshell4_inverse_edge_map,
365 nullptr,
nullptr, 2);
367 convert_type(
TRI3,
"TRI3");
368 convert_type(
TRI6,
"TRI6");
369 convert_type(
TRI7,
"TRI7");
379 convert_type(
TRISHELL3,
"TRISHELL3",
nullptr,
nullptr,
nullptr,
380 &trishell3_inverse_edge_map,
381 nullptr,
nullptr, 2);
383 convert_type(
HEX8,
"HEX8",
nullptr,
nullptr,
384 &hex_face_map, &hex_inverse_face_map);
385 convert_type(
HEX20,
"HEX20",
nullptr,
nullptr,
386 &hex_face_map, &hex_inverse_face_map);
387 convert_type(
HEX27,
"HEX27", &hex27_node_map,
388 &hex27_inverse_node_map,
389 &hex_face_map, &hex_inverse_face_map);
390 convert_type(
TET4,
"TETRA4",
nullptr,
nullptr,
391 &tet_face_map, &tet_inverse_face_map);
392 convert_type(
TET10,
"TETRA10",
nullptr,
nullptr,
393 &tet_face_map, &tet_inverse_face_map);
394 convert_type(
TET14,
"TETRA14", &tet14_node_map,
395 &tet14_inverse_node_map,
396 &tet_face_map, &tet_inverse_face_map);
397 convert_type(
PRISM6,
"WEDGE",
nullptr,
nullptr,
398 &prism_face_map, &prism_inverse_face_map);
399 convert_type(
PRISM15,
"WEDGE15",
nullptr,
nullptr,
400 &prism_face_map, &prism_inverse_face_map);
401 convert_type(
PRISM18,
"WEDGE18",
nullptr,
nullptr,
402 &prism_face_map, &prism_inverse_face_map);
403 convert_type(
PRISM20,
"WEDGE20", &prism20_node_map,
404 &prism20_inverse_node_map,
405 &prism_face_map, &prism_inverse_face_map);
406 convert_type(
PRISM21,
"WEDGE21", &prism21_node_map,
407 &prism21_inverse_node_map,
408 &prism_face_map, &prism_inverse_face_map);
545 return libmesh_map_find(maps_for_dim, type);
552 std::transform(type_str.begin(), type_str.end(), type_str.begin(), ::toupper);
578 bool single_precision_in)
579 : our_data(our_data_in),
580 single_precision(single_precision_in)
584 if (
sizeof(
Real) !=
sizeof(
float))
593 else if (
sizeof(
Real) !=
sizeof(double))
605 if (single_precision)
607 if (
sizeof(
Real) !=
sizeof(
float))
608 return static_cast<void*
>(float_vec.data());
611 else if (
sizeof(
Real) !=
sizeof(double))
612 return static_cast<void*
>(double_vec.data());
615 return const_cast<void *
>(
static_cast<const void *
>(our_data.data()));
620 bool single_precision_in)
621 : our_data(our_data_in),
622 single_precision(single_precision_in)
627 if (
sizeof(
Real) !=
sizeof(
float))
630 else if (
sizeof(
Real) !=
sizeof(double))
637 if (single_precision)
639 if (
sizeof(
Real) !=
sizeof(
float))
640 our_data.assign(float_vec.begin(), float_vec.end());
642 else if (
sizeof(
Real) !=
sizeof(double))
643 our_data.assign(double_vec.begin(), double_vec.end());
649 if (single_precision)
651 if (
sizeof(
Real) !=
sizeof(
float))
652 return static_cast<void*
>(float_vec.data());
655 else if (
sizeof(
Real) !=
sizeof(double))
656 return static_cast<void*
>(double_vec.data());
659 return static_cast<void *
>(our_data.data());
665 float ex_version = 0.;
670 comp_ws = cast_int<int>(
sizeof(float));
675 comp_ws = cast_int<int>(std::min(
sizeof(
Real),
sizeof(
double)));
684 ex_id = exII::ex_open(filename,
685 read_only ? EX_READ : EX_WRITE,
691 std::string err_msg = std::string(
"Error opening ExodusII mesh file: ") + std::string(filename);
692 EX_CHECK_ERR(
ex_id, err_msg);
713 exII::ex_init_params params = {};
714 int err_flag = exII::ex_get_init_ext(
ex_id, ¶ms);
715 EX_CHECK_ERR(err_flag,
"Error retrieving header info.");
719 h.
title.assign(params.title, params.title + MAX_LINE_LENGTH);
747 EX_CHECK_ERR(
ex_err,
"Error reading number of nodal variables.");
750 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
753 EX_CHECK_ERR(
ex_err,
"Error reading number of global variables.");
756 EX_CHECK_ERR(
ex_err,
"Error reading number of sideset variables.");
759 EX_CHECK_ERR(
ex_err,
"Error reading number of nodeset variables.");
762 EX_CHECK_ERR(
ex_err,
"Error reading number of elemset variables.");
764 message(
"Exodus header info retrieved successfully.");
774 inquire(*
this, exII::EX_INQ_QA,
"Error retrieving number of QA records");
779 <<
" QA record(s) in the Exodus file." 788 std::vector<std::vector<std::vector<char>>> qa_storage(num_qa_rec);
791 qa_storage[i].resize(4);
793 qa_storage[i][j].resize(MAX_STR_LENGTH+1);
797 typedef char * inner_array_t[4];
804 auto qa_record = std::make_unique<inner_array_t[]>(num_qa_rec);
810 qa_record[i][j] = qa_storage[i][j].data();
813 EX_CHECK_ERR(
ex_err,
"Error reading the QA records.");
835 <<
"Mesh Dimension: \t" <<
num_dim << std::endl
836 <<
"Number of Nodes: \t" <<
num_nodes << std::endl
837 <<
"Number of elements: \t" <<
num_elem << std::endl
838 <<
"Number of elt blocks: \t" <<
num_elem_blk << std::endl
848 LOG_SCOPE(
"read_nodes()",
"ExodusII_IO_Helper");
856 ex_err = exII::ex_get_coord
862 EX_CHECK_ERR(
ex_err,
"Error retrieving nodal data.");
863 message(
"Nodal data retrieved successfully.");
868 int n_nodal_attr = 0;
869 ex_err = exII::ex_get_attr_param(
ex_id, exII::EX_NODAL, 0, & n_nodal_attr);
870 EX_CHECK_ERR(
ex_err,
"Error getting number of nodal attributes.");
872 if (n_nodal_attr > 0)
874 std::vector<std::vector<char>> attr_name_data
875 (n_nodal_attr, std::vector<char>(MAX_STR_LENGTH + 1));
876 std::vector<char *> attr_names(n_nodal_attr);
878 attr_names[i] = attr_name_data[i].data();
880 ex_err = exII::ex_get_attr_names(
ex_id, exII::EX_NODAL, 0, attr_names.data());
881 EX_CHECK_ERR(
ex_err,
"Error getting nodal attribute names.");
884 if (std::string(
"bex_weight") == attr_names[i])
888 exII::ex_get_one_attr (
ex_id, exII::EX_NODAL, 0, i+1,
890 EX_CHECK_ERR(
ex_err,
"Error getting Bezier Extraction nodal weights");
905 ex_err = exII::ex_get_node_num_map
908 EX_CHECK_ERR(
ex_err,
"Error retrieving nodal number map.");
909 message(
"Nodal numbering map retrieved successfully.");
914 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_nodes-1)); ++i)
927 #if EX_API_VERS_NODOT >= 800 928 int n_blobs = exII::ex_inquire_int(
ex_id, exII::EX_INQ_BLOB);
932 std::vector<exII::ex_blob> blobs(n_blobs);
933 std::vector<std::vector<char>> blob_names(n_blobs);
936 blob_names[i].resize(MAX_STR_LENGTH+1);
937 blobs[i].name = blob_names[i].data();
941 EX_CHECK_ERR(
ex_err,
"Error getting blobs.");
943 bool found_blob =
false;
944 const exII::ex_blob * my_blob = &blobs[0];
945 for (
const auto & blob : blobs)
947 if (std::string(
"bex_cv_blob") == blob.name)
955 libmesh_error_msg(
"Found no bex_cv_blob for bezier elements");
957 const int n_blob_attr =
958 exII::ex_get_attribute_count(
ex_id, exII::EX_BLOB,
961 std::vector<exII::ex_attribute> attributes(n_blob_attr);
962 ex_err = exII::ex_get_attribute_param(
ex_id, exII::EX_BLOB,
965 EX_CHECK_ERR(
ex_err,
"Error getting bex blob attribute parameters.");
967 int bex_num_dense_cv_blocks = 0;
968 std::vector<int> bex_dense_cv_info;
969 for (
auto & attr : attributes)
971 if (std::string(
"bex_dense_cv_info") == attr.name)
973 const std::size_t value_count = attr.value_count;
975 libmesh_error_msg(
"Found odd number of bex_dense_cv_info");
977 bex_dense_cv_info.resize(value_count);
978 attr.values = bex_dense_cv_info.data();
979 exII::ex_get_attribute(
ex_id, &attr);
981 bex_num_dense_cv_blocks = value_count / 2;
983 libmesh_error_msg_if(bex_num_dense_cv_blocks > 1,
984 "Found more than 1 dense bex CV block; unsure how to handle that");
988 if (bex_dense_cv_info.empty())
989 libmesh_error_msg(
"No bex_dense_cv_info found");
992 exII::ex_get_variable_param(
ex_id, exII::EX_BLOB, &n_blob_vars);
993 std::vector<char> var_name (MAX_STR_LENGTH + 1);
996 ex_err = exII::ex_get_variable_name(
ex_id, exII::EX_BLOB, v_id, var_name.data());
997 EX_CHECK_ERR(
ex_err,
"Error reading bex blob var name.");
999 if (std::string(
"bex_dense_cv_blocks") == var_name.data())
1001 std::vector<double> bex_dense_cv_blocks(my_blob->num_entry);
1003 ex_err = exII::ex_get_var(
ex_id, 1, exII::EX_BLOB, v_id,
1004 my_blob->id, my_blob->num_entry,
1005 bex_dense_cv_blocks.data());
1006 EX_CHECK_ERR(
ex_err,
"Error reading bex_dense_cv_blocks.");
1011 std::size_t offset = 0;
1017 const int vecsize = bex_dense_cv_info[2*i+1];
1018 vec.resize(vecsize);
1019 std::copy(&bex_dense_cv_blocks[offset],
1020 &bex_dense_cv_blocks[offset+vecsize],
1028 #endif // EX_API_VERS_NODOT >= 800 1035 out_stream <<
"(" <<
x[i] <<
", " <<
y[i] <<
", " <<
z[i] <<
")" << std::endl;
1047 exII::EX_ELEM_BLOCK,
1050 EX_CHECK_ERR(
ex_err,
"Error getting block IDs.");
1051 message(
"All block IDs retrieved successfully.");
1053 char name_buffer[MAX_STR_LENGTH+1];
1056 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_BLOCK,
1058 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
1061 message(
"All block names retrieved successfully.");
1069 exII::EX_EDGE_BLOCK,
1072 EX_CHECK_ERR(
ex_err,
"Error getting edge block IDs.");
1073 message(
"All edge block IDs retrieved successfully.");
1076 char name_buffer[MAX_STR_LENGTH+1];
1079 ex_err = exII::ex_get_name(
ex_id, exII::EX_EDGE_BLOCK,
1081 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
1084 message(
"All edge block names retrieved successfully.");
1092 libmesh_assert_less (index,
block_ids.size());
1101 libmesh_assert_less (index,
block_ids.size());
1110 libmesh_assert_less (index,
ss_ids.size());
1119 libmesh_assert_less (index,
ss_ids.size());
1147 LOG_SCOPE(
"read_elem_in_block()",
"ExodusII_IO_Helper");
1149 libmesh_assert_less (block,
block_ids.size());
1152 int num_edges_per_elem = 0;
1153 int num_faces_per_elem = 0;
1154 int num_node_data_per_elem = 0;
1156 exII::EX_ELEM_BLOCK,
1160 &num_node_data_per_elem,
1161 &num_edges_per_elem,
1162 &num_faces_per_elem,
1165 EX_CHECK_ERR(
ex_err,
"Error getting block info.");
1166 message(
"Info retrieved successfully for block: ", block);
1171 if (!(num_edges_per_elem == 0) && !(num_edges_per_elem == -1))
1172 libmesh_warning(
"Exodus files with extended edge connectivity not currently supported.");
1173 if (!(num_faces_per_elem == 0) && !(num_faces_per_elem == -1))
1174 libmesh_warning(
"Exodus files with extended face connectivity not currently supported.");
1179 const bool is_bezier = is_bezier_elem(
elem_type.data());
1192 <<
" nodes per element." << std::endl;
1202 exII::EX_ELEM_BLOCK,
1208 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
1209 message(
"Connectivity retrieved successfully for block: ", block);
1217 #if EX_API_VERS_NODOT >= 800 1218 int real_n_attr = exII::ex_get_attribute_count(
ex_id, exII::EX_ELEM_BLOCK,
block_ids[block]);
1219 EX_CHECK_ERR(real_n_attr,
"Error getting number of element block attributes.");
1221 if (real_n_attr > 0)
1223 std::vector<exII::ex_attribute> attributes(real_n_attr);
1225 ex_err = exII::ex_get_attribute_param(
ex_id, exII::EX_ELEM_BLOCK,
block_ids[block], attributes.data());
1226 EX_CHECK_ERR(
ex_err,
"Error getting element block attribute parameters.");
1228 ex_err = exII::ex_get_attributes(
ex_id, real_n_attr, attributes.data());
1229 EX_CHECK_ERR(
ex_err,
"Error getting element block attribute values.");
1231 for (
auto attr : attributes)
1233 if (std::string(
"bex_elem_degrees") == attr.name)
1235 if (attr.type != exII::EX_INTEGER)
1236 libmesh_error_msg(
"Found non-integer bex_elem_degrees");
1238 if (attr.value_count > 3)
1239 libmesh_error_msg(
"Looking for at most 3 bex_elem_degrees; found " << attr.value_count);
1243 std::vector<int> bex_elem_degrees(3);
1245 const int * as_int =
static_cast<int *
>(attr.values);
1246 std::copy(as_int, as_int+attr.value_count, bex_elem_degrees.begin());
1256 libmesh_assert_equal_to(bex_elem_degrees[d], 2);
1282 auto src = old_connect.data();
1298 #endif // EX_API_VERS_NODOT >= 800 1305 LOG_SCOPE(
"read_edge_blocks()",
"ExodusII_IO_Helper");
1321 typedef std::pair<dof_id_type, unsigned int> ElemEdgePair;
1322 std::unordered_map<dof_id_type, std::vector<ElemEdgePair>> edge_map;
1323 std::unique_ptr<Elem> edge_ptr;
1324 for (
const auto & elem :
mesh.element_ptr_range())
1325 for (
auto e : elem->edge_index_range())
1327 elem->build_edge_ptr(edge_ptr, e);
1331 auto & vec = edge_map[edge_key];
1332 vec.emplace_back(elem->id(), e);
1339 if (edge_ptr->default_order() !=
FIRST)
1342 auto low_order_edge =
1346 for (
unsigned int v=0; v<edge_ptr->n_vertices(); ++v)
1347 low_order_edge->set_node(v, edge_ptr->node_ptr(v));
1350 dof_id_type low_order_edge_key = low_order_edge->key();
1354 auto & low_order_vec = edge_map[low_order_edge_key];
1355 low_order_vec.emplace_back(elem->id(), e);
1368 int num_edge_this_blk = 0;
1369 int num_nodes_per_edge = 0;
1370 int num_edges_per_edge = 0;
1371 int num_faces_per_edge = 0;
1372 int num_attr_per_edge = 0;
1374 exII::EX_EDGE_BLOCK,
1378 &num_nodes_per_edge,
1379 &num_edges_per_edge,
1380 &num_faces_per_edge,
1381 &num_attr_per_edge);
1383 EX_CHECK_ERR(
ex_err,
"Error getting edge block info.");
1384 message(
"Info retrieved successfully for block: ", edge_block_id);
1389 connect.resize(num_nodes_per_edge * num_edge_this_blk);
1394 exII::EX_EDGE_BLOCK,
1400 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
1401 message(
"Connectivity retrieved successfully for block: ", edge_block_id);
1410 for (
unsigned int i=0, sz=
connect.size(); i<sz; i+=num_nodes_per_edge)
1412 auto edge =
Elem::build(conv.libmesh_elem_type());
1413 for (
int n=0; n<num_nodes_per_edge; ++n)
1415 int exodus_node_id =
connect[i+n];
1416 int exodus_node_id_zero_based = exodus_node_id - 1;
1417 int libmesh_node_id =
node_num_map[exodus_node_id_zero_based] - 1;
1428 auto & elem_edge_pair_vec =
1429 libmesh_map_find(edge_map, edge_key);
1431 for (
const auto & elem_edge_pair : elem_edge_pair_vec)
1443 build_edge_ptr(edge_ptr, elem_edge_pair.second);
1452 ((edge_ptr->node_id(0) == edge->node_id(0)) && (edge_ptr->node_id(1) == edge->node_id(1))) ||
1453 ((edge_ptr->node_id(0) == edge->node_id(1)) && (edge_ptr->node_id(1) == edge->node_id(0)));
1459 elem_edge_pair.second,
1481 ex_err = exII::ex_get_elem_num_map
1484 EX_CHECK_ERR(
ex_err,
"Error retrieving element number map.");
1485 message(
"Element numbering map retrieved successfully.");
1498 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_elem-1)); ++i)
1514 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset information.");
1515 message(
"All sideset information retrieved successfully.");
1522 num_elem_all_sidesets = inquire(*
this, exII::EX_INQ_SS_ELEM_LEN,
"Error retrieving length of the concatenated side sets element list!");
1529 char name_buffer[MAX_STR_LENGTH+1];
1532 ex_err = exII::ex_get_name(
ex_id, exII::EX_SIDE_SET,
1534 EX_CHECK_ERR(
ex_err,
"Error getting side set name.");
1537 message(
"All side set names retrieved successfully.");
1549 EX_CHECK_ERR(
ex_err,
"Error retrieving nodeset information.");
1550 message(
"All nodeset information retrieved successfully.");
1557 char name_buffer[MAX_STR_LENGTH+1];
1560 ex_err = exII::ex_get_name(
ex_id, exII::EX_NODE_SET,
1562 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1565 message(
"All node set names retrieved successfully.");
1578 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset information.");
1579 message(
"All elemset information retrieved successfully.");
1587 inquire(*
this, exII::EX_INQ_ELS_LEN,
1588 "Error retrieving length of the concatenated elem sets element list!");
1597 char name_buffer[MAX_STR_LENGTH+1];
1600 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_SET,
1602 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1605 message(
"All elem set names retrieved successfully.");
1612 LOG_SCOPE(
"read_sideset()",
"ExodusII_IO_Helper");
1614 libmesh_assert_less (
id,
ss_ids.size());
1617 libmesh_assert_less_equal (offset,
elem_list.size());
1618 libmesh_assert_less_equal (offset,
side_list.size());
1625 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset parameters.");
1626 message(
"Parameters retrieved successfully for sideset: ",
id);
1632 if (static_cast<unsigned int>(offset) ==
elem_list.size() ||
1633 static_cast<unsigned int>(offset) ==
side_list.size() )
1647 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset data.");
1648 message(
"Data retrieved successfully for sideset: ",
id);
1659 LOG_SCOPE(
"read_elemset()",
"ExodusII_IO_Helper");
1664 libmesh_assert_less_equal (offset,
elemset_list.size());
1671 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset parameters.");
1672 message(
"Parameters retrieved successfully for elemset: ",
id);
1678 if (static_cast<unsigned int>(offset) ==
elemset_list.size())
1691 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset data.");
1692 message(
"Data retrieved successfully for elemset: ",
id);
1704 LOG_SCOPE(
"read_all_nodesets()",
"ExodusII_IO_Helper");
1710 (*
this, exII::EX_INQ_NODE_SETS,
1711 "Error retrieving number of node sets");
1714 int total_nodes_in_all_sets =
1716 (*
this, exII::EX_INQ_NS_NODE_LEN,
1717 "Error retrieving number of nodes in all node sets.");
1720 int total_df_in_all_sets =
1722 (*
this, exII::EX_INQ_NS_DF_LEN,
1723 "Error retrieving number of distribution factors in all node sets.");
1743 exII::ex_set_specs set_specs = {};
1750 set_specs.sets_extra_list =
nullptr;
1751 set_specs.sets_dist_fact = total_df_in_all_sets ? mapped_node_sets_dist_fact.
data() :
nullptr;
1753 ex_err = exII::ex_get_concat_sets(
ex_id, exII::EX_NODE_SET, &set_specs);
1754 EX_CHECK_ERR(
ex_err,
"Error reading concatenated nodesets");
1757 char name_buffer[MAX_STR_LENGTH+1];
1760 ex_err = exII::ex_get_name
1765 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1796 message(
"Error closing Exodus file.");
1798 message(
"Exodus file closed successfully.");
1819 ex_err = exII::ex_get_all_times
1822 EX_CHECK_ERR(
ex_err,
"Error reading timesteps!");
1831 inquire(*
this, exII::EX_INQ_TIME,
"Error retrieving number of time steps");
1838 LOG_SCOPE(
"read_nodal_var_values()",
"ExodusII_IO_Helper");
1844 unsigned int var_index = 0;
1861 libmesh_error_msg(
"Unable to locate variable named: " << nodal_var_name);
1867 std::vector<Real> unmapped_nodal_var_values(
num_nodes);
1870 ex_err = exII::ex_get_var
1878 EX_CHECK_ERR(
ex_err,
"Error reading nodal variable values!");
1880 for (
unsigned i=0; i<static_cast<unsigned>(
num_nodes); i++)
1886 const unsigned mapped_node_id = this->
node_num_map[i] - 1;
1888 libmesh_assert_less(i, unmapped_nodal_var_values.size());
1920 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
1928 std::vector<std::string> & result)
1931 ex_err = exII::ex_get_var_param(
ex_id, var_type, &count);
1932 EX_CHECK_ERR(
ex_err,
"Error reading number of variables.");
1939 NamesData names_table(count, MAX_STR_LENGTH);
1946 EX_CHECK_ERR(
ex_err,
"Error reading variable names!");
1950 libMesh::out <<
"Read the variable(s) from the file:" << std::endl;
1951 for (
int i=0; i<count; i++)
1956 result.resize(count);
1959 for (
int i=0; i<count; i++)
1968 const std::vector<std::string> & names)
2000 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
2009 const std::vector<std::string> & names)
2012 count = cast_int<int>(names.size());
2015 ex_err = exII::ex_put_var_param(
ex_id, var_type, count);
2016 EX_CHECK_ERR(
ex_err,
"Error setting number of vars.");
2025 NamesData names_table(count, MAX_STR_LENGTH);
2028 for (
int i=0; i != count; ++i)
2030 if(names[i].length() > MAX_STR_LENGTH)
2032 "*** Warning, Exodus variable name \"" 2033 << names[i] <<
"\" too long (max " << MAX_STR_LENGTH
2034 <<
" characters). Name will be truncated. ");
2040 libMesh::out <<
"Writing variable name(s) to file: " << std::endl;
2041 for (
int i=0; i != count; ++i)
2051 EX_CHECK_ERR(
ex_err,
"Error writing variable names.");
2059 std::map<dof_id_type, Real> & elem_var_value_map)
2061 LOG_SCOPE(
"read_elemental_var_values()",
"ExodusII_IO_Helper");
2066 unsigned int var_index = 0;
2083 libmesh_error_msg(
"Unable to locate variable named: " << elemental_var_name);
2087 unsigned ex_el_num = 0;
2093 for (
unsigned i=0; i<static_cast<unsigned>(
num_elem_blk); i++)
2096 exII::EX_ELEM_BLOCK,
2104 EX_CHECK_ERR(
ex_err,
"Error getting number of elements in block.");
2117 ex_err = exII::ex_get_var
2120 exII::EX_ELEM_BLOCK,
2125 EX_CHECK_ERR(
ex_err,
"Error getting elemental values.");
2131 unsigned mapped_elem_id = this->
elem_num_map[ex_el_num] - 1;
2134 elem_var_value_map[mapped_elem_id] = block_elem_var_values[j];
2158 comp_ws = cast_int<int>(
sizeof(float));
2159 io_ws = cast_int<int>(
sizeof(float));
2165 comp_ws = cast_int<int>
2166 (std::min(
sizeof(
Real),
sizeof(
double)));
2167 io_ws = cast_int<int>
2168 (std::min(
sizeof(
Real),
sizeof(
double)));
2174 int mode = EX_CLOBBER;
2179 #ifdef LIBMESH_HAVE_HDF5 2183 mode |= EX_NOCLASSIC;
2189 ex_id = exII::ex_create(filename.c_str(), mode, &comp_ws, &io_ws);
2192 EX_CHECK_ERR(
ex_id,
"Error creating ExodusII/Nemesis mesh file.");
2195 libMesh::out <<
"File created successfully." << std::endl;
2210 libmesh_parallel_only(
mesh.
comm());
2218 auto subdomain_map = build_subdomain_map(
mesh,
_add_sides, subdomain_id_end);
2233 for (
const auto & elem :
mesh.active_local_element_ptr_range())
2235 for (
auto s : elem->side_index_range())
2241 num_local_side_nodes += elem->nodes_on_side(s).size();
2259 mesh.local_nodes_end()));
2264 const dof_id_type n_gaps = max_nn - n_total_nodes;
2265 const dof_id_type gaps_per_processor = n_gaps / n_proc;
2266 const dof_id_type remainder_gaps = n_gaps % n_proc;
2268 n_local_nodes = n_local_nodes +
2269 gaps_per_processor +
2289 if (!use_discontinuous)
2299 for (
const auto & elem :
mesh.active_element_ptr_range())
2303 std::set<boundary_id_type> unique_side_boundaries;
2304 std::vector<boundary_id_type> unique_node_boundaries;
2309 std::vector<boundary_id_type> side_boundaries;
2311 unique_side_boundaries.insert(side_boundaries.begin(), side_boundaries.end());
2315 std::vector<boundary_id_type> shellface_boundaries;
2317 unique_side_boundaries.insert(shellface_boundaries.begin(), shellface_boundaries.end());
2321 unique_side_boundaries.insert(pr.first);
2330 if (std::find(unique_node_boundaries.begin(),
2331 unique_node_boundaries.end(), id)
2332 == unique_node_boundaries.end())
2333 unique_node_boundaries.push_back(
id);
2336 num_side_sets = cast_int<int>(unique_side_boundaries.size());
2337 num_node_sets = cast_int<int>(unique_node_boundaries.size());
2341 if (str_title.size() > MAX_LINE_LENGTH)
2343 libMesh::err <<
"Warning, Exodus files cannot have titles longer than " 2345 <<
" characters. Your title will be truncated." 2347 str_title.resize(MAX_LINE_LENGTH);
2384 exII::ex_init_params params = {};
2385 params.title[str_title.copy(params.title, MAX_LINE_LENGTH)] =
'\0';
2397 EX_CHECK_ERR(
ex_err,
"Error initializing new Exodus file.");
2420 auto push_node = [
this](
const Point & p) {
2454 if (!use_discontinuous)
2456 for (
const auto & node_ptr :
mesh.node_ptr_range())
2458 const Node & node = *node_ptr;
2476 for (
const auto & elem :
mesh.active_element_ptr_range())
2477 for (
const Node & node : elem->node_ref_range())
2495 std::vector<std::vector<const Elem *>>
2498 for (
const auto & elem :
mesh.active_element_ptr_range())
2499 elems_by_pid[elem->processor_id()].push_back(elem);
2502 for (
const Elem * elem : elems_by_pid[p])
2503 for (
auto s : elem->side_index_range())
2508 const std::vector<unsigned int> side_nodes =
2509 elem->nodes_on_side(s);
2511 for (
auto n : side_nodes)
2512 push_node(elem->point(n));
2521 ex_err = exII::ex_put_coord
2527 EX_CHECK_ERR(
ex_err,
"Error writing coordinates to Exodus file.");
2533 EX_CHECK_ERR(
ex_err,
"Error writing node_num_map");
2541 LOG_SCOPE(
"write_elements()",
"ExodusII_IO_Helper");
2546 auto subdomain_map = build_subdomain_map(
mesh,
_add_sides, subdomain_id_end);
2555 std::vector<int> elem_blk_id;
2556 std::vector<int> num_elem_this_blk_vec;
2557 std::vector<int> num_nodes_per_elem_vec;
2558 std::vector<int> num_edges_per_elem_vec;
2559 std::vector<int> num_faces_per_elem_vec;
2560 std::vector<int> num_attr_vec;
2572 unsigned int counter = 0;
2573 for (
auto & [subdomain_id, element_id_vec] : subdomain_map)
2577 const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
2578 ElemType(subdomain_id - subdomain_id_end) :
2581 if (subdomain_id >= subdomain_id_end)
2585 num_elem_this_blk_vec.push_back
2586 (cast_int<int>(element_id_vec[0]));
2588 (Utility::enum_to_string<ElemType>(elem_t));
2593 num_elem_this_blk_vec.push_back
2594 (cast_int<int>(element_id_vec.size()));
2599 num_elem += num_elem_this_blk_vec.back();
2607 libmesh_not_implemented_msg(
"Support for Polygons/Polyhedra not yet implemented");
2609 elem_blk_id.push_back(subdomain_id);
2612 num_attr_vec.push_back(0);
2613 num_edges_per_elem_vec.push_back(0);
2614 num_faces_per_elem_vec.push_back(0);
2619 std::vector<int>::iterator curr_elem_map_end =
elem_num_map.begin();
2627 std::map<std::pair<dof_id_type, unsigned int>,
dof_id_type> discontinuous_node_indices;
2629 if (use_discontinuous)
2631 for (
const auto & elem :
mesh.active_element_ptr_range())
2632 for (
auto n : elem->node_index_range())
2633 discontinuous_node_indices[std::make_pair(elem->id(),n)] =
2641 for (
const Elem * elem :
mesh.active_element_ptr_range())
2645 unsigned int local_node_index = elem->n_nodes();
2647 for (
auto s : elem->side_index_range())
2652 const std::vector<unsigned int> side_nodes =
2653 elem->nodes_on_side(s);
2658 discontinuous_node_indices
2659 [std::make_pair(elem->id(),local_node_index++)] =
2670 std::vector<BoundaryInfo::BCTuple> edge_tuples = bi.
build_edge_list();
2678 std::map<boundary_id_type, std::vector<int>> edge_id_to_conn;
2679 std::map<boundary_id_type, std::pair<ElemType, unsigned int>> edge_id_to_elem_type;
2681 std::unique_ptr<const Elem> edge;
2682 for (
const auto & t : edge_tuples)
2685 unsigned int edge_id = std::get<1>(t);
2693 if (
const auto check_it = edge_id_to_elem_type.find(b_id);
2694 check_it == edge_id_to_elem_type.end())
2697 edge_id_to_elem_type[b_id] = std::make_pair(edge->type(), edge->n_nodes());
2702 const auto & val_pair = check_it->second;
2703 libmesh_error_msg_if(val_pair.first != edge->type() || val_pair.second != edge->n_nodes(),
2704 "All edges in a block must have same geometric type.");
2708 auto & conn = edge_id_to_conn[b_id];
2714 for (
auto n : edge->node_index_range())
2718 int exodus_node_id = -1;
2720 if (!use_discontinuous)
2722 dof_id_type libmesh_node_id = edge->node_ptr(n)->id();
2723 exodus_node_id = libmesh_map_find
2732 exodus_node_id = libmesh_map_find
2733 (discontinuous_node_indices, std::make_pair(elem_id, pn));
2736 conn.push_back(exodus_node_id);
2746 std::vector<int> edge_blk_id;
2748 std::vector<int> num_edge_this_blk_vec;
2749 std::vector<int> num_nodes_per_edge_vec;
2750 std::vector<int> num_attr_edge_vec;
2757 for (
const auto & pr : edge_id_to_conn)
2761 edge_blk_id.push_back(
id);
2764 const auto & elem_type_node_count = edge_id_to_elem_type[id];
2767 num_nodes_per_edge_vec.push_back(elem_type_node_count.second);
2771 num_edge_this_blk_vec.push_back(pr.second.size() / elem_type_node_count.second);
2774 num_attr_edge_vec.push_back(0);
2791 exII::ex_block_params params = {};
2794 params.elem_blk_id = elem_blk_id.data();
2796 params.num_elem_this_blk = num_elem_this_blk_vec.data();
2797 params.num_nodes_per_elem = num_nodes_per_elem_vec.data();
2798 params.num_edges_per_elem = num_edges_per_elem_vec.data();
2799 params.num_faces_per_elem = num_faces_per_elem_vec.data();
2800 params.num_attr_elem = num_attr_vec.data();
2801 params.define_maps = 0;
2806 params.edge_blk_id = edge_blk_id.data();
2808 params.num_edge_this_blk = num_edge_this_blk_vec.data();
2809 params.num_nodes_per_edge = num_nodes_per_edge_vec.data();
2810 params.num_attr_edge = num_attr_edge_vec.data();
2813 ex_err = exII::ex_put_concat_all_blocks(
ex_id, ¶ms);
2814 EX_CHECK_ERR(
ex_err,
"Error writing element blocks.");
2817 unsigned libmesh_elem_num_to_exodus_counter = 0;
2821 auto num_elem_this_blk_it = num_elem_this_blk_vec.begin();
2824 for (
auto & [subdomain_id, element_id_vec] : subdomain_map)
2830 const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
2831 ElemType(subdomain_id - subdomain_id_end) :
2837 libmesh_not_implemented_msg(
"Support for Polygons/Polyhedra not yet implemented");
2841 if (subdomain_id < subdomain_id_end)
2847 unsigned int elem_id = element_id_vec[i];
2862 libmesh_error_msg_if(elem.
type() != conv.libmesh_elem_type(),
2863 "Error: Exodus requires all elements with a given subdomain ID to be the same type.\n" 2864 <<
"Can't write both " 2868 <<
" in the same block!");
2873 unsigned elem_node_index = conv.get_inverse_node_map(j);
2874 if (!use_discontinuous)
2884 cast_int<int>(libmesh_node_id));
2890 libmesh_map_find(discontinuous_node_indices,
2891 std::make_pair(elem_id, elem_node_index));
2901 curr_elem_map_end = std::transform
2902 (element_id_vec.begin(),
2903 element_id_vec.end(),
2913 libmesh_assert(num_elem_this_blk_it != num_elem_this_blk_vec.end());
2918 std::size_t connect_index = 0;
2919 for (
const auto & elem :
mesh.active_element_ptr_range())
2921 unsigned int local_node_index = elem->n_nodes();
2923 for (
auto s : elem->side_index_range())
2928 if (elem->side_type(s) != elem_t)
2931 const std::vector<unsigned int> side_nodes =
2932 elem->nodes_on_side(s);
2937 const int exodus_node_id = libmesh_map_find
2938 (discontinuous_node_indices,
2939 std::make_pair(elem->id(), local_node_index++));
2940 libmesh_assert_less(connect_index,
connect.size());
2941 connect[connect_index++] = exodus_node_id;
2946 auto old_curr_map_end = curr_elem_map_end;
2950 (old_curr_map_end, curr_elem_map_end,
2951 [&next_fake_id](){
return next_fake_id++;});
2954 ++num_elem_this_blk_it;
2956 ex_err = exII::ex_put_conn
2958 exII::EX_ELEM_BLOCK,
2963 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
2968 EX_CHECK_ERR(
ex_err,
"Error writing element map");
2974 EX_CHECK_ERR(
ex_err,
"Error writing element block names");
2978 for (
const auto & pr : edge_id_to_conn)
2980 ex_err = exII::ex_put_conn
2982 exII::EX_EDGE_BLOCK,
2987 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
2993 ex_err = exII::ex_put_names
2995 exII::EX_EDGE_BLOCK,
2997 EX_CHECK_ERR(
ex_err,
"Error writing edge block names");
3006 LOG_SCOPE(
"write_sidesets()",
"ExodusII_IO_Helper");
3012 std::map<int, std::vector<int>> elem_lists;
3013 std::map<int, std::vector<int>> side_lists;
3014 std::set<boundary_id_type> side_boundary_ids;
3021 std::vector<const Elem *> family;
3022 #ifdef LIBMESH_ENABLE_AMR 3032 for (
const auto & f : family)
3039 side_lists[std::get<2>(t)].push_back(conv.get_inverse_side_map(std::get<1>(t)));
3043 std::vector<boundary_id_type> tmp;
3045 side_boundary_ids.insert(tmp.begin(), tmp.end());
3054 std::vector<const Elem *> family;
3055 #ifdef LIBMESH_ENABLE_AMR 3065 for (
const auto & f : family)
3072 side_lists[std::get<2>(t)].push_back(conv.get_inverse_shellface_map(std::get<1>(t)));
3076 std::vector<boundary_id_type> tmp;
3078 side_boundary_ids.insert(tmp.begin(), tmp.end());
3083 side_boundary_ids.insert(pr.first);
3086 if (side_boundary_ids.size() > 0)
3088 NamesData names_table(side_boundary_ids.size(), MAX_STR_LENGTH);
3090 std::vector<exII::ex_set> sets(side_boundary_ids.size());
3093 for (
auto [i, it] = std::tuple{0u, side_boundary_ids.begin()}; i<sets.size(); ++i, ++it)
3099 sets[i].type = exII::EX_SIDE_SET;
3100 sets[i].num_distribution_factor = 0;
3101 sets[i].distribution_factor_list =
nullptr;
3103 if (
const auto elem_it = elem_lists.find(ss_id);
3104 elem_it == elem_lists.end())
3106 sets[i].num_entry = 0;
3107 sets[i].entry_list =
nullptr;
3108 sets[i].extra_list =
nullptr;
3112 sets[i].num_entry = elem_it->second.size();
3113 sets[i].entry_list = elem_it->second.data();
3114 sets[i].extra_list = libmesh_map_find(side_lists, ss_id).data();
3118 ex_err = exII::ex_put_sets(
ex_id, side_boundary_ids.size(), sets.data());
3119 EX_CHECK_ERR(
ex_err,
"Error writing sidesets");
3121 ex_err = exII::ex_put_names(
ex_id, exII::EX_SIDE_SET, names_table.get_char_star_star());
3122 EX_CHECK_ERR(
ex_err,
"Error writing sideset names");
3130 LOG_SCOPE(
"write_nodesets()",
"ExodusII_IO_Helper");
3147 std::stable_sort(bc_tuples.begin(), bc_tuples.end(),
3150 {
return std::get<1>(t1) < std::get<1>(t2); });
3152 std::vector<boundary_id_type> node_boundary_ids;
3160 if (std::find(node_boundary_ids.begin(),
3161 node_boundary_ids.end(), id)
3162 == node_boundary_ids.end())
3163 node_boundary_ids.push_back(
id);
3167 if (node_boundary_ids.size() > 0)
3169 NamesData names_table(node_boundary_ids.size(), MAX_STR_LENGTH);
3187 std::map<boundary_id_type, unsigned int> nodeset_counts;
3188 for (
auto id : node_boundary_ids)
3189 nodeset_counts[id] = 0;
3191 for (
const auto & t : bc_tuples)
3196 nodeset_counts[nodeset_id] += 1;
3200 unsigned int running_sum = 0;
3201 for (
const auto & pr : nodeset_counts)
3207 running_sum += pr.second;
3212 exII::ex_set_specs set_data = {};
3221 ex_err = exII::ex_put_concat_sets(
ex_id, exII::EX_NODE_SET, &set_data);
3222 EX_CHECK_ERR(
ex_err,
"Error writing concatenated nodesets");
3225 ex_err = exII::ex_put_names(
ex_id, exII::EX_NODE_SET, names_table.get_char_star_star());
3226 EX_CHECK_ERR(
ex_err,
"Error writing nodeset names");
3233 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
3239 if (names.size() == 0)
3262 for (
auto var_num :
index_range(vars_active_subdomains))
3266 std::set<subdomain_id_type> current_set;
3267 if (vars_active_subdomains[var_num].empty())
3269 current_set.insert(cast_int<subdomain_id_type>(block_id));
3271 current_set = vars_active_subdomains[var_num];
3274 for (
auto block_id : current_set)
3277 libmesh_error_msg_if(it ==
block_ids.end(),
3278 "ExodusII_IO_Helper: block id " << block_id <<
" not found in block_ids.");
3280 std::size_t block_index =
3283 std::size_t truth_tab_index = block_index*
num_elem_vars + var_num;
3284 truth_tab[truth_tab_index] = 1;
3288 ex_err = exII::ex_put_truth_table
3290 exII::EX_ELEM_BLOCK,
3294 EX_CHECK_ERR(
ex_err,
"Error writing element truth table.");
3305 if (names.size() == 0)
3333 if (names.size() == 0)
3354 std::vector<std::string> & names,
3355 std::vector<std::string> & names_from_file)
3369 std::equal(names.begin(), names.end(),
3370 names_from_file.begin(),
3371 [](
const std::string & a,
3372 const std::string & b) ->
bool 3374 return a.compare(0, MAX_STR_LENGTH, b) == 0;
3379 libMesh::err <<
"Error! The Exodus file already contains the variables:" << std::endl;
3380 for (
const auto &
name : names_from_file)
3383 libMesh::err <<
"And you asked to write:" << std::endl;
3384 for (
const auto &
name : names)
3387 libmesh_error_msg(
"Cannot overwrite existing variables in Exodus II file.");
3400 float cast_time = float(time);
3401 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
3405 double cast_time = double(time);
3406 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
3408 EX_CHECK_ERR(
ex_err,
"Error writing timestep.");
3418 LOG_SCOPE(
"write_elemsets()",
"ExodusII_IO_Helper");
3430 std::map<elemset_id_type, std::vector<int>> exodus_elemsets;
3432 unsigned int elemset_index =
3437 for (
const auto & elem :
mesh.element_ptr_range())
3440 elem->get_extra_integer(elemset_index);
3452 for (
const auto & set_id : set_ids)
3466 if (!exodus_elemsets.empty())
3472 std::vector<exII::ex_set> sets;
3473 sets.reserve(exodus_elemsets.size());
3475 for (
auto & [elem_set_id, ids_vec] : exodus_elemsets)
3480 exII::ex_set & current_set = sets.emplace_back();
3481 current_set.id = elem_set_id;
3482 current_set.type = exII::EX_ELEM_SET;
3483 current_set.num_entry = ids_vec.size();
3484 current_set.num_distribution_factor = 0;
3485 current_set.entry_list = ids_vec.data();
3486 current_set.extra_list =
nullptr;
3487 current_set.distribution_factor_list =
nullptr;
3492 libmesh_assert_msg(
num_elem_sets == cast_int<int>(exodus_elemsets.size()),
3493 "Mesh has " << exodus_elemsets.size()
3494 <<
" elemsets, but header was written with num_elem_sets == " <<
num_elem_sets);
3497 <<
", but header was written with num_elem_sets == " <<
num_elem_sets);
3499 ex_err = exII::ex_put_sets(
ex_id, exodus_elemsets.size(), sets.data());
3500 EX_CHECK_ERR(
ex_err,
"Error writing elemsets");
3515 const std::vector<std::string> & var_names,
3516 const std::vector<std::set<boundary_id_type>> & side_ids,
3517 const std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
3519 LOG_SCOPE(
"write_sideset_data()",
"ExodusII_IO_Helper");
3545 std::vector<int> sset_var_tab(
num_side_sets * var_names.size());
3564 if (!side_ids[var].count(
ss_ids[ss]))
3568 sset_var_tab[ss*var_names.size() + var] = 1;
3574 const auto & data_map = bc_vals[var];
3597 libmesh_error_msg_if
3599 cast_int<dof_id_type>(
elem_list[i + offset]),
3600 "Error mapping Exodus elem id to libmesh elem id.");
3618 sset_var_vals[i] = libmesh_map_find(data_map, key);
3624 if (sset_var_vals.size() > 0)
3626 ex_err = exII::ex_put_var
3634 EX_CHECK_ERR(
ex_err,
"Error writing sideset vars.");
3641 exII::ex_put_truth_table(
ex_id,
3644 cast_int<int>(var_names.size()),
3645 sset_var_tab.data());
3646 EX_CHECK_ERR(
ex_err,
"Error writing sideset var truth table.");
3655 std::vector<std::string> & var_names,
3656 std::vector<std::set<boundary_id_type>> & side_ids,
3657 std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
3659 LOG_SCOPE(
"read_sideset_data()",
"ExodusII_IO_Helper");
3669 ex_err = exII::ex_get_truth_table
3674 sset_var_tab.data());
3675 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable truth table.");
3704 side_ids[var].insert(
ss_ids[ss]);
3710 ex_err = exII::ex_get_var
3718 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable.");
3723 unsigned int exodus_side_id =
side_list[i + offset];
3728 dof_id_type converted_elem_id = exodus_elem_id - 1;
3737 unsigned int converted_side_id = conv.
get_side_map(exodus_side_id - 1);
3746 bc_vals[var].emplace(key, sset_var_vals[i]);
3758 std::map<BoundaryInfo::BCTuple, unsigned int> & bc_array_indices)
3761 bc_array_indices.clear();
3775 unsigned int exodus_side_id =
side_list[i + offset];
3780 dof_id_type converted_elem_id = exodus_elem_id - 1;
3788 unsigned int converted_side_id = conv.
get_side_map(exodus_side_id - 1);
3797 bc_array_indices.emplace(key, cast_int<unsigned int>(i));
3806 const std::vector<std::string> & var_names,
3807 const std::vector<std::set<boundary_id_type>> & node_boundary_ids,
3808 const std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals)
3810 LOG_SCOPE(
"write_nodeset_data()",
"ExodusII_IO_Helper");
3834 std::vector<int> nset_var_tab(
num_node_sets * var_names.size());
3846 if (!node_boundary_ids[var].count(
nodeset_ids[ns]))
3850 nset_var_tab[ns*var_names.size() + var] = 1;
3856 const auto & data_map = bc_vals[var];
3870 std::make_tuple(libmesh_node_id,
nodeset_ids[ns]);
3877 nset_var_vals[i] = libmesh_map_find(data_map, key);
3881 if (nset_var_vals.size() > 0)
3883 ex_err = exII::ex_put_var
3891 EX_CHECK_ERR(
ex_err,
"Error writing nodeset vars.");
3898 exII::ex_put_truth_table(
ex_id,
3901 cast_int<int>(var_names.size()),
3902 nset_var_tab.data());
3903 EX_CHECK_ERR(
ex_err,
"Error writing nodeset var truth table.");
3911 const std::vector<std::string> & var_names,
3912 const std::vector<std::set<elemset_id_type>> & elemset_ids_in,
3913 const std::vector<std::map<std::pair<dof_id_type, elemset_id_type>,
Real>> & elemset_vals)
3915 LOG_SCOPE(
"write_elemset_data()",
"ExodusII_IO_Helper");
3944 std::vector<int> elemset_var_tab(
num_elem_sets * var_names.size());
3970 elemset_var_tab[es*var_names.size() + var] = 1;
3976 const auto & data_map = elemset_vals[var];
3989 std::pair<dof_id_type, elemset_id_type> key =
4000 elemset_var_vals[i] = libmesh_map_find(data_map, key);
4004 if (elemset_var_vals.size() > 0)
4006 ex_err = exII::ex_put_var
4014 EX_CHECK_ERR(
ex_err,
"Error writing elemset vars.");
4021 exII::ex_put_truth_table(
ex_id,
4024 cast_int<int>(var_names.size()),
4025 elemset_var_tab.data());
4026 EX_CHECK_ERR(
ex_err,
"Error writing elemset var truth table.");
4034 std::vector<std::string> & var_names,
4035 std::vector<std::set<elemset_id_type>> & elemset_ids_in,
4036 std::vector<std::map<std::pair<dof_id_type, elemset_id_type>,
Real>> & elemset_vals)
4038 LOG_SCOPE(
"read_elemset_data()",
"ExodusII_IO_Helper");
4059 exII::ex_get_truth_table(
ex_id,
4063 elemset_var_tab.data());
4064 EX_CHECK_ERR(
ex_err,
"Error reading elemset variable truth table.");
4107 ex_err = exII::ex_get_var
4115 EX_CHECK_ERR(
ex_err,
"Error reading elemset variable.");
4124 dof_id_type converted_elem_id = exodus_elem_id - 1;
4127 auto key = std::make_pair(converted_elem_id,
4131 elemset_vals[var].emplace(key, elemset_var_vals[i]);
4145 elemset_array_indices.clear();
4169 dof_id_type converted_elem_id = exodus_elem_id - 1;
4173 auto key = std::make_pair(converted_elem_id,
4177 elemset_array_indices.emplace(key, cast_int<unsigned int>(i));
4186 std::vector<std::string> & var_names,
4187 std::vector<std::set<boundary_id_type>> & node_boundary_ids,
4188 std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals)
4190 LOG_SCOPE(
"read_nodeset_data()",
"ExodusII_IO_Helper");
4200 ex_err = exII::ex_get_truth_table
4205 nset_var_tab.data());
4206 EX_CHECK_ERR(
ex_err,
"Error reading nodeset variable truth table.");
4242 ex_err = exII::ex_get_var
4250 EX_CHECK_ERR(
ex_err,
"Error reading nodeset variable.");
4265 dof_id_type converted_node_id = exodus_node_id - 1;
4272 bc_vals[var].emplace(key, nset_var_vals[i]);
4287 bc_array_indices.clear();
4316 dof_id_type converted_node_id = exodus_node_id - 1;
4323 bc_array_indices.emplace(key, cast_int<unsigned int>(i));
4330 const std::vector<Real> & values,
4332 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
4334 LOG_SCOPE(
"write_element_values()",
"ExodusII_IO_Helper");
4341 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
4346 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
4347 for (
const auto & elem :
mesh.active_element_ptr_range())
4348 subdomain_map[elem->subdomain_id()].push_back(elem->id());
4357 libmesh_assert_equal_to
4358 (vars_active_subdomains.size(),
4364 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
4367 auto it = subdomain_map.begin();
4370 const auto & active_subdomains
4371 = vars_active_subdomains[var_id];
4373 for (
unsigned int j=0; it!=subdomain_map.end(); ++it, ++j)
4378 if (!(active_subdomains.empty() || active_subdomains.count(it->first)))
4384 const auto & elem_nums = it->second;
4385 const unsigned int num_elems_this_block =
4386 cast_int<unsigned int>(elem_nums.size());
4387 std::vector<Real> data(num_elems_this_block);
4392 for (
unsigned int k=0; k<num_elems_this_block; ++k)
4393 data[k] = values[var_id*
n_elem + elem_nums[k]];
4395 ex_err = exII::ex_put_var
4398 exII::EX_ELEM_BLOCK,
4401 num_elems_this_block,
4404 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
4415 const std::vector<Real> & values,
4417 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
4418 const std::vector<std::string> & derived_var_names,
4419 const std::map<
subdomain_id_type, std::vector<std::string>> & subdomain_to_var_names)
4426 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
4433 std::map<subdomain_id_type, unsigned int> subdomain_to_n_elem;
4434 for (
const auto & elem :
mesh.active_element_ptr_range())
4435 subdomain_to_n_elem[elem->subdomain_id()] += 1;
4439 libmesh_assert_equal_to
4440 (vars_active_subdomains.size(),
4444 auto subdomain_to_n_elem_iter = subdomain_to_n_elem.begin();
4450 (
mesh.active_elements_begin(),
4451 mesh.active_elements_end());
4453 for (
unsigned int sbd_idx=0;
4454 subdomain_to_n_elem_iter != subdomain_to_n_elem.end();
4455 ++subdomain_to_n_elem_iter, ++sbd_idx)
4456 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
4459 const auto & active_subdomains
4460 = vars_active_subdomains[var_id];
4467 if (!active_subdomains.count(subdomain_to_n_elem_iter->first))
4471 std::vector<Real> data;
4472 data.reserve(subdomain_to_n_elem_iter->second);
4474 unsigned int values_offset = 0;
4475 for (
auto & elem : elem_range)
4482 auto subdomain_to_var_names_iter =
4483 subdomain_to_var_names.find(sbd_id);
4491 if (subdomain_to_var_names_iter == subdomain_to_var_names.end())
4494 const auto & var_names_this_sbd
4495 = subdomain_to_var_names_iter->second;
4498 if (sbd_id == subdomain_to_n_elem_iter->first)
4506 std::find(var_names_this_sbd.begin(),
4507 var_names_this_sbd.end(),
4508 derived_var_names[var_id]);
4510 libmesh_error_msg_if(pos == var_names_this_sbd.end(),
4511 "Derived name " << derived_var_names[var_id] <<
" not found!");
4518 data.push_back(values[values_offset + true_index]);
4523 auto true_offset = var_names_this_sbd.size();
4526 values_offset += true_offset;
4532 ex_err = exII::ex_put_var
4535 exII::EX_ELEM_BLOCK,
4541 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
4552 const std::vector<Real> & values,
4558 if (!values.empty())
4560 libmesh_assert_equal_to(values.size(), std::size_t(
num_nodes));
4562 ex_err = exII::ex_put_var
4571 EX_CHECK_ERR(
ex_err,
"Error writing nodal values.");
4588 int num_info = inquire(*
this, exII::EX_INQ_INFO,
"Error retrieving the number of information records from file!");
4591 libMesh::err <<
"Warning! The Exodus file already contains information records.\n" 4592 <<
"Exodus does not support writing additional records in this situation." 4597 int num_records = cast_int<int>(records.size());
4599 if (num_records > 0)
4605 for (
const auto & record : records)
4606 info.push_back_entry(record);
4608 ex_err = exII::ex_put_info(
ex_id, num_records,
info.get_char_star_star());
4609 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
4622 if (!values.empty())
4624 ex_err = exII::ex_put_var
4633 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
4644 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
4656 ex_err = exII::ex_get_var
4665 EX_CHECK_ERR(
ex_err,
"Error reading global values.");
4697 std::vector<std::string>
4699 bool write_complex_abs)
const 4701 std::vector<std::string> complex_names;
4705 for (
const auto &
name : names)
4707 complex_names.push_back(
"r_" +
name);
4708 complex_names.push_back(
"i_" +
name);
4709 if (write_complex_abs)
4710 complex_names.push_back(
"a_" +
name);
4713 return complex_names;
4718 std::vector<std::set<subdomain_id_type>>
4721 (
const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
4722 bool write_complex_abs)
const 4724 std::vector<std::set<subdomain_id_type>> complex_vars_active_subdomains;
4726 for (
auto & s : vars_active_subdomains)
4730 complex_vars_active_subdomains.push_back(s);
4731 complex_vars_active_subdomains.push_back(s);
4732 if (write_complex_abs)
4733 complex_vars_active_subdomains.push_back(s);
4736 return complex_vars_active_subdomains;
4741 std::map<subdomain_id_type, std::vector<std::string>>
4745 bool write_complex_abs)
const 4748 std::map<subdomain_id_type, std::vector<std::string>> ret;
4750 unsigned int num_complex_outputs = write_complex_abs ? 3 : 2;
4752 for (
const auto & pr : subdomain_to_var_names)
4755 auto & vec = ret[pr.first];
4758 const auto & varnames = pr.second;
4761 vec.reserve(num_complex_outputs * varnames.size());
4766 for (
const auto & varname : varnames)
4768 vec.push_back(
"r_" + varname);
4769 vec.push_back(
"i_" + varname);
4770 if (write_complex_abs)
4771 vec.push_back(
"a_" + varname);
4784 libmesh_assert_less (i, node_map->size());
4785 return (*node_map)[i];
4792 if (!inverse_node_map)
4795 libmesh_assert_less (i, inverse_node_map->size());
4796 return (*inverse_node_map)[i];
4808 if (static_cast<size_t>(i) >= side_map->size())
4811 return (*side_map)[i];
4819 if (!inverse_side_map)
4822 libmesh_assert_less (i, inverse_side_map->size());
4823 return (*inverse_side_map)[i];
4837 libmesh_assert_less (i, shellface_map->size());
4838 return (*shellface_map)[i];
4845 if (!inverse_shellface_map)
4848 libmesh_assert_less (i, inverse_shellface_map->size());
4849 return (*inverse_shellface_map)[i];
4856 return libmesh_type;
4873 return shellface_index_offset;
4877 data_table(n_strings),
4878 data_table_pointers(n_strings),
4880 table_size(n_strings)
4882 for (
size_t i=0; i<n_strings; ++i)
4898 libmesh_assert_less (counter, table_size);
4901 size_t num_copied =
name.copy(data_table[counter].data(), data_table[counter].size()-1);
4904 data_table[counter][num_copied] =
'\0';
4914 return data_table_pointers.data();
4921 libmesh_error_msg_if(static_cast<unsigned>(i) >= table_size,
4922 "Requested char * " << i <<
" but only have " << table_size <<
"!");
4924 return data_table[i].data();
4933 #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
As above, but the library creates and fills in a vector of (elem-id, side-id, bc-id) triplets and ret...
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
const char * get_elem_type() const
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
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
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.
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...
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.
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 build_side_list(std::vector< dof_id_type > &element_id_list, std::vector< unsigned short int > &side_list, std::vector< boundary_id_type > &bc_id_list) const
Creates a list of element numbers, sides, and ids for those sides.
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
As above, but the library creates and fills in a vector of (node-id, bc-id) pairs and returns it to t...
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 &...)
void build_node_list(std::vector< dof_id_type > &node_id_list, std::vector< boundary_id_type > &bc_id_list) const
Creates a list of nodes and ids for those nodes.
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
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
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...
void build_shellface_list(std::vector< dof_id_type > &element_id_list, std::vector< unsigned short int > &shellface_list, std::vector< boundary_id_type > &bc_id_list) const
Creates a list of element numbers, shellfaces, and boundary ids for those shellfaces.
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
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.
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...
void build_edge_list(std::vector< dof_id_type > &element_id_list, std::vector< unsigned short int > &edge_list, std::vector< boundary_id_type > &bc_id_list) const
Creates a list of element numbers, edges, and boundary ids for those edges.
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...
unsigned int mesh_dimension() const
std::vector< int > elem_num_map
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< 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 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.
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