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;
1015 const int vecsize = bex_dense_cv_info[2*i+1];
1018 vec.resize(vecsize);
1019 std::copy(
std::next(bex_dense_cv_blocks.begin(), offset),
1020 std::next(bex_dense_cv_blocks.begin(), offset + vecsize),
1029 #endif // EX_API_VERS_NODOT >= 800 1036 out_stream <<
"(" <<
x[i] <<
", " <<
y[i] <<
", " <<
z[i] <<
")" << std::endl;
1048 exII::EX_ELEM_BLOCK,
1051 EX_CHECK_ERR(
ex_err,
"Error getting block IDs.");
1052 message(
"All block IDs retrieved successfully.");
1054 char name_buffer[MAX_STR_LENGTH+1];
1057 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_BLOCK,
1059 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
1062 message(
"All block names retrieved successfully.");
1070 exII::EX_EDGE_BLOCK,
1073 EX_CHECK_ERR(
ex_err,
"Error getting edge block IDs.");
1074 message(
"All edge block IDs retrieved successfully.");
1077 char name_buffer[MAX_STR_LENGTH+1];
1080 ex_err = exII::ex_get_name(
ex_id, exII::EX_EDGE_BLOCK,
1082 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
1085 message(
"All edge block names retrieved successfully.");
1093 libmesh_assert_less (index,
block_ids.size());
1102 libmesh_assert_less (index,
block_ids.size());
1111 libmesh_assert_less (index,
ss_ids.size());
1120 libmesh_assert_less (index,
ss_ids.size());
1148 LOG_SCOPE(
"read_elem_in_block()",
"ExodusII_IO_Helper");
1150 libmesh_assert_less (block,
block_ids.size());
1153 int num_edges_per_elem = 0;
1154 int num_faces_per_elem = 0;
1155 int num_node_data_per_elem = 0;
1157 exII::EX_ELEM_BLOCK,
1161 &num_node_data_per_elem,
1162 &num_edges_per_elem,
1163 &num_faces_per_elem,
1166 EX_CHECK_ERR(
ex_err,
"Error getting block info.");
1167 message(
"Info retrieved successfully for block: ", block);
1172 if (!(num_edges_per_elem == 0) && !(num_edges_per_elem == -1))
1173 libmesh_warning(
"Exodus files with extended edge connectivity not currently supported.");
1174 if (!(num_faces_per_elem == 0) && !(num_faces_per_elem == -1))
1175 libmesh_warning(
"Exodus files with extended face connectivity not currently supported.");
1180 const bool is_bezier = is_bezier_elem(
elem_type.data());
1193 <<
" nodes per element." << std::endl;
1203 exII::EX_ELEM_BLOCK,
1209 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
1210 message(
"Connectivity retrieved successfully for block: ", block);
1218 #if EX_API_VERS_NODOT >= 800 1219 int real_n_attr = exII::ex_get_attribute_count(
ex_id, exII::EX_ELEM_BLOCK,
block_ids[block]);
1220 EX_CHECK_ERR(real_n_attr,
"Error getting number of element block attributes.");
1222 if (real_n_attr > 0)
1224 std::vector<exII::ex_attribute> attributes(real_n_attr);
1226 ex_err = exII::ex_get_attribute_param(
ex_id, exII::EX_ELEM_BLOCK,
block_ids[block], attributes.data());
1227 EX_CHECK_ERR(
ex_err,
"Error getting element block attribute parameters.");
1229 ex_err = exII::ex_get_attributes(
ex_id, real_n_attr, attributes.data());
1230 EX_CHECK_ERR(
ex_err,
"Error getting element block attribute values.");
1232 for (
auto attr : attributes)
1234 if (std::string(
"bex_elem_degrees") == attr.name)
1236 if (attr.type != exII::EX_INTEGER)
1237 libmesh_error_msg(
"Found non-integer bex_elem_degrees");
1239 if (attr.value_count > 3)
1240 libmesh_error_msg(
"Looking for at most 3 bex_elem_degrees; found " << attr.value_count);
1244 std::vector<int> bex_elem_degrees(3);
1246 const int * as_int =
static_cast<int *
>(attr.values);
1247 std::copy(as_int, as_int+attr.value_count, bex_elem_degrees.begin());
1257 libmesh_assert_equal_to(bex_elem_degrees[d], 2);
1283 auto src = old_connect.data();
1299 #endif // EX_API_VERS_NODOT >= 800 1306 LOG_SCOPE(
"read_edge_blocks()",
"ExodusII_IO_Helper");
1322 typedef std::pair<dof_id_type, unsigned int> ElemEdgePair;
1323 std::unordered_map<dof_id_type, std::vector<ElemEdgePair>> edge_map;
1324 std::unique_ptr<Elem> edge_ptr;
1325 for (
const auto & elem :
mesh.element_ptr_range())
1326 for (
auto e : elem->edge_index_range())
1328 elem->build_edge_ptr(edge_ptr, e);
1332 auto & vec = edge_map[edge_key];
1333 vec.emplace_back(elem->id(), e);
1340 if (edge_ptr->default_order() !=
FIRST)
1343 auto low_order_edge =
1347 for (
unsigned int v=0; v<edge_ptr->n_vertices(); ++v)
1348 low_order_edge->set_node(v, edge_ptr->node_ptr(v));
1351 dof_id_type low_order_edge_key = low_order_edge->key();
1355 auto & low_order_vec = edge_map[low_order_edge_key];
1356 low_order_vec.emplace_back(elem->id(), e);
1369 int num_edge_this_blk = 0;
1370 int num_nodes_per_edge = 0;
1371 int num_edges_per_edge = 0;
1372 int num_faces_per_edge = 0;
1373 int num_attr_per_edge = 0;
1375 exII::EX_EDGE_BLOCK,
1379 &num_nodes_per_edge,
1380 &num_edges_per_edge,
1381 &num_faces_per_edge,
1382 &num_attr_per_edge);
1384 EX_CHECK_ERR(
ex_err,
"Error getting edge block info.");
1385 message(
"Info retrieved successfully for block: ", edge_block_id);
1390 connect.resize(num_nodes_per_edge * num_edge_this_blk);
1395 exII::EX_EDGE_BLOCK,
1401 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
1402 message(
"Connectivity retrieved successfully for block: ", edge_block_id);
1411 for (
unsigned int i=0, sz=
connect.size(); i<sz; i+=num_nodes_per_edge)
1413 auto edge =
Elem::build(conv.libmesh_elem_type());
1414 for (
int n=0; n<num_nodes_per_edge; ++n)
1416 int exodus_node_id =
connect[i+n];
1417 int exodus_node_id_zero_based = exodus_node_id - 1;
1418 int libmesh_node_id =
node_num_map[exodus_node_id_zero_based] - 1;
1429 auto & elem_edge_pair_vec =
1430 libmesh_map_find(edge_map, edge_key);
1432 for (
const auto & elem_edge_pair : elem_edge_pair_vec)
1444 build_edge_ptr(edge_ptr, elem_edge_pair.second);
1453 ((edge_ptr->node_id(0) == edge->node_id(0)) && (edge_ptr->node_id(1) == edge->node_id(1))) ||
1454 ((edge_ptr->node_id(0) == edge->node_id(1)) && (edge_ptr->node_id(1) == edge->node_id(0)));
1460 elem_edge_pair.second,
1482 ex_err = exII::ex_get_elem_num_map
1485 EX_CHECK_ERR(
ex_err,
"Error retrieving element number map.");
1486 message(
"Element numbering map retrieved successfully.");
1499 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_elem-1)); ++i)
1515 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset information.");
1516 message(
"All sideset information retrieved successfully.");
1523 num_elem_all_sidesets = inquire(*
this, exII::EX_INQ_SS_ELEM_LEN,
"Error retrieving length of the concatenated side sets element list!");
1530 char name_buffer[MAX_STR_LENGTH+1];
1533 ex_err = exII::ex_get_name(
ex_id, exII::EX_SIDE_SET,
1535 EX_CHECK_ERR(
ex_err,
"Error getting side set name.");
1538 message(
"All side set names retrieved successfully.");
1550 EX_CHECK_ERR(
ex_err,
"Error retrieving nodeset information.");
1551 message(
"All nodeset information retrieved successfully.");
1558 char name_buffer[MAX_STR_LENGTH+1];
1561 ex_err = exII::ex_get_name(
ex_id, exII::EX_NODE_SET,
1563 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1566 message(
"All node set names retrieved successfully.");
1579 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset information.");
1580 message(
"All elemset information retrieved successfully.");
1588 inquire(*
this, exII::EX_INQ_ELS_LEN,
1589 "Error retrieving length of the concatenated elem sets element list!");
1598 char name_buffer[MAX_STR_LENGTH+1];
1601 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_SET,
1603 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1606 message(
"All elem set names retrieved successfully.");
1613 LOG_SCOPE(
"read_sideset()",
"ExodusII_IO_Helper");
1615 libmesh_assert_less (
id,
ss_ids.size());
1618 libmesh_assert_less_equal (offset,
elem_list.size());
1619 libmesh_assert_less_equal (offset,
side_list.size());
1626 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset parameters.");
1627 message(
"Parameters retrieved successfully for sideset: ",
id);
1633 if (static_cast<unsigned int>(offset) ==
elem_list.size() ||
1634 static_cast<unsigned int>(offset) ==
side_list.size() )
1648 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset data.");
1649 message(
"Data retrieved successfully for sideset: ",
id);
1660 LOG_SCOPE(
"read_elemset()",
"ExodusII_IO_Helper");
1665 libmesh_assert_less_equal (offset,
elemset_list.size());
1672 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset parameters.");
1673 message(
"Parameters retrieved successfully for elemset: ",
id);
1679 if (static_cast<unsigned int>(offset) ==
elemset_list.size())
1692 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset data.");
1693 message(
"Data retrieved successfully for elemset: ",
id);
1705 LOG_SCOPE(
"read_all_nodesets()",
"ExodusII_IO_Helper");
1711 (*
this, exII::EX_INQ_NODE_SETS,
1712 "Error retrieving number of node sets");
1715 int total_nodes_in_all_sets =
1717 (*
this, exII::EX_INQ_NS_NODE_LEN,
1718 "Error retrieving number of nodes in all node sets.");
1721 int total_df_in_all_sets =
1723 (*
this, exII::EX_INQ_NS_DF_LEN,
1724 "Error retrieving number of distribution factors in all node sets.");
1744 exII::ex_set_specs set_specs = {};
1751 set_specs.sets_extra_list =
nullptr;
1752 set_specs.sets_dist_fact = total_df_in_all_sets ? mapped_node_sets_dist_fact.
data() :
nullptr;
1754 ex_err = exII::ex_get_concat_sets(
ex_id, exII::EX_NODE_SET, &set_specs);
1755 EX_CHECK_ERR(
ex_err,
"Error reading concatenated nodesets");
1758 char name_buffer[MAX_STR_LENGTH+1];
1761 ex_err = exII::ex_get_name
1766 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1797 message(
"Error closing Exodus file.");
1799 message(
"Exodus file closed successfully.");
1820 ex_err = exII::ex_get_all_times
1823 EX_CHECK_ERR(
ex_err,
"Error reading timesteps!");
1832 inquire(*
this, exII::EX_INQ_TIME,
"Error retrieving number of time steps");
1839 LOG_SCOPE(
"read_nodal_var_values()",
"ExodusII_IO_Helper");
1845 unsigned int var_index = 0;
1862 libmesh_error_msg(
"Unable to locate variable named: " << nodal_var_name);
1868 std::vector<Real> unmapped_nodal_var_values(
num_nodes);
1871 ex_err = exII::ex_get_var
1879 EX_CHECK_ERR(
ex_err,
"Error reading nodal variable values!");
1881 for (
unsigned i=0; i<static_cast<unsigned>(
num_nodes); i++)
1887 const unsigned mapped_node_id = this->
node_num_map[i] - 1;
1889 libmesh_assert_less(i, unmapped_nodal_var_values.size());
1921 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
1929 std::vector<std::string> & result)
1932 ex_err = exII::ex_get_var_param(
ex_id, var_type, &count);
1933 EX_CHECK_ERR(
ex_err,
"Error reading number of variables.");
1940 NamesData names_table(count, MAX_STR_LENGTH);
1947 EX_CHECK_ERR(
ex_err,
"Error reading variable names!");
1951 libMesh::out <<
"Read the variable(s) from the file:" << std::endl;
1952 for (
int i=0; i<count; i++)
1957 result.resize(count);
1960 for (
int i=0; i<count; i++)
1969 const std::vector<std::string> & names)
2001 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
2010 const std::vector<std::string> & names)
2013 count = cast_int<int>(names.size());
2016 ex_err = exII::ex_put_var_param(
ex_id, var_type, count);
2017 EX_CHECK_ERR(
ex_err,
"Error setting number of vars.");
2026 NamesData names_table(count, MAX_STR_LENGTH);
2029 for (
int i=0; i != count; ++i)
2031 if(names[i].length() > MAX_STR_LENGTH)
2033 "*** Warning, Exodus variable name \"" 2034 << names[i] <<
"\" too long (max " << MAX_STR_LENGTH
2035 <<
" characters). Name will be truncated. ");
2041 libMesh::out <<
"Writing variable name(s) to file: " << std::endl;
2042 for (
int i=0; i != count; ++i)
2052 EX_CHECK_ERR(
ex_err,
"Error writing variable names.");
2060 std::map<dof_id_type, Real> & elem_var_value_map)
2062 LOG_SCOPE(
"read_elemental_var_values()",
"ExodusII_IO_Helper");
2067 unsigned int var_index = 0;
2084 libmesh_error_msg(
"Unable to locate variable named: " << elemental_var_name);
2088 unsigned ex_el_num = 0;
2094 for (
unsigned i=0; i<static_cast<unsigned>(
num_elem_blk); i++)
2097 exII::EX_ELEM_BLOCK,
2105 EX_CHECK_ERR(
ex_err,
"Error getting number of elements in block.");
2118 ex_err = exII::ex_get_var
2121 exII::EX_ELEM_BLOCK,
2126 EX_CHECK_ERR(
ex_err,
"Error getting elemental values.");
2132 unsigned mapped_elem_id = this->
elem_num_map[ex_el_num] - 1;
2135 elem_var_value_map[mapped_elem_id] = block_elem_var_values[j];
2159 comp_ws = cast_int<int>(
sizeof(float));
2160 io_ws = cast_int<int>(
sizeof(float));
2166 comp_ws = cast_int<int>
2167 (std::min(
sizeof(
Real),
sizeof(
double)));
2168 io_ws = cast_int<int>
2169 (std::min(
sizeof(
Real),
sizeof(
double)));
2175 int mode = EX_CLOBBER;
2180 #ifdef LIBMESH_HAVE_HDF5 2184 mode |= EX_NOCLASSIC;
2190 ex_id = exII::ex_create(filename.c_str(), mode, &comp_ws, &io_ws);
2193 EX_CHECK_ERR(
ex_id,
"Error creating ExodusII/Nemesis mesh file.");
2196 libMesh::out <<
"File created successfully." << std::endl;
2211 libmesh_parallel_only(
mesh.
comm());
2219 auto subdomain_map = build_subdomain_map(
mesh,
_add_sides, subdomain_id_end);
2234 for (
const auto & elem :
mesh.active_local_element_ptr_range())
2236 for (
auto s : elem->side_index_range())
2242 num_local_side_nodes += elem->nodes_on_side(s).size();
2260 mesh.local_nodes_end()));
2265 const dof_id_type n_gaps = max_nn - n_total_nodes;
2266 const dof_id_type gaps_per_processor = n_gaps / n_proc;
2267 const dof_id_type remainder_gaps = n_gaps % n_proc;
2269 n_local_nodes = n_local_nodes +
2270 gaps_per_processor +
2290 if (!use_discontinuous)
2300 for (
const auto & elem :
mesh.active_element_ptr_range())
2304 std::set<boundary_id_type> unique_side_boundaries;
2305 std::vector<boundary_id_type> unique_node_boundaries;
2310 std::vector<boundary_id_type> side_boundaries;
2312 unique_side_boundaries.insert(side_boundaries.begin(), side_boundaries.end());
2316 std::vector<boundary_id_type> shellface_boundaries;
2318 unique_side_boundaries.insert(shellface_boundaries.begin(), shellface_boundaries.end());
2322 unique_side_boundaries.insert(pr.first);
2331 if (std::find(unique_node_boundaries.begin(),
2332 unique_node_boundaries.end(), id)
2333 == unique_node_boundaries.end())
2334 unique_node_boundaries.push_back(
id);
2337 num_side_sets = cast_int<int>(unique_side_boundaries.size());
2338 num_node_sets = cast_int<int>(unique_node_boundaries.size());
2342 if (str_title.size() > MAX_LINE_LENGTH)
2344 libMesh::err <<
"Warning, Exodus files cannot have titles longer than " 2346 <<
" characters. Your title will be truncated." 2348 str_title.resize(MAX_LINE_LENGTH);
2385 exII::ex_init_params params = {};
2386 params.title[str_title.copy(params.title, MAX_LINE_LENGTH)] =
'\0';
2398 EX_CHECK_ERR(
ex_err,
"Error initializing new Exodus file.");
2421 auto push_node = [
this](
const Point & p) {
2455 if (!use_discontinuous)
2457 for (
const auto & node_ptr :
mesh.node_ptr_range())
2459 const Node & node = *node_ptr;
2477 for (
const auto & elem :
mesh.active_element_ptr_range())
2478 for (
const Node & node : elem->node_ref_range())
2496 std::vector<std::vector<const Elem *>>
2499 for (
const auto & elem :
mesh.active_element_ptr_range())
2500 elems_by_pid[elem->processor_id()].push_back(elem);
2503 for (
const Elem * elem : elems_by_pid[p])
2504 for (
auto s : elem->side_index_range())
2509 const std::vector<unsigned int> side_nodes =
2510 elem->nodes_on_side(s);
2512 for (
auto n : side_nodes)
2513 push_node(elem->point(n));
2522 ex_err = exII::ex_put_coord
2528 EX_CHECK_ERR(
ex_err,
"Error writing coordinates to Exodus file.");
2534 EX_CHECK_ERR(
ex_err,
"Error writing node_num_map");
2542 LOG_SCOPE(
"write_elements()",
"ExodusII_IO_Helper");
2547 auto subdomain_map = build_subdomain_map(
mesh,
_add_sides, subdomain_id_end);
2556 std::vector<int> elem_blk_id;
2557 std::vector<int> num_elem_this_blk_vec;
2558 std::vector<int> num_nodes_per_elem_vec;
2559 std::vector<int> num_edges_per_elem_vec;
2560 std::vector<int> num_faces_per_elem_vec;
2561 std::vector<int> num_attr_vec;
2573 unsigned int counter = 0;
2574 for (
auto & [subdomain_id, element_id_vec] : subdomain_map)
2578 const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
2579 ElemType(subdomain_id - subdomain_id_end) :
2582 if (subdomain_id >= subdomain_id_end)
2586 num_elem_this_blk_vec.push_back
2587 (cast_int<int>(element_id_vec[0]));
2589 (Utility::enum_to_string<ElemType>(elem_t));
2594 num_elem_this_blk_vec.push_back
2595 (cast_int<int>(element_id_vec.size()));
2600 num_elem += num_elem_this_blk_vec.back();
2608 libmesh_not_implemented_msg(
"Support for Polygons/Polyhedra not yet implemented");
2610 elem_blk_id.push_back(subdomain_id);
2613 num_attr_vec.push_back(0);
2614 num_edges_per_elem_vec.push_back(0);
2615 num_faces_per_elem_vec.push_back(0);
2620 std::vector<int>::iterator curr_elem_map_end =
elem_num_map.begin();
2628 std::map<std::pair<dof_id_type, unsigned int>,
dof_id_type> discontinuous_node_indices;
2630 if (use_discontinuous)
2632 for (
const auto & elem :
mesh.active_element_ptr_range())
2633 for (
auto n : elem->node_index_range())
2634 discontinuous_node_indices[std::make_pair(elem->id(),n)] =
2642 for (
const Elem * elem :
mesh.active_element_ptr_range())
2646 unsigned int local_node_index = elem->n_nodes();
2648 for (
auto s : elem->side_index_range())
2653 const std::vector<unsigned int> side_nodes =
2654 elem->nodes_on_side(s);
2659 discontinuous_node_indices
2660 [std::make_pair(elem->id(),local_node_index++)] =
2671 std::vector<BoundaryInfo::BCTuple> edge_tuples = bi.
build_edge_list();
2679 std::map<boundary_id_type, std::vector<int>> edge_id_to_conn;
2680 std::map<boundary_id_type, std::pair<ElemType, unsigned int>> edge_id_to_elem_type;
2682 std::unique_ptr<const Elem> edge;
2683 for (
const auto & t : edge_tuples)
2686 unsigned int edge_id = std::get<1>(t);
2694 if (
const auto check_it = edge_id_to_elem_type.find(b_id);
2695 check_it == edge_id_to_elem_type.end())
2698 edge_id_to_elem_type[b_id] = std::make_pair(edge->type(), edge->n_nodes());
2703 const auto & val_pair = check_it->second;
2704 libmesh_error_msg_if(val_pair.first != edge->type() || val_pair.second != edge->n_nodes(),
2705 "All edges in a block must have same geometric type.");
2709 auto & conn = edge_id_to_conn[b_id];
2715 for (
auto n : edge->node_index_range())
2719 int exodus_node_id = -1;
2721 if (!use_discontinuous)
2723 dof_id_type libmesh_node_id = edge->node_ptr(n)->id();
2724 exodus_node_id = libmesh_map_find
2733 exodus_node_id = libmesh_map_find
2734 (discontinuous_node_indices, std::make_pair(elem_id, pn));
2737 conn.push_back(exodus_node_id);
2747 std::vector<int> edge_blk_id;
2749 std::vector<int> num_edge_this_blk_vec;
2750 std::vector<int> num_nodes_per_edge_vec;
2751 std::vector<int> num_attr_edge_vec;
2758 for (
const auto & pr : edge_id_to_conn)
2762 edge_blk_id.push_back(
id);
2765 const auto & elem_type_node_count = edge_id_to_elem_type[id];
2768 num_nodes_per_edge_vec.push_back(elem_type_node_count.second);
2772 num_edge_this_blk_vec.push_back(pr.second.size() / elem_type_node_count.second);
2775 num_attr_edge_vec.push_back(0);
2792 exII::ex_block_params params = {};
2795 params.elem_blk_id = elem_blk_id.data();
2797 params.num_elem_this_blk = num_elem_this_blk_vec.data();
2798 params.num_nodes_per_elem = num_nodes_per_elem_vec.data();
2799 params.num_edges_per_elem = num_edges_per_elem_vec.data();
2800 params.num_faces_per_elem = num_faces_per_elem_vec.data();
2801 params.num_attr_elem = num_attr_vec.data();
2802 params.define_maps = 0;
2807 params.edge_blk_id = edge_blk_id.data();
2809 params.num_edge_this_blk = num_edge_this_blk_vec.data();
2810 params.num_nodes_per_edge = num_nodes_per_edge_vec.data();
2811 params.num_attr_edge = num_attr_edge_vec.data();
2814 ex_err = exII::ex_put_concat_all_blocks(
ex_id, ¶ms);
2815 EX_CHECK_ERR(
ex_err,
"Error writing element blocks.");
2818 unsigned libmesh_elem_num_to_exodus_counter = 0;
2822 auto num_elem_this_blk_it = num_elem_this_blk_vec.begin();
2825 for (
auto & [subdomain_id, element_id_vec] : subdomain_map)
2831 const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
2832 ElemType(subdomain_id - subdomain_id_end) :
2838 libmesh_not_implemented_msg(
"Support for Polygons/Polyhedra not yet implemented");
2842 if (subdomain_id < subdomain_id_end)
2848 unsigned int elem_id = element_id_vec[i];
2863 libmesh_error_msg_if(elem.
type() != conv.libmesh_elem_type(),
2864 "Error: Exodus requires all elements with a given subdomain ID to be the same type.\n" 2865 <<
"Can't write both " 2869 <<
" in the same block!");
2874 unsigned elem_node_index = conv.get_inverse_node_map(j);
2875 if (!use_discontinuous)
2885 cast_int<int>(libmesh_node_id));
2891 libmesh_map_find(discontinuous_node_indices,
2892 std::make_pair(elem_id, elem_node_index));
2902 curr_elem_map_end = std::transform
2903 (element_id_vec.begin(),
2904 element_id_vec.end(),
2914 libmesh_assert(num_elem_this_blk_it != num_elem_this_blk_vec.end());
2919 std::size_t connect_index = 0;
2920 for (
const auto & elem :
mesh.active_element_ptr_range())
2922 unsigned int local_node_index = elem->n_nodes();
2924 for (
auto s : elem->side_index_range())
2929 if (elem->side_type(s) != elem_t)
2932 const std::vector<unsigned int> side_nodes =
2933 elem->nodes_on_side(s);
2938 const int exodus_node_id = libmesh_map_find
2939 (discontinuous_node_indices,
2940 std::make_pair(elem->id(), local_node_index++));
2941 libmesh_assert_less(connect_index,
connect.size());
2942 connect[connect_index++] = exodus_node_id;
2947 auto old_curr_map_end = curr_elem_map_end;
2951 (old_curr_map_end, curr_elem_map_end,
2952 [&next_fake_id](){
return next_fake_id++;});
2955 ++num_elem_this_blk_it;
2957 ex_err = exII::ex_put_conn
2959 exII::EX_ELEM_BLOCK,
2964 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
2969 EX_CHECK_ERR(
ex_err,
"Error writing element map");
2975 EX_CHECK_ERR(
ex_err,
"Error writing element block names");
2979 for (
const auto & pr : edge_id_to_conn)
2981 ex_err = exII::ex_put_conn
2983 exII::EX_EDGE_BLOCK,
2988 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
2994 ex_err = exII::ex_put_names
2996 exII::EX_EDGE_BLOCK,
2998 EX_CHECK_ERR(
ex_err,
"Error writing edge block names");
3007 LOG_SCOPE(
"write_sidesets()",
"ExodusII_IO_Helper");
3013 std::map<int, std::vector<int>> elem_lists;
3014 std::map<int, std::vector<int>> side_lists;
3015 std::set<boundary_id_type> side_boundary_ids;
3022 std::vector<const Elem *> family;
3023 #ifdef LIBMESH_ENABLE_AMR 3033 for (
const auto & f : family)
3040 side_lists[std::get<2>(t)].push_back(conv.get_inverse_side_map(std::get<1>(t)));
3044 std::vector<boundary_id_type> tmp;
3046 side_boundary_ids.insert(tmp.begin(), tmp.end());
3055 std::vector<const Elem *> family;
3056 #ifdef LIBMESH_ENABLE_AMR 3066 for (
const auto & f : family)
3073 side_lists[std::get<2>(t)].push_back(conv.get_inverse_shellface_map(std::get<1>(t)));
3077 std::vector<boundary_id_type> tmp;
3079 side_boundary_ids.insert(tmp.begin(), tmp.end());
3084 side_boundary_ids.insert(pr.first);
3087 if (side_boundary_ids.size() > 0)
3089 NamesData names_table(side_boundary_ids.size(), MAX_STR_LENGTH);
3091 std::vector<exII::ex_set> sets(side_boundary_ids.size());
3094 for (
auto [i, it] = std::tuple{0u, side_boundary_ids.begin()}; i<sets.size(); ++i, ++it)
3100 sets[i].type = exII::EX_SIDE_SET;
3101 sets[i].num_distribution_factor = 0;
3102 sets[i].distribution_factor_list =
nullptr;
3104 if (
const auto elem_it = elem_lists.find(ss_id);
3105 elem_it == elem_lists.end())
3107 sets[i].num_entry = 0;
3108 sets[i].entry_list =
nullptr;
3109 sets[i].extra_list =
nullptr;
3113 sets[i].num_entry = elem_it->second.size();
3114 sets[i].entry_list = elem_it->second.data();
3115 sets[i].extra_list = libmesh_map_find(side_lists, ss_id).data();
3119 ex_err = exII::ex_put_sets(
ex_id, side_boundary_ids.size(), sets.data());
3120 EX_CHECK_ERR(
ex_err,
"Error writing sidesets");
3122 ex_err = exII::ex_put_names(
ex_id, exII::EX_SIDE_SET, names_table.get_char_star_star());
3123 EX_CHECK_ERR(
ex_err,
"Error writing sideset names");
3131 LOG_SCOPE(
"write_nodesets()",
"ExodusII_IO_Helper");
3148 std::stable_sort(bc_tuples.begin(), bc_tuples.end(),
3151 {
return std::get<1>(t1) < std::get<1>(t2); });
3153 std::vector<boundary_id_type> node_boundary_ids;
3161 if (std::find(node_boundary_ids.begin(),
3162 node_boundary_ids.end(), id)
3163 == node_boundary_ids.end())
3164 node_boundary_ids.push_back(
id);
3168 if (node_boundary_ids.size() > 0)
3170 NamesData names_table(node_boundary_ids.size(), MAX_STR_LENGTH);
3188 std::map<boundary_id_type, unsigned int> nodeset_counts;
3189 for (
auto id : node_boundary_ids)
3190 nodeset_counts[id] = 0;
3192 for (
const auto & t : bc_tuples)
3197 nodeset_counts[nodeset_id] += 1;
3201 unsigned int running_sum = 0;
3202 for (
const auto & pr : nodeset_counts)
3208 running_sum += pr.second;
3213 exII::ex_set_specs set_data = {};
3222 ex_err = exII::ex_put_concat_sets(
ex_id, exII::EX_NODE_SET, &set_data);
3223 EX_CHECK_ERR(
ex_err,
"Error writing concatenated nodesets");
3226 ex_err = exII::ex_put_names(
ex_id, exII::EX_NODE_SET, names_table.get_char_star_star());
3227 EX_CHECK_ERR(
ex_err,
"Error writing nodeset names");
3234 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
3240 if (names.size() == 0)
3263 for (
auto var_num :
index_range(vars_active_subdomains))
3267 std::set<subdomain_id_type> current_set;
3268 if (vars_active_subdomains[var_num].empty())
3270 current_set.insert(cast_int<subdomain_id_type>(block_id));
3272 current_set = vars_active_subdomains[var_num];
3275 for (
auto block_id : current_set)
3278 libmesh_error_msg_if(it ==
block_ids.end(),
3279 "ExodusII_IO_Helper: block id " << block_id <<
" not found in block_ids.");
3281 std::size_t block_index =
3284 std::size_t truth_tab_index = block_index*
num_elem_vars + var_num;
3285 truth_tab[truth_tab_index] = 1;
3289 ex_err = exII::ex_put_truth_table
3291 exII::EX_ELEM_BLOCK,
3295 EX_CHECK_ERR(
ex_err,
"Error writing element truth table.");
3306 if (names.size() == 0)
3334 if (names.size() == 0)
3355 std::vector<std::string> & names,
3356 std::vector<std::string> & names_from_file)
3370 std::equal(names.begin(), names.end(),
3371 names_from_file.begin(),
3372 [](
const std::string & a,
3373 const std::string & b) ->
bool 3375 return a.compare(0, MAX_STR_LENGTH, b) == 0;
3380 libMesh::err <<
"Error! The Exodus file already contains the variables:" << std::endl;
3381 for (
const auto &
name : names_from_file)
3384 libMesh::err <<
"And you asked to write:" << std::endl;
3385 for (
const auto &
name : names)
3388 libmesh_error_msg(
"Cannot overwrite existing variables in Exodus II file.");
3401 float cast_time = float(time);
3402 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
3406 double cast_time = double(time);
3407 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
3409 EX_CHECK_ERR(
ex_err,
"Error writing timestep.");
3419 LOG_SCOPE(
"write_elemsets()",
"ExodusII_IO_Helper");
3431 std::map<elemset_id_type, std::vector<int>> exodus_elemsets;
3433 unsigned int elemset_index =
3438 for (
const auto & elem :
mesh.element_ptr_range())
3441 elem->get_extra_integer(elemset_index);
3453 for (
const auto & set_id : set_ids)
3467 if (!exodus_elemsets.empty())
3473 std::vector<exII::ex_set> sets;
3474 sets.reserve(exodus_elemsets.size());
3476 for (
auto & [elem_set_id, ids_vec] : exodus_elemsets)
3481 exII::ex_set & current_set = sets.emplace_back();
3482 current_set.id = elem_set_id;
3483 current_set.type = exII::EX_ELEM_SET;
3484 current_set.num_entry = ids_vec.size();
3485 current_set.num_distribution_factor = 0;
3486 current_set.entry_list = ids_vec.data();
3487 current_set.extra_list =
nullptr;
3488 current_set.distribution_factor_list =
nullptr;
3493 libmesh_assert_msg(
num_elem_sets == cast_int<int>(exodus_elemsets.size()),
3494 "Mesh has " << exodus_elemsets.size()
3495 <<
" elemsets, but header was written with num_elem_sets == " <<
num_elem_sets);
3498 <<
", but header was written with num_elem_sets == " <<
num_elem_sets);
3500 ex_err = exII::ex_put_sets(
ex_id, exodus_elemsets.size(), sets.data());
3501 EX_CHECK_ERR(
ex_err,
"Error writing elemsets");
3516 const std::vector<std::string> & var_names,
3517 const std::vector<std::set<boundary_id_type>> & side_ids,
3518 const std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
3520 LOG_SCOPE(
"write_sideset_data()",
"ExodusII_IO_Helper");
3546 std::vector<int> sset_var_tab(
num_side_sets * var_names.size());
3565 if (!side_ids[var].count(
ss_ids[ss]))
3569 sset_var_tab[ss*var_names.size() + var] = 1;
3575 const auto & data_map = bc_vals[var];
3598 libmesh_error_msg_if
3600 cast_int<dof_id_type>(
elem_list[i + offset]),
3601 "Error mapping Exodus elem id to libmesh elem id.");
3619 sset_var_vals[i] = libmesh_map_find(data_map, key);
3625 if (sset_var_vals.size() > 0)
3627 ex_err = exII::ex_put_var
3635 EX_CHECK_ERR(
ex_err,
"Error writing sideset vars.");
3642 exII::ex_put_truth_table(
ex_id,
3645 cast_int<int>(var_names.size()),
3646 sset_var_tab.data());
3647 EX_CHECK_ERR(
ex_err,
"Error writing sideset var truth table.");
3656 std::vector<std::string> & var_names,
3657 std::vector<std::set<boundary_id_type>> & side_ids,
3658 std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
3660 LOG_SCOPE(
"read_sideset_data()",
"ExodusII_IO_Helper");
3670 ex_err = exII::ex_get_truth_table
3675 sset_var_tab.data());
3676 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable truth table.");
3705 side_ids[var].insert(
ss_ids[ss]);
3711 ex_err = exII::ex_get_var
3719 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable.");
3724 unsigned int exodus_side_id =
side_list[i + offset];
3729 dof_id_type converted_elem_id = exodus_elem_id - 1;
3738 unsigned int converted_side_id = conv.
get_side_map(exodus_side_id - 1);
3747 bc_vals[var].emplace(key, sset_var_vals[i]);
3759 std::map<BoundaryInfo::BCTuple, unsigned int> & bc_array_indices)
3762 bc_array_indices.clear();
3776 unsigned int exodus_side_id =
side_list[i + offset];
3781 dof_id_type converted_elem_id = exodus_elem_id - 1;
3789 unsigned int converted_side_id = conv.
get_side_map(exodus_side_id - 1);
3798 bc_array_indices.emplace(key, cast_int<unsigned int>(i));
3807 const std::vector<std::string> & var_names,
3808 const std::vector<std::set<boundary_id_type>> & node_boundary_ids,
3809 const std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals)
3811 LOG_SCOPE(
"write_nodeset_data()",
"ExodusII_IO_Helper");
3835 std::vector<int> nset_var_tab(
num_node_sets * var_names.size());
3847 if (!node_boundary_ids[var].count(
nodeset_ids[ns]))
3851 nset_var_tab[ns*var_names.size() + var] = 1;
3857 const auto & data_map = bc_vals[var];
3871 std::make_tuple(libmesh_node_id,
nodeset_ids[ns]);
3878 nset_var_vals[i] = libmesh_map_find(data_map, key);
3882 if (nset_var_vals.size() > 0)
3884 ex_err = exII::ex_put_var
3892 EX_CHECK_ERR(
ex_err,
"Error writing nodeset vars.");
3899 exII::ex_put_truth_table(
ex_id,
3902 cast_int<int>(var_names.size()),
3903 nset_var_tab.data());
3904 EX_CHECK_ERR(
ex_err,
"Error writing nodeset var truth table.");
3912 const std::vector<std::string> & var_names,
3913 const std::vector<std::set<elemset_id_type>> & elemset_ids_in,
3914 const std::vector<std::map<std::pair<dof_id_type, elemset_id_type>,
Real>> & elemset_vals)
3916 LOG_SCOPE(
"write_elemset_data()",
"ExodusII_IO_Helper");
3945 std::vector<int> elemset_var_tab(
num_elem_sets * var_names.size());
3971 elemset_var_tab[es*var_names.size() + var] = 1;
3977 const auto & data_map = elemset_vals[var];
3990 std::pair<dof_id_type, elemset_id_type> key =
4001 elemset_var_vals[i] = libmesh_map_find(data_map, key);
4005 if (elemset_var_vals.size() > 0)
4007 ex_err = exII::ex_put_var
4015 EX_CHECK_ERR(
ex_err,
"Error writing elemset vars.");
4022 exII::ex_put_truth_table(
ex_id,
4025 cast_int<int>(var_names.size()),
4026 elemset_var_tab.data());
4027 EX_CHECK_ERR(
ex_err,
"Error writing elemset var truth table.");
4035 std::vector<std::string> & var_names,
4036 std::vector<std::set<elemset_id_type>> & elemset_ids_in,
4037 std::vector<std::map<std::pair<dof_id_type, elemset_id_type>,
Real>> & elemset_vals)
4039 LOG_SCOPE(
"read_elemset_data()",
"ExodusII_IO_Helper");
4060 exII::ex_get_truth_table(
ex_id,
4064 elemset_var_tab.data());
4065 EX_CHECK_ERR(
ex_err,
"Error reading elemset variable truth table.");
4108 ex_err = exII::ex_get_var
4116 EX_CHECK_ERR(
ex_err,
"Error reading elemset variable.");
4125 dof_id_type converted_elem_id = exodus_elem_id - 1;
4128 auto key = std::make_pair(converted_elem_id,
4132 elemset_vals[var].emplace(key, elemset_var_vals[i]);
4146 elemset_array_indices.clear();
4170 dof_id_type converted_elem_id = exodus_elem_id - 1;
4174 auto key = std::make_pair(converted_elem_id,
4178 elemset_array_indices.emplace(key, cast_int<unsigned int>(i));
4187 std::vector<std::string> & var_names,
4188 std::vector<std::set<boundary_id_type>> & node_boundary_ids,
4189 std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals)
4191 LOG_SCOPE(
"read_nodeset_data()",
"ExodusII_IO_Helper");
4201 ex_err = exII::ex_get_truth_table
4206 nset_var_tab.data());
4207 EX_CHECK_ERR(
ex_err,
"Error reading nodeset variable truth table.");
4243 ex_err = exII::ex_get_var
4251 EX_CHECK_ERR(
ex_err,
"Error reading nodeset variable.");
4266 dof_id_type converted_node_id = exodus_node_id - 1;
4273 bc_vals[var].emplace(key, nset_var_vals[i]);
4288 bc_array_indices.clear();
4317 dof_id_type converted_node_id = exodus_node_id - 1;
4324 bc_array_indices.emplace(key, cast_int<unsigned int>(i));
4331 const std::vector<Real> & values,
4333 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
4335 LOG_SCOPE(
"write_element_values()",
"ExodusII_IO_Helper");
4342 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
4347 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
4348 for (
const auto & elem :
mesh.active_element_ptr_range())
4349 subdomain_map[elem->subdomain_id()].push_back(elem->id());
4358 libmesh_assert_equal_to
4359 (vars_active_subdomains.size(),
4365 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
4368 auto it = subdomain_map.begin();
4371 const auto & active_subdomains
4372 = vars_active_subdomains[var_id];
4374 for (
unsigned int j=0; it!=subdomain_map.end(); ++it, ++j)
4379 if (!(active_subdomains.empty() || active_subdomains.count(it->first)))
4385 const auto & elem_nums = it->second;
4386 const unsigned int num_elems_this_block =
4387 cast_int<unsigned int>(elem_nums.size());
4388 std::vector<Real> data(num_elems_this_block);
4393 for (
unsigned int k=0; k<num_elems_this_block; ++k)
4394 data[k] = values[var_id*
n_elem + elem_nums[k]];
4396 ex_err = exII::ex_put_var
4399 exII::EX_ELEM_BLOCK,
4402 num_elems_this_block,
4405 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
4416 const std::vector<Real> & values,
4418 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
4419 const std::vector<std::string> & derived_var_names,
4420 const std::map<
subdomain_id_type, std::vector<std::string>> & subdomain_to_var_names)
4427 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
4434 std::map<subdomain_id_type, unsigned int> subdomain_to_n_elem;
4435 for (
const auto & elem :
mesh.active_element_ptr_range())
4436 subdomain_to_n_elem[elem->subdomain_id()] += 1;
4440 libmesh_assert_equal_to
4441 (vars_active_subdomains.size(),
4445 auto subdomain_to_n_elem_iter = subdomain_to_n_elem.begin();
4451 (
mesh.active_elements_begin(),
4452 mesh.active_elements_end());
4454 for (
unsigned int sbd_idx=0;
4455 subdomain_to_n_elem_iter != subdomain_to_n_elem.end();
4456 ++subdomain_to_n_elem_iter, ++sbd_idx)
4457 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
4460 const auto & active_subdomains
4461 = vars_active_subdomains[var_id];
4468 if (!active_subdomains.count(subdomain_to_n_elem_iter->first))
4472 std::vector<Real> data;
4473 data.reserve(subdomain_to_n_elem_iter->second);
4475 unsigned int values_offset = 0;
4476 for (
auto & elem : elem_range)
4483 auto subdomain_to_var_names_iter =
4484 subdomain_to_var_names.find(sbd_id);
4492 if (subdomain_to_var_names_iter == subdomain_to_var_names.end())
4495 const auto & var_names_this_sbd
4496 = subdomain_to_var_names_iter->second;
4499 if (sbd_id == subdomain_to_n_elem_iter->first)
4507 std::find(var_names_this_sbd.begin(),
4508 var_names_this_sbd.end(),
4509 derived_var_names[var_id]);
4511 libmesh_error_msg_if(pos == var_names_this_sbd.end(),
4512 "Derived name " << derived_var_names[var_id] <<
" not found!");
4519 data.push_back(values[values_offset + true_index]);
4524 auto true_offset = var_names_this_sbd.size();
4527 values_offset += true_offset;
4533 ex_err = exII::ex_put_var
4536 exII::EX_ELEM_BLOCK,
4542 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
4553 const std::vector<Real> & values,
4559 if (!values.empty())
4561 libmesh_assert_equal_to(values.size(), std::size_t(
num_nodes));
4563 ex_err = exII::ex_put_var
4572 EX_CHECK_ERR(
ex_err,
"Error writing nodal values.");
4589 int num_info = inquire(*
this, exII::EX_INQ_INFO,
"Error retrieving the number of information records from file!");
4592 libMesh::err <<
"Warning! The Exodus file already contains information records.\n" 4593 <<
"Exodus does not support writing additional records in this situation." 4598 int num_records = cast_int<int>(records.size());
4600 if (num_records > 0)
4606 for (
const auto & record : records)
4607 info.push_back_entry(record);
4609 ex_err = exII::ex_put_info(
ex_id, num_records,
info.get_char_star_star());
4610 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
4623 if (!values.empty())
4625 ex_err = exII::ex_put_var
4634 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
4645 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
4657 ex_err = exII::ex_get_var
4666 EX_CHECK_ERR(
ex_err,
"Error reading global values.");
4698 std::vector<std::string>
4700 bool write_complex_abs)
const 4702 std::vector<std::string> complex_names;
4706 for (
const auto &
name : names)
4708 complex_names.push_back(
"r_" +
name);
4709 complex_names.push_back(
"i_" +
name);
4710 if (write_complex_abs)
4711 complex_names.push_back(
"a_" +
name);
4714 return complex_names;
4719 std::vector<std::set<subdomain_id_type>>
4722 (
const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
4723 bool write_complex_abs)
const 4725 std::vector<std::set<subdomain_id_type>> complex_vars_active_subdomains;
4727 for (
auto & s : vars_active_subdomains)
4731 complex_vars_active_subdomains.push_back(s);
4732 complex_vars_active_subdomains.push_back(s);
4733 if (write_complex_abs)
4734 complex_vars_active_subdomains.push_back(s);
4737 return complex_vars_active_subdomains;
4742 std::map<subdomain_id_type, std::vector<std::string>>
4746 bool write_complex_abs)
const 4749 std::map<subdomain_id_type, std::vector<std::string>> ret;
4751 unsigned int num_complex_outputs = write_complex_abs ? 3 : 2;
4753 for (
const auto & pr : subdomain_to_var_names)
4756 auto & vec = ret[pr.first];
4759 const auto & varnames = pr.second;
4762 vec.reserve(num_complex_outputs * varnames.size());
4767 for (
const auto & varname : varnames)
4769 vec.push_back(
"r_" + varname);
4770 vec.push_back(
"i_" + varname);
4771 if (write_complex_abs)
4772 vec.push_back(
"a_" + varname);
4785 libmesh_assert_less (i, node_map->size());
4786 return (*node_map)[i];
4793 if (!inverse_node_map)
4796 libmesh_assert_less (i, inverse_node_map->size());
4797 return (*inverse_node_map)[i];
4809 if (static_cast<size_t>(i) >= side_map->size())
4812 return (*side_map)[i];
4820 if (!inverse_side_map)
4823 libmesh_assert_less (i, inverse_side_map->size());
4824 return (*inverse_side_map)[i];
4838 libmesh_assert_less (i, shellface_map->size());
4839 return (*shellface_map)[i];
4846 if (!inverse_shellface_map)
4849 libmesh_assert_less (i, inverse_shellface_map->size());
4850 return (*inverse_shellface_map)[i];
4857 return libmesh_type;
4874 return shellface_index_offset;
4878 data_table(n_strings),
4879 data_table_pointers(n_strings),
4881 table_size(n_strings)
4883 for (
size_t i=0; i<n_strings; ++i)
4899 libmesh_assert_less (counter, table_size);
4902 size_t num_copied =
name.copy(data_table[counter].data(), data_table[counter].size()-1);
4905 data_table[counter][num_copied] =
'\0';
4915 return data_table_pointers.data();
4922 libmesh_error_msg_if(static_cast<unsigned>(i) >= table_size,
4923 "Requested char * " << i <<
" but only have " << table_size <<
"!");
4925 return data_table[i].data();
4934 #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