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>
57#include <unordered_map>
66static constexpr int libmesh_max_str_length = MAX_LINE_LENGTH;
73const std::vector<int> trishell3_inverse_edge_map = {3, 4, 5};
74const std::vector<int> quadshell4_inverse_edge_map = {3, 4, 5, 6};
80const std::vector<int> hex27_node_map = {
82 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
84 21, 25, 24, 26, 23, 22, 20};
87const std::vector<int> hex27_inverse_node_map = {
89 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
91 26, 20, 25, 24, 22, 21, 23};
94const std::vector<int> prism20_node_map = {
98 6, 7, 8, 9, 10, 11, 12, 13, 14,
103const std::vector<int> prism20_inverse_node_map = {
107 6, 7, 8, 9, 10, 11, 12, 13, 14,
112const std::vector<int> prism21_node_map = {
116 6, 7, 8, 9, 10, 11, 12, 13, 14,
118 20, 18, 19, 16, 17, 15};
121const std::vector<int> prism21_inverse_node_map = {
125 6, 7, 8, 9, 10, 11, 12, 13, 14,
127 20, 18, 19, 16, 17, 15};
130const std::vector<int> tet14_node_map = {
132 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
137const std::vector<int> tet14_inverse_node_map = {
139 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
146const std::vector<int> tet_face_map = {1, 2, 3, 0};
147const std::vector<int> hex_face_map = {1, 2, 3, 4, 0, 5};
148const std::vector<int> prism_face_map = {1, 2, 3, 0, 4};
151const std::vector<int> tet_inverse_face_map = {4, 1, 2, 3};
152const std::vector<int> hex_inverse_face_map = {5, 1, 2, 3, 4, 6};
153const std::vector<int> prism_inverse_face_map = {4, 1, 2, 3, 5};
174 float ret_float = 0.;
182 EX_CHECK_ERR(e2h.
ex_err, error_msg);
189 inline bool is_bezier_elem(
const char * elem_type_str)
192#if EX_API_VERS_NODOT < 800
196 if (strlen(elem_type_str) <= 4)
198 return (std::string(elem_type_str, elem_type_str+4) ==
"BEX_");
203 std::map<subdomain_id_type, std::vector<unsigned int>>
217 auto for_each_elem = [&
mesh, reduce](
auto && f)
220 for (
const auto & elem :
mesh.active_local_element_ptr_range())
223 for (
const auto & elem :
mesh.active_element_ptr_range())
233 std::map<ElemType, std::vector<unsigned int>>> elems_by_subdomain_type;
240 std::vector<dof_id_type> elem_ids;
241 std::vector<subdomain_id_type> elem_sbd_ids;
243 for_each_elem([&](
const Elem & elem)
247 elem_ids.push_back(elem.
id());
264 for (
auto & [sbd_id, type_map] : elems_by_subdomain_type)
267 for (
auto & [elem_t, ids] : type_map)
270 std::sort(ids.begin(), ids.end());
275 for_each_elem([&](
const Elem & elem)
288 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
290 0 : elems_by_subdomain_type.rbegin()->first + 1;
292 for (
auto & [sbd_id, type_map] : elems_by_subdomain_type)
294 bool first_type =
true;
295 for (
auto & [elem_t, elem_ids] : type_map)
299 first_type ? sbd_id : next_synth_block_id++;
302 subdomain_map[block_id] = std::move(elem_ids);
308 if (!subdomain_map.empty())
309 subdomain_id_end = subdomain_map.rbegin()->first + 1;
317 std::map<subdomain_id_type, unsigned int> side_block_counts;
318 for_each_elem([&](
const Elem & elem)
323 for (
auto s : elem.side_index_range())
329 cast_int<subdomain_id_type>(subdomain_id_end + elem.
side_type(s));
334 libmesh_assert_greater_equal(side_block_id, subdomain_id_end);
336 ++side_block_counts[side_block_id];
343 for (
const auto & [side_block_id, count] : side_block_counts)
344 subdomain_map[side_block_id] = {count};
347 return subdomain_map;
361 bool run_only_on_proc0,
362 bool single_precision) :
367 title(header_info.title),
368 num_dim(header_info.num_dim),
369 num_nodes(header_info.num_nodes),
370 num_elem(header_info.num_elem),
371 num_elem_blk(header_info.num_elem_blk),
372 num_edge(header_info.num_edge),
373 num_edge_blk(header_info.num_edge_blk),
374 num_face(header_info.num_face),
375 num_face_blk(header_info.num_face_blk),
376 num_node_sets(header_info.num_node_sets),
377 num_side_sets(header_info.num_side_sets),
378 num_elem_sets(header_info.num_elem_sets),
383 num_elem_this_blk(0),
384 num_nodes_per_elem(0),
386 num_elem_all_sidesets(0),
387 num_elem_all_elemsets(0),
393 set_unique_ids_from_maps(false),
394 opened_for_writing(false),
395 opened_for_reading(false),
396 _run_only_on_proc0(run_only_on_proc0),
397 _opened_by_create(false),
398 _elem_vars_initialized(false),
399 _global_vars_initialized(false),
400 _nodal_vars_initialized(false),
401 _use_mesh_dimension_instead_of_spatial_dimension(false),
403 _max_name_length(32),
405 _write_as_dimension(0),
406 _single_precision(single_precision)
408 title.resize(MAX_LINE_LENGTH+1);
409 elem_type.resize(libmesh_max_str_length);
422 return EX_API_VERS_NODOT;
430 auto convert_type = [
this](
ElemType type,
431 std::string_view exodus_type,
432 const std::vector<int> * node_map =
nullptr,
433 const std::vector<int> * inverse_node_map =
nullptr,
434 const std::vector<int> * side_map =
nullptr,
435 const std::vector<int> * inverse_side_map =
nullptr,
436 const std::vector<int> * shellface_map =
nullptr,
437 const std::vector<int> * inverse_shellface_map =
nullptr,
438 size_t shellface_index_offset = 0)
442 conv.libmesh_type = type;
443 conv.exodus_type = exodus_type;
444 conv.node_map = node_map;
445 conv.inverse_node_map = inverse_node_map;
446 conv.side_map = side_map;
447 conv.inverse_side_map = inverse_side_map;
448 conv.shellface_map = shellface_map;
449 conv.inverse_shellface_map = inverse_shellface_map;
450 conv.shellface_index_offset = shellface_index_offset;
451 conv.n_nodes = elem->n_nodes();
452 for (
int d = elem->dim()+1; d <= 3; ++d)
457 convert_type(
EDGE2,
"EDGE2");
458 convert_type(
EDGE3,
"EDGE3");
459 convert_type(
EDGE4,
"EDGE4");
460 convert_type(
QUAD4,
"QUAD4");
461 convert_type(
QUAD8,
"QUAD8");
462 convert_type(
QUAD9,
"QUAD9");
467 conv.exodus_type =
"NFACED";
471 convert_type(
QUADSHELL4,
"SHELL4",
nullptr,
nullptr,
nullptr,
472 &quadshell4_inverse_edge_map,
473 nullptr,
nullptr, 2);
474 convert_type(
QUADSHELL8,
"SHELL8",
nullptr,
nullptr,
nullptr,
475 &quadshell4_inverse_edge_map,
476 nullptr,
nullptr, 2);
477 convert_type(
QUADSHELL9,
"SHELL9",
nullptr,
nullptr,
nullptr,
478 &quadshell4_inverse_edge_map,
479 nullptr,
nullptr, 2);
481 convert_type(
TRI3,
"TRI3");
482 convert_type(
TRI6,
"TRI6");
483 convert_type(
TRI7,
"TRI7");
493 convert_type(
TRISHELL3,
"TRISHELL3",
nullptr,
nullptr,
nullptr,
494 &trishell3_inverse_edge_map,
495 nullptr,
nullptr, 2);
497 convert_type(
HEX8,
"HEX8",
nullptr,
nullptr,
498 &hex_face_map, &hex_inverse_face_map);
499 convert_type(
HEX20,
"HEX20",
nullptr,
nullptr,
500 &hex_face_map, &hex_inverse_face_map);
501 convert_type(
HEX27,
"HEX27", &hex27_node_map,
502 &hex27_inverse_node_map,
503 &hex_face_map, &hex_inverse_face_map);
504 convert_type(
TET4,
"TETRA4",
nullptr,
nullptr,
505 &tet_face_map, &tet_inverse_face_map);
506 convert_type(
TET10,
"TETRA10",
nullptr,
nullptr,
507 &tet_face_map, &tet_inverse_face_map);
508 convert_type(
TET14,
"TETRA14", &tet14_node_map,
509 &tet14_inverse_node_map,
510 &tet_face_map, &tet_inverse_face_map);
511 convert_type(
PRISM6,
"WEDGE",
nullptr,
nullptr,
512 &prism_face_map, &prism_inverse_face_map);
513 convert_type(
PRISM15,
"WEDGE15",
nullptr,
nullptr,
514 &prism_face_map, &prism_inverse_face_map);
515 convert_type(
PRISM18,
"WEDGE18",
nullptr,
nullptr,
516 &prism_face_map, &prism_inverse_face_map);
517 convert_type(
PRISM20,
"WEDGE20", &prism20_node_map,
518 &prism20_inverse_node_map,
519 &prism_face_map, &prism_inverse_face_map);
520 convert_type(
PRISM21,
"WEDGE21", &prism21_node_map,
521 &prism21_inverse_node_map,
522 &prism_face_map, &prism_inverse_face_map);
663 return libmesh_map_find(maps_for_dim, type);
670 std::transform(type_str.begin(), type_str.end(), type_str.begin(), ::toupper);
696 bool single_precision_in)
697 : our_data(our_data_in),
698 single_precision(single_precision_in)
702 if (
sizeof(
Real) !=
sizeof(
float))
711 else if (
sizeof(
Real) !=
sizeof(double))
723 if (single_precision)
725 if (
sizeof(
Real) !=
sizeof(
float))
726 return static_cast<void*
>(float_vec.data());
729 else if (
sizeof(
Real) !=
sizeof(double))
730 return static_cast<void*
>(double_vec.data());
733 return const_cast<void *
>(
static_cast<const void *
>(our_data.data()));
738 bool single_precision_in)
739 : our_data(our_data_in),
740 single_precision(single_precision_in)
745 if (
sizeof(
Real) !=
sizeof(
float))
748 else if (
sizeof(
Real) !=
sizeof(
double))
755 if (single_precision)
757 if (
sizeof(
Real) !=
sizeof(
float))
758 our_data.assign(float_vec.begin(), float_vec.end());
760 else if (
sizeof(
Real) !=
sizeof(
double))
761 our_data.assign(double_vec.begin(), double_vec.end());
767 if (single_precision)
769 if (
sizeof(
Real) !=
sizeof(
float))
770 return static_cast<void*
>(float_vec.data());
773 else if (
sizeof(
Real) !=
sizeof(double))
774 return static_cast<void*
>(double_vec.data());
777 return static_cast<void *
>(our_data.data());
783 float ex_version = 0.;
788 comp_ws = cast_int<int>(
sizeof(
float));
793 comp_ws = cast_int<int>(std::min(
sizeof(
Real),
sizeof(
double)));
802 ex_id = exII::ex_open(filename,
803 read_only ? EX_READ : EX_WRITE,
809 std::string err_msg = std::string(
"Error opening ExodusII mesh file: ") + std::string(filename);
810 EX_CHECK_ERR(
ex_id, err_msg);
827 int max_name_length = exII::ex_inquire_int(
ex_id, exII::EX_INQ_DB_MAX_USED_NAME_LENGTH);
829 libmesh_error_msg_if(max_name_length > MAX_LINE_LENGTH,
830 "Unexpected maximum name length of " <<
831 max_name_length <<
" in file " << filename <<
832 " exceeds expected " << MAX_LINE_LENGTH);
836 max_name_length_to_set = std::max(max_name_length, 32);
841 ex_err = exII::ex_set_max_name_length(
ex_id, max_name_length_to_set);
842 EX_CHECK_ERR(
ex_err,
"Error setting max ExodusII name length.");
857 exII::ex_init_params params = {};
858 int err_flag = exII::ex_get_init_ext(
ex_id, ¶ms);
859 EX_CHECK_ERR(err_flag,
"Error retrieving header info.");
863 h.
title.assign(params.title, params.title + MAX_LINE_LENGTH);
893 EX_CHECK_ERR(
ex_err,
"Error reading number of nodal variables.");
896 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
899 EX_CHECK_ERR(
ex_err,
"Error reading number of global variables.");
902 EX_CHECK_ERR(
ex_err,
"Error reading number of sideset variables.");
905 EX_CHECK_ERR(
ex_err,
"Error reading number of nodeset variables.");
908 EX_CHECK_ERR(
ex_err,
"Error reading number of elemset variables.");
910 message(
"Exodus header info retrieved successfully.");
920 inquire(*
this, exII::EX_INQ_QA,
"Error retrieving number of QA records");
925 <<
" QA record(s) in the Exodus file."
934 std::vector<std::vector<std::vector<char>>> qa_storage(num_qa_rec);
937 qa_storage[i].resize(4);
939 qa_storage[i][j].resize(libmesh_max_str_length+1);
943 typedef char * inner_array_t[4];
950 auto qa_record = std::make_unique<inner_array_t[]>(num_qa_rec);
956 qa_record[i][j] = qa_storage[i][j].data();
959 EX_CHECK_ERR(
ex_err,
"Error reading the QA records.");
981 <<
"Mesh Dimension: \t" <<
num_dim << std::endl
982 <<
"Number of Nodes: \t" <<
num_nodes << std::endl
983 <<
"Number of elements: \t" <<
num_elem << std::endl
984 <<
"Number of elt blocks: \t" <<
num_elem_blk << std::endl
994 LOG_SCOPE(
"read_nodes()",
"ExodusII_IO_Helper");
1002 ex_err = exII::ex_get_coord
1008 EX_CHECK_ERR(
ex_err,
"Error retrieving nodal data.");
1009 message(
"Nodal data retrieved successfully.");
1014 int n_nodal_attr = 0;
1015 ex_err = exII::ex_get_attr_param(
ex_id, exII::EX_NODAL, 0, & n_nodal_attr);
1016 EX_CHECK_ERR(
ex_err,
"Error getting number of nodal attributes.");
1018 if (n_nodal_attr > 0)
1020 std::vector<std::vector<char>> attr_name_data
1021 (n_nodal_attr, std::vector<char>(libmesh_max_str_length + 1));
1022 std::vector<char *> attr_names(n_nodal_attr);
1024 attr_names[i] = attr_name_data[i].data();
1026 ex_err = exII::ex_get_attr_names(
ex_id, exII::EX_NODAL, 0, attr_names.data());
1027 EX_CHECK_ERR(
ex_err,
"Error getting nodal attribute names.");
1030 if (std::string(
"bex_weight") == attr_names[i])
1034 exII::ex_get_one_attr (
ex_id, exII::EX_NODAL, 0, i+1,
1036 EX_CHECK_ERR(
ex_err,
"Error getting Bezier Extraction nodal weights");
1051 ex_err = exII::ex_get_node_num_map
1054 EX_CHECK_ERR(
ex_err,
"Error retrieving nodal number map.");
1055 message(
"Nodal numbering map retrieved successfully.");
1060 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_nodes-1)); ++i)
1073#if EX_API_VERS_NODOT >= 800
1074 int n_blobs = exII::ex_inquire_int(
ex_id, exII::EX_INQ_BLOB);
1078 std::vector<exII::ex_blob> blobs(n_blobs);
1079 std::vector<std::vector<char>> blob_names(n_blobs);
1082 blob_names[i].resize(libmesh_max_str_length+1);
1083 blobs[i].name = blob_names[i].data();
1087 EX_CHECK_ERR(
ex_err,
"Error getting blobs.");
1089 bool found_blob =
false;
1090 const exII::ex_blob * my_blob = &blobs[0];
1091 for (
const auto & blob : blobs)
1093 if (std::string(
"bex_cv_blob") == blob.name)
1101 libmesh_error_msg(
"Found no bex_cv_blob for bezier elements");
1103 const int n_blob_attr =
1104 exII::ex_get_attribute_count(
ex_id, exII::EX_BLOB,
1107 std::vector<exII::ex_attribute> attributes(n_blob_attr);
1108 ex_err = exII::ex_get_attribute_param(
ex_id, exII::EX_BLOB,
1111 EX_CHECK_ERR(
ex_err,
"Error getting bex blob attribute parameters.");
1113 int bex_num_dense_cv_blocks = 0;
1114 std::vector<int> bex_dense_cv_info;
1115 for (
auto & attr : attributes)
1117 if (std::string(
"bex_dense_cv_info") == attr.name)
1119 const std::size_t value_count = attr.value_count;
1120 if (value_count % 2)
1121 libmesh_error_msg(
"Found odd number of bex_dense_cv_info");
1123 bex_dense_cv_info.resize(value_count);
1124 attr.values = bex_dense_cv_info.data();
1125 exII::ex_get_attribute(
ex_id, &attr);
1127 bex_num_dense_cv_blocks = value_count / 2;
1129 libmesh_error_msg_if(bex_num_dense_cv_blocks > 1,
1130 "Found more than 1 dense bex CV block; unsure how to handle that");
1134 if (bex_dense_cv_info.empty())
1135 libmesh_error_msg(
"No bex_dense_cv_info found");
1138 exII::ex_get_variable_param(
ex_id, exII::EX_BLOB, &n_blob_vars);
1139 std::vector<char> var_name (libmesh_max_str_length + 1);
1140 for (
auto v_id :
make_range(1,n_blob_vars+1))
1142 ex_err = exII::ex_get_variable_name(
ex_id, exII::EX_BLOB, v_id, var_name.data());
1143 EX_CHECK_ERR(
ex_err,
"Error reading bex blob var name.");
1145 if (std::string(
"bex_dense_cv_blocks") == var_name.data())
1147 std::vector<double> bex_dense_cv_blocks(my_blob->num_entry);
1149 ex_err = exII::ex_get_var(
ex_id, 1, exII::EX_BLOB, v_id,
1150 my_blob->id, my_blob->num_entry,
1151 bex_dense_cv_blocks.data());
1152 EX_CHECK_ERR(
ex_err,
"Error reading bex_dense_cv_blocks.");
1157 std::size_t offset = 0;
1161 const int vecsize = bex_dense_cv_info[2*i+1];
1164 vec.resize(vecsize);
1165 std::copy(std::next(bex_dense_cv_blocks.begin(), offset),
1166 std::next(bex_dense_cv_blocks.begin(), offset + vecsize),
1182 out_stream <<
"(" <<
x[i] <<
", " <<
y[i] <<
", " <<
z[i] <<
")" << std::endl;
1194 exII::EX_ELEM_BLOCK,
1197 EX_CHECK_ERR(
ex_err,
"Error getting block IDs.");
1198 message(
"All block IDs retrieved successfully.");
1200 char name_buffer[libmesh_max_str_length+1];
1203 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_BLOCK,
1205 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
1208 message(
"All block names retrieved successfully.");
1216 exII::EX_EDGE_BLOCK,
1219 EX_CHECK_ERR(
ex_err,
"Error getting edge block IDs.");
1220 message(
"All edge block IDs retrieved successfully.");
1223 char name_buffer[libmesh_max_str_length+1];
1226 ex_err = exII::ex_get_name(
ex_id, exII::EX_EDGE_BLOCK,
1228 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
1231 message(
"All edge block names retrieved successfully.");
1239 libmesh_assert_less (index,
block_ids.size());
1248 libmesh_assert_less (index,
block_ids.size());
1257 libmesh_assert_less (index,
ss_ids.size());
1266 libmesh_assert_less (index,
ss_ids.size());
1292 LOG_SCOPE(
"read_face_blocks()",
"ExodusII_IO_Helper");
1298 "Error: Exodus NFACED element block found, "
1299 "but the file has no face blocks.");
1303 exII::EX_FACE_BLOCK,
1304 face_block_ids.data());
1305 EX_CHECK_ERR(
ex_err,
"Error getting face block IDs.");
1312 std::vector<char> face_type(libmesh_max_str_length+1);
1313 int num_face_this_blk = 0;
1314 int num_node_data_this_blk = 0;
1315 int num_edges_per_face = 0;
1316 int num_faces_per_face = 0;
1317 int num_attr_face = 0;
1320 exII::EX_FACE_BLOCK,
1321 face_block_ids[block],
1324 &num_node_data_this_blk,
1325 &num_edges_per_face,
1326 &num_faces_per_face,
1328 EX_CHECK_ERR(
ex_err,
"Error getting face block info.");
1330 const auto & conv =
get_conversion(std::string(face_type.data()));
1331 libmesh_error_msg_if(conv.libmesh_elem_type() !=
C0POLYGON,
1332 "Error: NFACED polyhedron input currently expects "
1333 "NSIDED face blocks, but face block "
1334 << face_block_ids[block] <<
" has Exodus type "
1335 << face_type.data() <<
".");
1337 libmesh_error_msg_if
1338 (!(num_edges_per_face == 0) && !(num_edges_per_face == -1),
1339 "Error: Exodus NSIDED face block "
1340 << face_block_ids[block]
1341 <<
" has edge connectivity, which NFACED polyhedron input "
1342 <<
"does not currently support.");
1343 libmesh_error_msg_if
1344 (!(num_faces_per_face == 0) && !(num_faces_per_face == -1),
1345 "Error: Exodus NSIDED face block "
1346 << face_block_ids[block]
1347 <<
" has face-in-face connectivity, which NFACED polyhedron "
1348 <<
"input does not currently support.");
1350 std::vector<int> face_node_counts(num_face_this_blk);
1351 if (!face_node_counts.empty())
1353 ex_err = exII::ex_get_entity_count_per_polyhedra
1355 exII::EX_FACE_BLOCK,
1356 face_block_ids[block],
1357 face_node_counts.data());
1358 EX_CHECK_ERR(
ex_err,
"Error reading polyhedron face node counts");
1361 int counted_nodes = 0;
1362 for (
const auto count : face_node_counts)
1363 counted_nodes += count;
1365 libmesh_error_msg_if(counted_nodes != num_node_data_this_blk,
1366 "Error: Exodus NSIDED face block "
1367 << face_block_ids[block]
1368 <<
" says it has " << num_node_data_this_blk
1369 <<
" total node entries, but its per-face "
1370 <<
"node counts sum to " << counted_nodes <<
".");
1372 std::vector<int> face_connect(num_node_data_this_blk);
1373 if (!face_connect.empty())
1376 exII::EX_FACE_BLOCK,
1377 face_block_ids[block],
1378 face_connect.data(),
1381 EX_CHECK_ERR(
ex_err,
"Error reading polyhedron face connectivity.");
1384 std::size_t offset = 0;
1385 for (
const auto count : face_node_counts)
1387 libmesh_error_msg_if(count < 3,
1388 "Error: Exodus NSIDED face block "
1389 << face_block_ids[block]
1390 <<
" has a face with only "
1391 << count <<
" nodes.");
1394 (face_connect.begin() + offset,
1395 face_connect.begin() + offset + count);
1402 "Error: Exodus file says it has "
1403 <<
num_face <<
" faces, but its face blocks contain "
1412 LOG_SCOPE(
"read_elem_in_block()",
"ExodusII_IO_Helper");
1414 libmesh_assert_less (block,
block_ids.size());
1419 int num_edges_per_elem = 0;
1420 int num_faces_per_elem = 0;
1421 int num_node_data_per_elem = 0;
1423 exII::EX_ELEM_BLOCK,
1427 &num_node_data_per_elem,
1428 &num_edges_per_elem,
1429 &num_faces_per_elem,
1432 EX_CHECK_ERR(
ex_err,
"Error getting block info.");
1433 message(
"Info retrieved successfully for block: ", block);
1438 const bool is_bezier = is_bezier_elem(
elem_type.data());
1443 const bool is_c0polygon =
1445 const bool is_c0polyhedron =
1451 if (is_c0polyhedron && !(num_edges_per_elem == 0) && !(num_edges_per_elem == -1))
1452 libmesh_error_msg(
"Error: Exodus NFACED element blocks with edge "
1453 "connectivity are not currently supported.");
1454 else if (!(num_edges_per_elem == 0) && !(num_edges_per_elem == -1))
1455 libmesh_warning(
"Exodus files with extended edge connectivity not currently supported.");
1456 if (!is_c0polyhedron && !(num_faces_per_elem == 0) && !(num_faces_per_elem == -1))
1457 libmesh_warning(
"Exodus files with extended face connectivity not currently supported.");
1467 else if (is_c0polygon)
1473 ex_err = exII::ex_get_entity_count_per_polyhedra
1475 exII::EX_ELEM_BLOCK,
1478 EX_CHECK_ERR(
ex_err,
"Error reading polygon node counts");
1481 int counted_nodes = 0;
1483 counted_nodes += count;
1485 libmesh_error_msg_if(counted_nodes != num_node_data_per_elem,
1486 "Error: Exodus NSIDED block "
1488 <<
" says it has " << num_node_data_per_elem
1489 <<
" total node entries, but its per-element "
1490 <<
"node counts sum to " << counted_nodes <<
".");
1494 else if (is_c0polyhedron)
1503 ex_err = exII::ex_get_entity_count_per_polyhedra
1505 exII::EX_ELEM_BLOCK,
1508 EX_CHECK_ERR(
ex_err,
"Error reading polyhedron face counts");
1511 int counted_faces = 0;
1513 counted_faces += count;
1515 libmesh_error_msg_if(counted_faces != num_faces_per_elem,
1516 "Error: Exodus NFACED block "
1518 <<
" says it has " << num_faces_per_elem
1519 <<
" total face entries, but its per-element "
1520 <<
"face counts sum to " << counted_faces <<
".");
1533 <<
" total node entries.";
1534 else if (is_c0polyhedron)
1536 <<
" total face entries.";
1539 <<
" nodes per element.";
1547 num_node_data_per_elem :
1549 num_faces_per_elem :
1555 exII::EX_ELEM_BLOCK,
1557 is_c0polyhedron ?
nullptr :
connect.data(),
1559 is_c0polyhedron ?
connect.data() :
nullptr);
1561 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
1562 message(
"Connectivity retrieved successfully for block: ", block);
1570#if EX_API_VERS_NODOT >= 800
1571 int real_n_attr = exII::ex_get_attribute_count(
ex_id, exII::EX_ELEM_BLOCK,
block_ids[block]);
1572 EX_CHECK_ERR(real_n_attr,
"Error getting number of element block attributes.");
1574 if (real_n_attr > 0)
1576 std::vector<exII::ex_attribute> attributes(real_n_attr);
1578 ex_err = exII::ex_get_attribute_param(
ex_id, exII::EX_ELEM_BLOCK,
block_ids[block], attributes.data());
1579 EX_CHECK_ERR(
ex_err,
"Error getting element block attribute parameters.");
1581 ex_err = exII::ex_get_attributes(
ex_id, real_n_attr, attributes.data());
1582 EX_CHECK_ERR(
ex_err,
"Error getting element block attribute values.");
1584 for (
auto attr : attributes)
1586 if (std::string(
"bex_elem_degrees") == attr.name)
1588 if (attr.type != exII::EX_INTEGER)
1589 libmesh_error_msg(
"Found non-integer bex_elem_degrees");
1591 if (attr.value_count > 3)
1592 libmesh_error_msg(
"Looking for at most 3 bex_elem_degrees; found " << attr.value_count);
1596 std::vector<int> bex_elem_degrees(3);
1598 const int * as_int =
static_cast<int *
>(attr.values);
1599 std::copy(as_int, as_int+attr.value_count, bex_elem_degrees.begin());
1608 libmesh_assert_equal_to(bex_elem_degrees[d], 2);
1634 auto src = old_connect.data();
1657 LOG_SCOPE(
"read_edge_blocks()",
"ExodusII_IO_Helper");
1673 typedef std::pair<dof_id_type, unsigned int> ElemEdgePair;
1674 std::unordered_map<dof_id_type, std::vector<ElemEdgePair>> edge_map;
1675 std::unique_ptr<Elem> edge_ptr;
1676 for (
const auto & elem :
mesh.element_ptr_range())
1683 auto & vec = edge_map[edge_key];
1684 vec.emplace_back(elem->
id(), e);
1691 if (edge_ptr->default_order() !=
FIRST)
1694 auto low_order_edge =
1698 for (
unsigned int v=0; v<edge_ptr->n_vertices(); ++v)
1699 low_order_edge->set_node(v, edge_ptr->node_ptr(v));
1702 dof_id_type low_order_edge_key = low_order_edge->key();
1706 auto & low_order_vec = edge_map[low_order_edge_key];
1707 low_order_vec.emplace_back(elem->
id(), e);
1720 int num_edge_this_blk = 0;
1721 int num_nodes_per_edge = 0;
1722 int num_edges_per_edge = 0;
1723 int num_faces_per_edge = 0;
1724 int num_attr_per_edge = 0;
1726 exII::EX_EDGE_BLOCK,
1730 &num_nodes_per_edge,
1731 &num_edges_per_edge,
1732 &num_faces_per_edge,
1733 &num_attr_per_edge);
1735 EX_CHECK_ERR(
ex_err,
"Error getting edge block info.");
1736 message(
"Info retrieved successfully for block: ", edge_block_id);
1741 connect.resize(num_nodes_per_edge * num_edge_this_blk);
1746 exII::EX_EDGE_BLOCK,
1752 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
1753 message(
"Connectivity retrieved successfully for block: ", edge_block_id);
1762 for (
auto [i, sz] = std::make_tuple(0u,
connect.size()); i<sz; i+=num_nodes_per_edge)
1764 auto edge =
Elem::build(conv.libmesh_elem_type());
1765 for (
int n=0; n<num_nodes_per_edge; ++n)
1767 auto exodus_node_id = this->
connect[i+n];
1778 auto & elem_edge_pair_vec =
1779 libmesh_map_find(edge_map, edge_key);
1781 for (
const auto & elem_edge_pair : elem_edge_pair_vec)
1793 build_edge_ptr(edge_ptr, elem_edge_pair.second);
1802 ((edge_ptr->node_id(0) == edge->node_id(0)) && (edge_ptr->node_id(1) == edge->node_id(1))) ||
1803 ((edge_ptr->node_id(0) == edge->node_id(1)) && (edge_ptr->node_id(1) == edge->node_id(0)));
1809 elem_edge_pair.second,
1831 ex_err = exII::ex_get_elem_num_map
1834 EX_CHECK_ERR(
ex_err,
"Error retrieving element number map.");
1835 message(
"Element numbering map retrieved successfully.");
1854 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_elem-1)); ++i)
1870 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset information.");
1871 message(
"All sideset information retrieved successfully.");
1878 num_elem_all_sidesets = inquire(*
this, exII::EX_INQ_SS_ELEM_LEN,
"Error retrieving length of the concatenated side sets element list!");
1885 char name_buffer[libmesh_max_str_length+1];
1888 ex_err = exII::ex_get_name(
ex_id, exII::EX_SIDE_SET,
1890 EX_CHECK_ERR(
ex_err,
"Error getting side set name.");
1893 message(
"All side set names retrieved successfully.");
1905 EX_CHECK_ERR(
ex_err,
"Error retrieving nodeset information.");
1906 message(
"All nodeset information retrieved successfully.");
1913 char name_buffer[libmesh_max_str_length+1];
1916 ex_err = exII::ex_get_name(
ex_id, exII::EX_NODE_SET,
1918 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1921 message(
"All node set names retrieved successfully.");
1934 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset information.");
1935 message(
"All elemset information retrieved successfully.");
1943 inquire(*
this, exII::EX_INQ_ELS_LEN,
1944 "Error retrieving length of the concatenated elem sets element list!");
1953 char name_buffer[libmesh_max_str_length+1];
1956 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_SET,
1958 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1961 message(
"All elem set names retrieved successfully.");
1968 LOG_SCOPE(
"read_sideset()",
"ExodusII_IO_Helper");
1970 libmesh_assert_less (
id,
ss_ids.size());
1973 libmesh_assert_less_equal (offset,
elem_list.size());
1974 libmesh_assert_less_equal (offset,
side_list.size());
1981 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset parameters.");
1982 message(
"Parameters retrieved successfully for sideset: ",
id);
1988 if (
static_cast<unsigned int>(offset) ==
elem_list.size() ||
1989 static_cast<unsigned int>(offset) ==
side_list.size() )
2003 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset data.");
2004 message(
"Data retrieved successfully for sideset: ",
id);
2015 LOG_SCOPE(
"read_elemset()",
"ExodusII_IO_Helper");
2020 libmesh_assert_less_equal (offset,
elemset_list.size());
2027 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset parameters.");
2028 message(
"Parameters retrieved successfully for elemset: ",
id);
2034 if (
static_cast<unsigned int>(offset) ==
elemset_list.size())
2047 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset data.");
2048 message(
"Data retrieved successfully for elemset: ",
id);
2060 LOG_SCOPE(
"read_all_nodesets()",
"ExodusII_IO_Helper");
2066 (*
this, exII::EX_INQ_NODE_SETS,
2067 "Error retrieving number of node sets");
2070 int total_nodes_in_all_sets =
2072 (*
this, exII::EX_INQ_NS_NODE_LEN,
2073 "Error retrieving number of nodes in all node sets.");
2076 int total_df_in_all_sets =
2078 (*
this, exII::EX_INQ_NS_DF_LEN,
2079 "Error retrieving number of distribution factors in all node sets.");
2099 exII::ex_set_specs set_specs = {};
2106 set_specs.sets_extra_list =
nullptr;
2107 set_specs.sets_dist_fact = total_df_in_all_sets ? mapped_node_sets_dist_fact.
data() :
nullptr;
2109 ex_err = exII::ex_get_concat_sets(
ex_id, exII::EX_NODE_SET, &set_specs);
2110 EX_CHECK_ERR(
ex_err,
"Error reading concatenated nodesets");
2113 char name_buffer[libmesh_max_str_length+1];
2116 ex_err = exII::ex_get_name
2121 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
2152 message(
"Error closing Exodus file.");
2154 message(
"Exodus file closed successfully.");
2175 ex_err = exII::ex_get_all_times
2178 EX_CHECK_ERR(
ex_err,
"Error reading timesteps!");
2187 inquire(*
this, exII::EX_INQ_TIME,
"Error retrieving number of time steps");
2194 LOG_SCOPE(
"read_nodal_var_values()",
"ExodusII_IO_Helper");
2200 unsigned int var_index = 0;
2217 libmesh_error_msg(
"Unable to locate variable named: " << nodal_var_name);
2223 std::vector<Real> unmapped_nodal_var_values(
num_nodes);
2226 ex_err = exII::ex_get_var
2234 EX_CHECK_ERR(
ex_err,
"Error reading nodal variable values!");
2279 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
2287 std::vector<std::string> & result)
2290 ex_err = exII::ex_get_var_param(
ex_id, var_type, &count);
2291 EX_CHECK_ERR(
ex_err,
"Error reading number of variables.");
2298 NamesData names_table(count, libmesh_max_str_length);
2305 EX_CHECK_ERR(
ex_err,
"Error reading variable names!");
2309 libMesh::out <<
"Read the variable(s) from the file:" << std::endl;
2310 for (
int i=0; i<count; i++)
2315 result.resize(count);
2318 for (
int i=0; i<count; i++)
2327 const std::vector<std::string> & names)
2359 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
2368 const std::vector<std::string> & names)
2371 count = cast_int<int>(names.size());
2374 ex_err = exII::ex_put_var_param(
ex_id, var_type, count);
2375 EX_CHECK_ERR(
ex_err,
"Error setting number of vars.");
2387 for (
int i=0; i != count; ++i)
2391 "*** Warning, Exodus variable name \"" <<
2392 names[i] <<
"\" too long (current max " <<
2394 " characters). Name will be truncated. ");
2400 libMesh::out <<
"Writing variable name(s) to file: " << std::endl;
2401 for (
int i=0; i != count; ++i)
2411 EX_CHECK_ERR(
ex_err,
"Error writing variable names.");
2419 std::map<dof_id_type, Real> & elem_var_value_map)
2421 LOG_SCOPE(
"read_elemental_var_values()",
"ExodusII_IO_Helper");
2426 unsigned int var_index = 0;
2443 libmesh_error_msg(
"Unable to locate variable named: " << elemental_var_name);
2447 unsigned ex_el_num = 0;
2453 for (
unsigned i=0; i<static_cast<unsigned>(
num_elem_blk); i++)
2456 exII::EX_ELEM_BLOCK,
2464 EX_CHECK_ERR(
ex_err,
"Error getting number of elements in block.");
2477 ex_err = exII::ex_get_var
2480 exII::EX_ELEM_BLOCK,
2485 EX_CHECK_ERR(
ex_err,
"Error getting elemental values.");
2492 auto libmesh_elem_id =
2496 elem_var_value_map[libmesh_elem_id] = block_elem_var_values[j];
2518 const std::vector<int> & num_map)
2523 auto exodus_id_zero_based =
2524 cast_int<dof_id_type>(exodus_id - 1);
2530 libmesh_error_msg_if(exodus_id_zero_based >= num_map.size(),
2531 "Cannot get LibMesh id for Exodus id: " << exodus_id);
2541 cast_int<dof_id_type>(exodus_id_zero_based) :
2542 cast_int<dof_id_type>(num_map[exodus_id_zero_based] - 1);
2567 int exodus_mapped_id)
2574 auto exodus_mapped_id_zero_based =
2575 cast_int<dof_id_type>(exodus_mapped_id - 1);
2578 dof_object->
set_unique_id(cast_int<unique_id_type>(exodus_mapped_id_zero_based));
2588#ifdef LIBMESH_ENABLE_UNIQUE_ID
2614 comp_ws = cast_int<int>(
sizeof(
float));
2615 io_ws = cast_int<int>(
sizeof(
float));
2621 comp_ws = cast_int<int>
2622 (std::min(
sizeof(
Real),
sizeof(
double)));
2623 io_ws = cast_int<int>
2624 (std::min(
sizeof(
Real),
sizeof(
double)));
2630 int mode = EX_CLOBBER;
2635#ifdef LIBMESH_HAVE_HDF5
2639 mode |= EX_NOCLASSIC;
2645 ex_id = exII::ex_create(filename.c_str(), mode, &comp_ws, &io_ws);
2648 EX_CHECK_ERR(
ex_id,
"Error creating ExodusII/Nemesis mesh file.");
2655 EX_CHECK_ERR(
ex_err,
"Error setting max ExodusII name length.");
2658 libMesh::out <<
"File created successfully." << std::endl;
2673 libmesh_parallel_only(
mesh.
comm());
2685 bool has_c0polyhedron =
false;
2686 for (
const auto & elem :
mesh.active_local_element_ptr_range())
2689 has_c0polyhedron =
true;
2690 local_num_c0polyhedron_faces += elem->
n_sides();
2695 if (has_c0polyhedron)
2697 num_face = cast_int<int>(local_num_c0polyhedron_faces);
2711 for (
const auto & elem :
mesh.active_local_element_ptr_range())
2736 (std::distance(
mesh.local_nodes_begin(),
2737 mesh.local_nodes_end()));
2742 const dof_id_type n_gaps = max_nn - n_total_nodes;
2743 const dof_id_type gaps_per_processor = n_gaps / n_proc;
2744 const dof_id_type remainder_gaps = n_gaps % n_proc;
2746 n_local_nodes = n_local_nodes +
2747 gaps_per_processor +
2768 subdomain_id_type subdomain_id_end = 0;
2769 auto subdomain_map = build_subdomain_map(
mesh,
2774 if (!use_discontinuous)
2779 num_nodes += cast_int<int>(std::distance(
mesh.nodes_begin(),
2784 for (
const auto & elem :
mesh.active_element_ptr_range())
2788 std::set<boundary_id_type> unique_side_boundaries;
2789 std::vector<boundary_id_type> unique_node_boundaries;
2794 std::vector<boundary_id_type> side_boundaries;
2796 unique_side_boundaries.insert(side_boundaries.begin(), side_boundaries.end());
2800 std::vector<boundary_id_type> shellface_boundaries;
2802 unique_side_boundaries.insert(shellface_boundaries.begin(), shellface_boundaries.end());
2806 unique_side_boundaries.insert(pr.first);
2815 if (std::find(unique_node_boundaries.begin(),
2816 unique_node_boundaries.end(),
id)
2817 == unique_node_boundaries.end())
2818 unique_node_boundaries.push_back(
id);
2821 num_side_sets = cast_int<int>(unique_side_boundaries.size());
2822 num_node_sets = cast_int<int>(unique_node_boundaries.size());
2826 if (str_title.size() > MAX_LINE_LENGTH)
2828 libMesh::err <<
"Warning, Exodus files cannot have titles longer than "
2830 <<
" characters. Your title will be truncated."
2832 str_title.resize(MAX_LINE_LENGTH);
2869 exII::ex_init_params params = {};
2870 params.title[str_title.copy(params.title, MAX_LINE_LENGTH)] =
'\0';
2884 EX_CHECK_ERR(
ex_err,
"Error initializing new Exodus file.");
2907 auto push_node = [
this](
const Point & p) {
2951 if (!use_discontinuous)
2953 for (
const auto & node_ptr :
mesh.node_ptr_range())
2955 const Node & node = *node_ptr;
2983 for (
const auto & elem :
mesh.active_element_ptr_range())
3002 std::vector<std::vector<const Elem *>>
3005 for (
const auto & elem :
mesh.active_element_ptr_range())
3009 for (
const Elem * elem : elems_by_pid[p])
3015 const std::vector<unsigned int> side_nodes =
3018 for (
auto n : side_nodes)
3019 push_node(elem->
point(n));
3028 ex_err = exII::ex_put_coord
3034 EX_CHECK_ERR(
ex_err,
"Error writing coordinates to Exodus file.");
3040 EX_CHECK_ERR(
ex_err,
"Error writing node_num_map");
3048 LOG_SCOPE(
"write_elements()",
"ExodusII_IO_Helper");
3055 subdomain_id_type subdomain_id_end = 0;
3056 auto subdomain_map = build_subdomain_map(
mesh,
3063 const int c0polyhedron_face_block_id = subdomain_map.empty() ? 0 :
3064 cast_int<int>(subdomain_map.rbegin()->first) + 1;
3070 std::vector<int> elem_blk_id;
3071 std::vector<int> num_elem_this_blk_vec;
3072 std::vector<int> num_nodes_per_elem_vec;
3073 std::vector<int> num_edges_per_elem_vec;
3074 std::vector<int> num_faces_per_elem_vec;
3075 std::vector<int> num_attr_vec;
3085 bool has_c0polygon_blocks =
false;
3086 bool has_c0polyhedron_blocks =
false;
3087 int c0polyhedron_total_faces = 0;
3088 int c0polyhedron_total_face_nodes = 0;
3091 unsigned int counter = 0;
3092 for (
auto & [subdomain_id, element_id_vec] : subdomain_map)
3096 const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
3097 ElemType(subdomain_id - subdomain_id_end) :
3100 if (subdomain_id >= subdomain_id_end)
3104 num_elem_this_blk_vec.push_back
3105 (cast_int<int>(element_id_vec[0]));
3107 (Utility::enum_to_string<ElemType>(elem_t));
3112 num_elem_this_blk_vec.push_back
3113 (cast_int<int>(element_id_vec.size()));
3124 const bool is_synthesized_block = (subdomain_id != elem_subdomain_id);
3128 if (is_synthesized_block)
3135 const std::string type_suffix = Utility::enum_to_string<ElemType>(elem_t);
3136 block_name = block_name.empty()
3137 ? (std::to_string(elem_subdomain_id) +
"_" + type_suffix)
3138 : (block_name +
"_" + type_suffix);
3144 libMesh::out <<
"ExodusII_IO: subdomain " << elem_subdomain_id
3145 <<
" contains more than one element type; writing its "
3146 << type_suffix <<
" elements to a new block \"" << block_name
3147 <<
"\" (block id " << subdomain_id
3152 if (block_name.empty() && elem_t ==
C0POLYGON)
3153 block_name =
"NSIDED_" + std::to_string(counter + 1);
3155 block_name =
"NFACED_" + std::to_string(counter + 1);
3159 num_elem += num_elem_this_blk_vec.back();
3165 int num_edges_per_elem = 0;
3166 int num_faces_per_elem = 0;
3169 if (subdomain_id >= subdomain_id_end)
3170 libmesh_not_implemented_msg(
"Support for C0POLYGON side blocks not yet implemented");
3172 has_c0polygon_blocks =
true;
3175 for (
auto elem_id : element_id_vec)
3180 "Error: Exodus requires all elements with a given subdomain ID "
3181 "to be the same type.\n"
3182 <<
"Can't write both "
3184 <<
" and C0POLYGON in the same block!");
3191 if (subdomain_id >= subdomain_id_end)
3192 libmesh_not_implemented_msg(
"Support for C0POLYHEDRON side blocks not yet implemented");
3194 has_c0polyhedron_blocks =
true;
3197 for (
auto elem_id : element_id_vec)
3202 "Error: Exodus requires all elements with a given subdomain ID "
3203 "to be the same type.\n"
3204 <<
"Can't write both "
3206 <<
" and C0POLYHEDRON in the same block!");
3208 const int elem_n_sides = cast_int<int>(elem.
n_sides());
3209 num_faces_per_elem += elem_n_sides;
3210 c0polyhedron_total_faces += elem_n_sides;
3213 c0polyhedron_total_face_nodes += cast_int<int>(elem.
nodes_on_side(s).size());
3220 libmesh_not_implemented_msg(
"Support for Polygons/Polyhedra not yet implemented");
3223 elem_blk_id.push_back(subdomain_id);
3226 num_attr_vec.push_back(0);
3227 num_edges_per_elem_vec.push_back(num_edges_per_elem);
3228 num_faces_per_elem_vec.push_back(num_faces_per_elem);
3232 if (has_c0polyhedron_blocks)
3235 libmesh_assert_equal_to(
num_face, c0polyhedron_total_faces);
3248 std::map<std::pair<dof_id_type, unsigned int>,
dof_id_type> discontinuous_node_indices;
3250 if (use_discontinuous)
3252 for (
const auto & elem :
mesh.active_element_ptr_range())
3254 discontinuous_node_indices[std::make_pair(elem->
id(),n)] =
3262 for (
const Elem * elem :
mesh.active_element_ptr_range())
3266 unsigned int local_node_index = elem->
n_nodes();
3273 const std::vector<unsigned int> side_nodes =
3279 discontinuous_node_indices
3280 [std::make_pair(elem->
id(),local_node_index++)] =
3291 std::vector<BoundaryInfo::BCTuple> edge_tuples = bi.
build_edge_list();
3299 std::map<boundary_id_type, std::vector<int>> edge_id_to_conn;
3300 std::map<boundary_id_type, std::pair<ElemType, unsigned int>> edge_id_to_elem_type;
3302 std::unique_ptr<const Elem> edge;
3303 for (
const auto & t : edge_tuples)
3306 unsigned int edge_id = std::get<1>(t);
3314 if (
const auto check_it = edge_id_to_elem_type.find(b_id);
3315 check_it == edge_id_to_elem_type.end())
3318 edge_id_to_elem_type[b_id] = std::make_pair(edge->type(), edge->n_nodes());
3323 const auto & val_pair = check_it->second;
3324 libmesh_error_msg_if(val_pair.first != edge->type() || val_pair.second != edge->n_nodes(),
3325 "All edges in a block must have same geometric type.");
3329 auto & conn = edge_id_to_conn[b_id];
3335 for (
auto n : edge->node_index_range())
3339 int exodus_node_id = -1;
3341 if (!use_discontinuous)
3343 dof_id_type libmesh_node_id = edge->node_ptr(n)->id();
3344 exodus_node_id = libmesh_map_find
3353 exodus_node_id = libmesh_map_find
3354 (discontinuous_node_indices, std::make_pair(elem_id, pn));
3357 conn.push_back(exodus_node_id);
3367 std::vector<int> edge_blk_id;
3369 std::vector<int> num_edge_this_blk_vec;
3370 std::vector<int> num_nodes_per_edge_vec;
3371 std::vector<int> num_attr_edge_vec;
3377 if (has_c0polyhedron_blocks)
3381 for (
const auto & pr : edge_id_to_conn)
3385 edge_blk_id.push_back(
id);
3388 const auto & elem_type_node_count = edge_id_to_elem_type[id];
3391 num_nodes_per_edge_vec.push_back(elem_type_node_count.second);
3395 num_edge_this_blk_vec.push_back(pr.second.size() / elem_type_node_count.second);
3398 num_attr_edge_vec.push_back(0);
3404 if (has_c0polygon_blocks || has_c0polyhedron_blocks)
3409 if (has_c0polyhedron_blocks)
3412 exII::EX_FACE_BLOCK,
3413 c0polyhedron_face_block_id,
3415 c0polyhedron_total_faces,
3416 c0polyhedron_total_face_nodes,
3420 EX_CHECK_ERR(
ex_err,
"Error writing polyhedron face block.");
3426 exII::EX_ELEM_BLOCK,
3429 num_elem_this_blk_vec[i],
3430 num_nodes_per_elem_vec[i],
3431 num_edges_per_elem_vec[i],
3432 num_faces_per_elem_vec[i],
3434 EX_CHECK_ERR(
ex_err,
"Error writing element block.");
3440 exII::EX_EDGE_BLOCK,
3443 num_edge_this_blk_vec[i],
3444 num_nodes_per_edge_vec[i],
3447 num_attr_edge_vec[i]);
3448 EX_CHECK_ERR(
ex_err,
"Error writing edge block.");
3464 exII::ex_block_params params = {};
3467 params.elem_blk_id = elem_blk_id.data();
3469 params.num_elem_this_blk = num_elem_this_blk_vec.data();
3470 params.num_nodes_per_elem = num_nodes_per_elem_vec.data();
3471 params.num_edges_per_elem = num_edges_per_elem_vec.data();
3472 params.num_faces_per_elem = num_faces_per_elem_vec.data();
3473 params.num_attr_elem = num_attr_vec.data();
3474 params.define_maps = 0;
3479 params.edge_blk_id = edge_blk_id.data();
3481 params.num_edge_this_blk = num_edge_this_blk_vec.data();
3482 params.num_nodes_per_edge = num_nodes_per_edge_vec.data();
3483 params.num_attr_edge = num_attr_edge_vec.data();
3486 ex_err = exII::ex_put_concat_all_blocks(
ex_id, ¶ms);
3487 EX_CHECK_ERR(
ex_err,
"Error writing element blocks.");
3491 unsigned libmesh_elem_num_to_exodus_counter = 0;
3495 auto num_elem_this_blk_it = num_elem_this_blk_vec.begin();
3502#ifdef LIBMESH_ENABLE_UNIQUE_ID
3507 std::vector<int> face_connect;
3508 std::vector<int> c0polyhedron_face_node_counts;
3509 face_connect.reserve(c0polyhedron_total_face_nodes);
3510 c0polyhedron_face_node_counts.reserve(c0polyhedron_total_faces);
3511 int next_c0polyhedron_face_id = 1;
3513 const auto get_exodus_node_id = [&](
const Elem &elem,
3515 unsigned int elem_node_index)
3518 if (!use_discontinuous)
3520 cast_int<int>(elem.
node_id(elem_node_index)));
3522 return cast_int<int>(libmesh_map_find(discontinuous_node_indices,
3523 std::make_pair(elem_id, elem_node_index)));
3526 for (
auto & [subdomain_id, element_id_vec] : subdomain_map)
3532 const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
3533 ElemType(subdomain_id - subdomain_id_end) :
3537 const bool is_c0polygon_block = (elem_t ==
C0POLYGON);
3538 const bool is_c0polyhedron_block = (elem_t ==
C0POLYHEDRON);
3539 const bool is_variable_connectivity_block =
3540 is_c0polygon_block || is_c0polyhedron_block;
3541 std::vector<int> c0polygon_node_counts;
3542 std::vector<int> c0polyhedron_face_counts;
3544 if (is_variable_connectivity_block && subdomain_id >= subdomain_id_end)
3545 libmesh_not_implemented_msg(
"Support for " <<
3547 " side blocks not yet implemented");
3549 if (!is_variable_connectivity_block)
3553 libmesh_not_implemented_msg(
"Support for Polygons/Polyhedra not yet implemented");
3558 if (subdomain_id < subdomain_id_end)
3560 if (is_variable_connectivity_block)
3562 if (is_c0polygon_block)
3563 c0polygon_node_counts.reserve(element_id_vec.size());
3564 else if (is_c0polyhedron_block)
3565 c0polyhedron_face_counts.reserve(element_id_vec.size());
3569 const auto add_c0polygon_connectivity =
3572 c0polygon_node_counts.push_back(cast_int<int>(elem.
n_nodes()));
3574 connect.push_back(get_exodus_node_id(elem, elem_id, elem_node_index));
3578 const auto add_c0polyhedron_connectivity =
3581 c0polyhedron_face_counts.push_back(cast_int<int>(elem.
n_sides()));
3585 connect.push_back(next_c0polyhedron_face_id++);
3587 const std::vector<unsigned int> side_nodes = elem.
nodes_on_side(s);
3588 c0polyhedron_face_node_counts.push_back(cast_int<int>(side_nodes.size()));
3590 for (
const auto elem_node_index : side_nodes)
3591 face_connect.push_back(
3592 get_exodus_node_id(elem, elem_id, elem_node_index));
3596 const auto add_fixed_connectivity =
3599 for (
unsigned int j = 0;
3603 const auto connect_index =
3605 const auto elem_node_index = conv.get_inverse_node_map(j);
3607 get_exodus_node_id(elem, elem_id, elem_node_index);
3613 unsigned int elem_id = element_id_vec[i];
3628 libmesh_error_msg_if(elem.
type() != conv.libmesh_elem_type(),
3629 "Error: Exodus requires all elements with a given subdomain ID to be the same type.\n"
3630 <<
"Can't write both "
3634 <<
" in the same block!");
3636 if (is_c0polygon_block)
3637 add_c0polygon_connectivity(elem, elem_id);
3638 else if (is_c0polyhedron_block)
3639 add_c0polyhedron_connectivity(elem, elem_id);
3641 add_fixed_connectivity(elem, elem_id, i);
3659 libmesh_assert(num_elem_this_blk_it != num_elem_this_blk_vec.end());
3664 std::size_t connect_index = 0;
3665 for (
const auto & elem :
mesh.active_element_ptr_range())
3667 unsigned int local_node_index = elem->
n_nodes();
3677 const std::vector<unsigned int> side_nodes =
3683 const int exodus_node_id = libmesh_map_find
3684 (discontinuous_node_indices,
3685 std::make_pair(elem->
id(), local_node_index++));
3686 libmesh_assert_less(connect_index,
connect.size());
3687 connect[connect_index++] = exodus_node_id;
3699 ++num_elem_this_blk_it;
3701 ex_err = exII::ex_put_conn
3703 exII::EX_ELEM_BLOCK,
3705 is_c0polyhedron_block ?
nullptr :
connect.data(),
3707 is_c0polyhedron_block ?
connect.data() :
nullptr);
3708 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
3710 if (is_c0polygon_block)
3712 ex_err = exII::ex_put_entity_count_per_polyhedra
3714 exII::EX_ELEM_BLOCK,
3716 c0polygon_node_counts.data());
3717 EX_CHECK_ERR(
ex_err,
"Error writing polygon node counts");
3719 if (is_c0polyhedron_block)
3721 ex_err = exII::ex_put_entity_count_per_polyhedra
3723 exII::EX_ELEM_BLOCK,
3725 c0polyhedron_face_counts.data());
3726 EX_CHECK_ERR(
ex_err,
"Error writing polyhedron face counts");
3730 if (has_c0polyhedron_blocks)
3732 libmesh_assert_equal_to(c0polyhedron_face_node_counts.size(),
3734 libmesh_assert_equal_to(next_c0polyhedron_face_id,
num_face + 1);
3736 ex_err = exII::ex_put_conn
3738 exII::EX_FACE_BLOCK,
3739 c0polyhedron_face_block_id,
3740 face_connect.data(),
3743 EX_CHECK_ERR(
ex_err,
"Error writing polyhedron face connectivities");
3745 ex_err = exII::ex_put_entity_count_per_polyhedra
3747 exII::EX_FACE_BLOCK,
3748 c0polyhedron_face_block_id,
3749 c0polyhedron_face_node_counts.data());
3750 EX_CHECK_ERR(
ex_err,
"Error writing polyhedron face node counts");
3755 EX_CHECK_ERR(
ex_err,
"Error writing element map");
3761 EX_CHECK_ERR(
ex_err,
"Error writing element block names");
3766 ex_err = exII::ex_put_names
3768 exII::EX_FACE_BLOCK,
3770 EX_CHECK_ERR(
ex_err,
"Error writing face block names");
3774 for (
const auto & pr : edge_id_to_conn)
3776 ex_err = exII::ex_put_conn
3778 exII::EX_EDGE_BLOCK,
3783 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
3789 ex_err = exII::ex_put_names
3791 exII::EX_EDGE_BLOCK,
3793 EX_CHECK_ERR(
ex_err,
"Error writing edge block names");
3802 LOG_SCOPE(
"write_sidesets()",
"ExodusII_IO_Helper");
3808 std::map<int, std::vector<int>> elem_lists;
3809 std::map<int, std::vector<int>> side_lists;
3810 std::set<boundary_id_type> side_boundary_ids;
3817 std::vector<const Elem *> family;
3818#ifdef LIBMESH_ENABLE_AMR
3823 mesh.
elem_ref(std::get<0>(t)).active_family_tree_by_side(family, std::get<1>(t),
false);
3828 for (
const auto & f : family)
3835 side_lists[std::get<2>(t)].push_back(conv.get_inverse_side_map(std::get<1>(t)));
3839 std::vector<boundary_id_type> tmp;
3841 side_boundary_ids.insert(tmp.begin(), tmp.end());
3850 std::vector<const Elem *> family;
3851#ifdef LIBMESH_ENABLE_AMR
3856 mesh.
elem_ref(std::get<0>(t)).active_family_tree_by_side(family, std::get<1>(t),
false);
3861 for (
const auto & f : family)
3868 side_lists[std::get<2>(t)].push_back(conv.get_inverse_shellface_map(std::get<1>(t)));
3872 std::vector<boundary_id_type> tmp;
3874 side_boundary_ids.insert(tmp.begin(), tmp.end());
3879 side_boundary_ids.insert(pr.first);
3882 if (side_boundary_ids.size() > 0)
3886 std::vector<exII::ex_set> sets(side_boundary_ids.size());
3889 for (
auto [i, it] = std::tuple{0u, side_boundary_ids.begin()}; i<sets.size(); ++i, ++it)
3895 sets[i].type = exII::EX_SIDE_SET;
3896 sets[i].num_distribution_factor = 0;
3897 sets[i].distribution_factor_list =
nullptr;
3899 if (
const auto elem_it = elem_lists.find(ss_id);
3900 elem_it == elem_lists.end())
3902 sets[i].num_entry = 0;
3903 sets[i].entry_list =
nullptr;
3904 sets[i].extra_list =
nullptr;
3908 sets[i].num_entry = elem_it->second.size();
3909 sets[i].entry_list = elem_it->second.data();
3910 sets[i].extra_list = libmesh_map_find(side_lists, ss_id).data();
3914 ex_err = exII::ex_put_sets(
ex_id, side_boundary_ids.size(), sets.data());
3915 EX_CHECK_ERR(
ex_err,
"Error writing sidesets");
3918 EX_CHECK_ERR(
ex_err,
"Error writing sideset names");
3926 LOG_SCOPE(
"write_nodesets()",
"ExodusII_IO_Helper");
3943 std::stable_sort(bc_tuples.begin(), bc_tuples.end(),
3946 { return std::get<1>(t1) < std::get<1>(t2); });
3948 std::vector<boundary_id_type> node_boundary_ids;
3956 if (std::find(node_boundary_ids.begin(),
3957 node_boundary_ids.end(),
id)
3958 == node_boundary_ids.end())
3959 node_boundary_ids.push_back(
id);
3963 if (node_boundary_ids.size() > 0)
3983 std::map<boundary_id_type, unsigned int> nodeset_counts;
3984 for (
auto id : node_boundary_ids)
3985 nodeset_counts[
id] = 0;
3987 for (
const auto & t : bc_tuples)
3992 nodeset_counts[nodeset_id] += 1;
3996 unsigned int running_sum = 0;
3997 for (
const auto & pr : nodeset_counts)
4003 running_sum += pr.second;
4008 exII::ex_set_specs set_data = {};
4017 ex_err = exII::ex_put_concat_sets(
ex_id, exII::EX_NODE_SET, &set_data);
4018 EX_CHECK_ERR(
ex_err,
"Error writing concatenated nodesets");
4022 EX_CHECK_ERR(
ex_err,
"Error writing nodeset names");
4029 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
4035 if (names.size() == 0)
4058 for (
auto var_num :
index_range(vars_active_subdomains))
4062 std::set<subdomain_id_type> current_set;
4063 if (vars_active_subdomains[var_num].empty())
4065 current_set.insert(restrict_int<subdomain_id_type>(block_id));
4067 current_set = vars_active_subdomains[var_num];
4070 for (
auto block_id : current_set)
4073 libmesh_error_msg_if(it ==
block_ids.end(),
4074 "ExodusII_IO_Helper: block id " << block_id <<
" not found in block_ids.");
4076 std::size_t block_index =
4079 std::size_t truth_tab_index = block_index*
num_elem_vars + var_num;
4080 truth_tab[truth_tab_index] = 1;
4084 ex_err = exII::ex_put_truth_table
4086 exII::EX_ELEM_BLOCK,
4090 EX_CHECK_ERR(
ex_err,
"Error writing element truth table.");
4101 if (names.size() == 0)
4129 if (names.size() == 0)
4150 std::vector<std::string> & names,
4151 std::vector<std::string> & names_from_file)
4165 std::equal(names.begin(), names.end(),
4166 names_from_file.begin(),
4167 [
this](
const std::string & a,
4168 const std::string &
b) ->
bool
4170 return a.compare(0, _max_name_length, b) == 0;
4175 libMesh::err <<
"Error! The Exodus file already contains the variables:" << std::endl;
4176 for (
const auto & name : names_from_file)
4179 libMesh::err <<
"And you asked to write:" << std::endl;
4180 for (
const auto & name : names)
4183 libmesh_error_msg(
"Cannot overwrite existing variables in Exodus II file.");
4196 float cast_time = float(time);
4197 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
4201 double cast_time = double(time);
4202 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
4204 EX_CHECK_ERR(
ex_err,
"Error writing timestep.");
4214 LOG_SCOPE(
"write_elemsets()",
"ExodusII_IO_Helper");
4226 std::map<elemset_id_type, std::vector<int>> exodus_elemsets;
4228 unsigned int elemset_index =
4233 for (
const auto & elem :
mesh.element_ptr_range())
4248 for (
const auto & set_id : set_ids)
4262 if (!exodus_elemsets.empty())
4268 std::vector<exII::ex_set> sets;
4269 sets.reserve(exodus_elemsets.size());
4271 for (
auto & [elem_set_id, ids_vec] : exodus_elemsets)
4276 exII::ex_set & current_set = sets.emplace_back();
4277 current_set.id = elem_set_id;
4278 current_set.type = exII::EX_ELEM_SET;
4279 current_set.num_entry = ids_vec.size();
4280 current_set.num_distribution_factor = 0;
4281 current_set.entry_list = ids_vec.data();
4282 current_set.extra_list =
nullptr;
4283 current_set.distribution_factor_list =
nullptr;
4288 libmesh_assert_msg(
num_elem_sets == cast_int<int>(exodus_elemsets.size()),
4289 "Mesh has " << exodus_elemsets.size()
4290 <<
" elemsets, but header was written with num_elem_sets == " <<
num_elem_sets);
4293 <<
", but header was written with num_elem_sets == " <<
num_elem_sets);
4295 ex_err = exII::ex_put_sets(
ex_id, exodus_elemsets.size(), sets.data());
4296 EX_CHECK_ERR(
ex_err,
"Error writing elemsets");
4311 const std::vector<std::string> & var_names,
4312 const std::vector<std::set<boundary_id_type>> & side_ids,
4313 const std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
4315 LOG_SCOPE(
"write_sideset_data()",
"ExodusII_IO_Helper");
4341 std::vector<int> sset_var_tab(
num_side_sets * var_names.size());
4360 if (!side_ids[var].count(
ss_ids[ss]))
4364 sset_var_tab[ss*var_names.size() + var] = 1;
4370 const auto & data_map = bc_vals[var];
4393 libmesh_error_msg_if
4395 cast_int<dof_id_type>(
elem_list[i + offset]),
4396 "Error mapping Exodus elem id to libmesh elem id.");
4402 unsigned int converted_side_id = conv.get_side_map(
side_id);
4414 sset_var_vals[i] = libmesh_map_find(data_map, key);
4420 if (sset_var_vals.size() > 0)
4422 ex_err = exII::ex_put_var
4430 EX_CHECK_ERR(
ex_err,
"Error writing sideset vars.");
4437 exII::ex_put_truth_table(
ex_id,
4440 cast_int<int>(var_names.size()),
4441 sset_var_tab.data());
4442 EX_CHECK_ERR(
ex_err,
"Error writing sideset var truth table.");
4451 std::vector<std::string> & var_names,
4452 std::vector<std::set<boundary_id_type>> & side_ids,
4453 std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
4455 LOG_SCOPE(
"read_sideset_data()",
"ExodusII_IO_Helper");
4465 ex_err = exII::ex_get_truth_table
4470 sset_var_tab.data());
4471 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable truth table.");
4500 side_ids[var].insert(
ss_ids[ss]);
4506 ex_err = exII::ex_get_var
4514 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable.");
4519 unsigned int exodus_side_id =
side_list[i + offset];
4524 dof_id_type converted_elem_id = exodus_elem_id - 1;
4533 unsigned int converted_side_id = conv.get_side_map(exodus_side_id - 1);
4542 bc_vals[var].emplace(key, sset_var_vals[i]);
4554 std::map<BoundaryInfo::BCTuple, unsigned int> & bc_array_indices)
4557 bc_array_indices.clear();
4571 unsigned int exodus_side_id =
side_list[i + offset];
4576 dof_id_type converted_elem_id = exodus_elem_id - 1;
4584 unsigned int converted_side_id = conv.get_side_map(exodus_side_id - 1);
4593 bc_array_indices.emplace(key, cast_int<unsigned int>(i));
4602 const std::vector<std::string> & var_names,
4603 const std::vector<std::set<boundary_id_type>> & node_boundary_ids,
4604 const std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals)
4606 LOG_SCOPE(
"write_nodeset_data()",
"ExodusII_IO_Helper");
4630 std::vector<int> nset_var_tab(
num_node_sets * var_names.size());
4642 if (!node_boundary_ids[var].count(
nodeset_ids[ns]))
4646 nset_var_tab[ns*var_names.size() + var] = 1;
4652 const auto & data_map = bc_vals[var];
4666 std::make_tuple(libmesh_node_id,
nodeset_ids[ns]);
4673 nset_var_vals[i] = libmesh_map_find(data_map, key);
4677 if (nset_var_vals.size() > 0)
4679 ex_err = exII::ex_put_var
4687 EX_CHECK_ERR(
ex_err,
"Error writing nodeset vars.");
4694 exII::ex_put_truth_table(
ex_id,
4697 cast_int<int>(var_names.size()),
4698 nset_var_tab.data());
4699 EX_CHECK_ERR(
ex_err,
"Error writing nodeset var truth table.");
4707 const std::vector<std::string> & var_names,
4708 const std::vector<std::set<elemset_id_type>> & elemset_ids_in,
4709 const std::vector<std::map<std::pair<dof_id_type, elemset_id_type>,
Real>> & elemset_vals)
4711 LOG_SCOPE(
"write_elemset_data()",
"ExodusII_IO_Helper");
4740 std::vector<int> elemset_var_tab(
num_elem_sets * var_names.size());
4766 elemset_var_tab[es*var_names.size() + var] = 1;
4772 const auto & data_map = elemset_vals[var];
4785 std::pair<dof_id_type, elemset_id_type> key =
4796 elemset_var_vals[i] = libmesh_map_find(data_map, key);
4800 if (elemset_var_vals.size() > 0)
4802 ex_err = exII::ex_put_var
4810 EX_CHECK_ERR(
ex_err,
"Error writing elemset vars.");
4817 exII::ex_put_truth_table(
ex_id,
4820 cast_int<int>(var_names.size()),
4821 elemset_var_tab.data());
4822 EX_CHECK_ERR(
ex_err,
"Error writing elemset var truth table.");
4830 std::vector<std::string> & var_names,
4831 std::vector<std::set<elemset_id_type>> & elemset_ids_in,
4832 std::vector<std::map<std::pair<dof_id_type, elemset_id_type>,
Real>> & elemset_vals)
4834 LOG_SCOPE(
"read_elemset_data()",
"ExodusII_IO_Helper");
4855 exII::ex_get_truth_table(
ex_id,
4859 elemset_var_tab.data());
4860 EX_CHECK_ERR(
ex_err,
"Error reading elemset variable truth table.");
4903 ex_err = exII::ex_get_var
4911 EX_CHECK_ERR(
ex_err,
"Error reading elemset variable.");
4920 dof_id_type converted_elem_id = exodus_elem_id - 1;
4923 auto key = std::make_pair(converted_elem_id,
4927 elemset_vals[var].emplace(key, elemset_var_vals[i]);
4941 elemset_array_indices.clear();
4965 dof_id_type converted_elem_id = exodus_elem_id - 1;
4969 auto key = std::make_pair(converted_elem_id,
4973 elemset_array_indices.emplace(key, cast_int<unsigned int>(i));
4982 std::vector<std::string> & var_names,
4983 std::vector<std::set<boundary_id_type>> & node_boundary_ids,
4984 std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals)
4986 LOG_SCOPE(
"read_nodeset_data()",
"ExodusII_IO_Helper");
4996 ex_err = exII::ex_get_truth_table
5001 nset_var_tab.data());
5002 EX_CHECK_ERR(
ex_err,
"Error reading nodeset variable truth table.");
5038 ex_err = exII::ex_get_var
5046 EX_CHECK_ERR(
ex_err,
"Error reading nodeset variable.");
5061 dof_id_type converted_node_id = exodus_node_id - 1;
5068 bc_vals[var].emplace(key, nset_var_vals[i]);
5083 bc_array_indices.clear();
5112 dof_id_type converted_node_id = exodus_node_id - 1;
5119 bc_array_indices.emplace(key, cast_int<unsigned int>(i));
5126 const std::vector<Real> & values,
5128 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
5130 LOG_SCOPE(
"write_element_values()",
"ExodusII_IO_Helper");
5137 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
5142 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
5143 for (
const auto & elem :
mesh.active_element_ptr_range())
5153 libmesh_assert_equal_to
5154 (vars_active_subdomains.size(),
5160 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
5163 auto it = subdomain_map.begin();
5166 const auto & active_subdomains
5167 = vars_active_subdomains[var_id];
5169 for (
unsigned int j=0; it!=subdomain_map.end(); ++it, ++j)
5174 if (!(active_subdomains.empty() || active_subdomains.count(it->first)))
5180 const auto & elem_nums = it->second;
5181 const unsigned int num_elems_this_block =
5182 cast_int<unsigned int>(elem_nums.size());
5183 std::vector<Real> data(num_elems_this_block);
5188 for (
unsigned int k=0; k<num_elems_this_block; ++k)
5189 data[k] = values[var_id*n_elem + elem_nums[k]];
5191 ex_err = exII::ex_put_var
5194 exII::EX_ELEM_BLOCK,
5197 num_elems_this_block,
5200 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
5211 const std::vector<Real> & values,
5213 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
5214 const std::vector<std::string> & derived_var_names,
5215 const std::map<
subdomain_id_type, std::vector<std::string>> & subdomain_to_var_names)
5222 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
5229 std::map<subdomain_id_type, unsigned int> subdomain_to_n_elem;
5230 for (
const auto & elem :
mesh.active_element_ptr_range())
5235 libmesh_assert_equal_to
5236 (vars_active_subdomains.size(),
5240 auto subdomain_to_n_elem_iter = subdomain_to_n_elem.begin();
5246 (
mesh.active_elements_begin(),
5247 mesh.active_elements_end());
5249 for (
unsigned int sbd_idx=0;
5250 subdomain_to_n_elem_iter != subdomain_to_n_elem.end();
5251 ++subdomain_to_n_elem_iter, ++sbd_idx)
5252 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
5255 const auto & active_subdomains
5256 = vars_active_subdomains[var_id];
5263 if (!active_subdomains.count(subdomain_to_n_elem_iter->first))
5267 std::vector<Real> data;
5268 data.reserve(subdomain_to_n_elem_iter->second);
5270 unsigned int values_offset = 0;
5271 for (
auto & elem : elem_range)
5278 auto subdomain_to_var_names_iter =
5279 subdomain_to_var_names.find(sbd_id);
5287 if (subdomain_to_var_names_iter == subdomain_to_var_names.end())
5290 const auto & var_names_this_sbd
5291 = subdomain_to_var_names_iter->second;
5294 if (sbd_id == subdomain_to_n_elem_iter->first)
5302 std::find(var_names_this_sbd.begin(),
5303 var_names_this_sbd.end(),
5304 derived_var_names[var_id]);
5306 libmesh_error_msg_if(pos == var_names_this_sbd.end(),
5307 "Derived name " << derived_var_names[var_id] <<
" not found!");
5312 std::distance(var_names_this_sbd.begin(), pos);
5314 data.push_back(values[values_offset + true_index]);
5319 auto true_offset = var_names_this_sbd.size();
5322 values_offset += true_offset;
5328 ex_err = exII::ex_put_var
5331 exII::EX_ELEM_BLOCK,
5337 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
5348 const std::vector<Real> & values,
5354 if (!values.empty())
5356 libmesh_assert_equal_to(values.size(), std::size_t(
num_nodes));
5358 ex_err = exII::ex_put_var
5367 EX_CHECK_ERR(
ex_err,
"Error writing nodal values.");
5384 int num_info = inquire(*
this, exII::EX_INQ_INFO,
"Error retrieving the number of information records from file!");
5387 libMesh::err <<
"Warning! The Exodus file already contains information records.\n"
5388 <<
"Exodus does not support writing additional records in this situation."
5393 int num_records = cast_int<int>(records.size());
5395 if (num_records > 0)
5397 NamesData info(num_records, MAX_LINE_LENGTH);
5401 for (
const auto & record : records)
5402 info.push_back_entry(record);
5404 ex_err = exII::ex_put_info(
ex_id, num_records, info.get_char_star_star());
5405 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
5418 if (!values.empty())
5420 ex_err = exII::ex_put_var
5429 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
5440 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
5452 ex_err = exII::ex_get_var
5461 EX_CHECK_ERR(
ex_err,
"Error reading global values.");
5481 libmesh_error_msg_if (max_length > libmesh_max_str_length,
5482 "Exodus maximum name length is limited to " <<
5483 libmesh_max_str_length <<
" characters");
5505std::vector<std::string>
5507 bool write_complex_abs)
const
5509 std::vector<std::string> complex_names;
5513 for (
const auto & name : names)
5515 complex_names.push_back(
"r_" + name);
5516 complex_names.push_back(
"i_" + name);
5517 if (write_complex_abs)
5518 complex_names.push_back(
"a_" + name);
5521 return complex_names;
5526std::vector<std::set<subdomain_id_type>>
5529(
const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
5530 bool write_complex_abs)
const
5532 std::vector<std::set<subdomain_id_type>> complex_vars_active_subdomains;
5534 for (
auto & s : vars_active_subdomains)
5538 complex_vars_active_subdomains.push_back(s);
5539 complex_vars_active_subdomains.push_back(s);
5540 if (write_complex_abs)
5541 complex_vars_active_subdomains.push_back(s);
5544 return complex_vars_active_subdomains;
5549std::map<subdomain_id_type, std::vector<std::string>>
5552(
const std::map<
subdomain_id_type, std::vector<std::string>> & subdomain_to_var_names,
5553 bool write_complex_abs)
const
5556 std::map<subdomain_id_type, std::vector<std::string>> ret;
5558 unsigned int num_complex_outputs = write_complex_abs ? 3 : 2;
5560 for (
const auto & pr : subdomain_to_var_names)
5563 auto & vec = ret[pr.first];
5566 const auto & varnames = pr.second;
5569 vec.reserve(num_complex_outputs * varnames.size());
5574 for (
const auto & varname : varnames)
5576 vec.push_back(
"r_" + varname);
5577 vec.push_back(
"i_" + varname);
5578 if (write_complex_abs)
5579 vec.push_back(
"a_" + varname);
5592 libmesh_assert_less (i, node_map->size());
5593 return (*node_map)[i];
5600 if (!inverse_node_map)
5603 libmesh_assert_less (i, inverse_node_map->size());
5604 return (*inverse_node_map)[i];
5616 if (
static_cast<size_t>(i) >= side_map->size())
5619 return (*side_map)[i];
5627 if (!inverse_side_map)
5630 libmesh_assert_less (i, inverse_side_map->size());
5631 return (*inverse_side_map)[i];
5645 libmesh_assert_less (i, shellface_map->size());
5646 return (*shellface_map)[i];
5653 if (!inverse_shellface_map)
5656 libmesh_assert_less (i, inverse_shellface_map->size());
5657 return (*inverse_shellface_map)[i];
5664 return libmesh_type;
5681 return shellface_index_offset;
5685 data_table(n_strings),
5686 data_table_pointers(n_strings),
5688 table_size(n_strings)
5690 for (
size_t i=0; i<n_strings; ++i)
5706 libmesh_assert_less (counter, table_size);
5709 size_t num_copied = name.copy(data_table[counter].data(), data_table[counter].size()-1);
5712 data_table[counter][num_copied] =
'\0';
5722 return data_table_pointers.data();
5729 libmesh_error_msg_if(
static_cast<unsigned>(i) >= table_size,
5730 "Requested char * " << i <<
" but only have " << table_size <<
"!");
5732 return data_table[i].data();
void ErrorVector unsigned int
void max(const T &r, T &o, Request &req) const
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
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.
std::tuple< dof_id_type, unsigned short int, boundary_id_type > BCTuple
Create a list of (element_id, side_id, boundary_id) tuples for relevant sides.
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
std::size_t n_edge_conds() const
std::vector< NodeBCTuple > build_node_list(NodeBCTupleSortBy sort_by=NodeBCTupleSortBy::NODE_ID) const
const std::set< boundary_id_type > & get_edge_boundary_ids() const
std::vector< BCTuple > build_shellface_list() const
Create a list of (element_id, shellface_id, boundary_id) tuples for all relevant shellfaces.
const std::string & get_nodeset_name(boundary_id_type id) const
std::tuple< dof_id_type, boundary_id_type > NodeBCTuple
Create a list of (node_id, boundary_id) tuples for all relevant nodes.
const std::string & get_sideset_name(boundary_id_type id) const
std::string & edgeset_name(boundary_id_type id)
const std::string & get_edgeset_name(boundary_id_type id) const
void build_node_boundary_ids(std::vector< boundary_id_type > &b_ids) const
Builds the list of unique node boundary ids.
void build_side_boundary_ids(std::vector< boundary_id_type > &b_ids) const
Builds the list of unique side boundary ids.
std::vector< BCTuple > build_edge_list() const
Create a list of (element_id, edge_id, boundary_id) tuples for all relevant edges.
void build_shellface_boundary_ids(std::vector< boundary_id_type > &b_ids) const
Builds the list of unique shellface boundary ids.
const std::map< boundary_id_type, std::string > & get_nodeset_name_map() const
const std::map< boundary_id_type, std::string > & get_sideset_name_map() const
The DofObject defines an abstract base class for objects that have degrees of freedom associated with...
dof_id_type get_extra_integer(const unsigned int index) const
Gets the value on this object of the extra integer associated with index, which should have been obta...
processor_id_type processor_id() const
unique_id_type unique_id() const
void set_unique_id(unique_id_type new_id)
Sets the unique_id for this DofObject.
This is the base class from which all geometric element types are derived.
const Point & point(const unsigned int i) const
virtual unsigned int n_nodes() const =0
SimpleRange< NodeRefIter > node_ref_range()
Returns a range with all nodes of an element, usable in range-based for loops.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
static ElemType first_order_equivalent_type(const ElemType et)
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 ...
subdomain_id_type subdomain_id() const
static constexpr 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...
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i)=0
IntRange< unsigned short > edge_index_range() const
virtual ElemType type() const =0
IntRange< unsigned short > node_index_range() const
virtual ElemType side_type(const unsigned int s) const =0
virtual unsigned int n_sides() const =0
dof_id_type node_id(const unsigned int i) const
virtual bool infinite() const =0
IntRange< unsigned short > side_index_range() const
static bool redundant_added_side(const Elem &elem, unsigned int side)
int get_inverse_side_map(int i) const
static const int invalid_id
An invalid_id that can be returned to signal failure in case something goes wrong.
int get_shellface_map(int i) const
int get_node_map(int i) const
int dim
The element dimension; useful since we don't seem to have a cheap way to look this up from ElemType.
int get_inverse_node_map(int i) const
std::string exodus_elem_type() const
int get_side_map(int i) const
int n_nodes
The number of nodes per element; useful likewise.
int get_inverse_shellface_map(int i) const
std::size_t get_shellface_index_offset() const
ElemType libmesh_elem_type() const
This class is useful for managing anything that requires a char ** input/output in ExodusII file.
void push_back_entry(const std::string &name)
Adds another name to the current data table.
char * get_char_star(int i)
Provide access to the i'th underlying char *.
std::vector< std::vector< char > > data_table
char ** get_char_star_star()
Provide access to the underlying C data table.
std::vector< char * > data_table_pointers
NamesData(size_t n_strings, size_t string_length)
Constructor.
This is the ExodusII_IO_Helper class.
void write_as_dimension(unsigned dim)
Sets the value of _write_as_dimension.
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.
void read_block_info()
Reads information for all of the blocks in the ExodusII mesh file.
void update()
Uses ex_update() to flush buffers to file.
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.
std::vector< int > elemset_id_list
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::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...
void read_nodeset_info()
Reads information about all of the nodesets in the ExodusII mesh file.
unsigned int bex_num_elem_cvs
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.
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.
virtual void write_nodal_coordinates(const MeshBase &mesh, bool use_discontinuous=false)
Writes the nodal coordinates contained in "mesh".
ExodusHeaderInfo header_info
void read_node_num_map()
Reads the optional node_num_map from the ExodusII mesh file.
void read_time_steps()
Reads and stores the timesteps in the 'time_steps' array.
bool _add_sides
Set to true iff we want to write separate "side" elements too.
dof_id_type get_libmesh_id(int exodus_id, const std::vector< int > &num_map)
Internal implementation for the two sets of functions above.
std::vector< std::string > get_complex_names(const std::vector< std::string > &names, bool write_complex_abs) const
std::vector< std::string > nodal_var_names
std::vector< int > num_df_per_set
bool _global_vars_initialized
void read_and_store_header_info()
Reads an ExodusII mesh file header, and stores required information on this object.
unsigned _write_as_dimension
ExodusHeaderInfo read_header() const
Reads an ExodusII mesh file header, leaving this object's internal data structures unchanged.
virtual void write_sidesets(const MeshBase &mesh)
Writes the sidesets contained in "mesh".
std::map< int, std::string > id_to_ns_names
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< 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.
std::vector< int > num_elem_df_per_set
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.
int get_node_set_id(int index)
Get the node set id for the given node set index.
std::map< dof_id_type, Real > nodal_var_values
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.
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.
void close() noexcept
Closes the ExodusII mesh file.
void read_qa_records()
Reads the QA records from an ExodusII file.
bool _elem_vars_initialized
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,...
void read_all_nodesets()
New API that reads all nodesets simultaneously.
std::string current_filename
std::vector< int > num_nodes_per_set
std::vector< std::string > sideset_var_names
void read_bex_cv_blocks()
Reads the optional bex_cv_blocks from the ExodusII mesh file.
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,...
void set_dof_object_unique_id(MeshBase &mesh, DofObject *dof_object, int exodus_mapped_id)
dof_id_type get_libmesh_elem_id(int exodus_elem_id)
std::vector< int > ss_ids
std::vector< int > id_list
void message(std::string_view msg)
Prints the message defined in msg.
virtual void write_nodesets(const MeshBase &mesh)
Writes the nodesets contained in "mesh".
std::string get_block_name(int index)
Get the block name for the given block index if supplied in the mesh file.
void write_nodal_values(int var_id, const std::vector< Real > &values, int timestep)
Writes the vector of values to a nodal variable.
void read_elemset_info()
Reads information about all of the elemsets in the ExodusII mesh file.
std::vector< int > side_list
std::vector< std::vector< std::vector< Real > > > bex_dense_constraint_vecs
bool _nodal_vars_initialized
void read_nodes()
Reads the nodal data (x,y,z coordinates) from the ExodusII mesh file.
std::vector< int > node_sets_dist_index
ExodusII_IO_Helper(const ParallelObject &parent, bool v=false, bool run_only_on_proc0=true, bool single_precision=false)
Constructor.
virtual void read_var_names_impl(const char *var_type, int &count, std::vector< std::string > &result)
read_var_names() dispatches to this function.
std::vector< int > num_elems_per_set
virtual ~ExodusII_IO_Helper()
const char * get_elem_type() const
static int get_exodus_version()
bool set_unique_ids_from_maps
std::vector< int > node_num_map
std::vector< int > elem_face_counts
int get_side_set_id(int index)
Get the side set id for the given side set index.
void set_max_name_length(unsigned int max_length)
Set how many characters to use in names when opening a file for writing.
void read_var_names(ExodusVarType type)
void read_sideset(int id, int offset)
Reads information about sideset id and inserts it into the global sideset array at the position offse...
int get_block_id(int index)
Get the block number for the given block index.
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().
void read_elemset(int id, int offset)
Reads information about elemset id and inserts it into the global elemset array at the position offse...
dof_id_type get_libmesh_node_id(int exodus_node_id)
Helper function that takes a (1-based) Exodus node/elem id and determines the corresponding libMesh N...
std::vector< std::vector< int > > c0polyhedron_face_connect
void write_timestep(int timestep, Real time)
Writes the time for the timestep.
void init_element_equivalence_map()
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.
std::vector< std::string > global_var_names
void print_nodes(std::ostream &out_stream=libMesh::out)
Prints the nodal information, by default to libMesh::out.
std::vector< int > elemset_ids
std::vector< int > elem_node_counts
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 conditionally_set_elem_unique_id(MeshBase &mesh, Elem *elem, int zero_based_elem_num_map_index)
std::vector< int > elem_list
virtual void create(std::string filename)
Opens an ExodusII mesh file named filename for writing.
std::map< std::string, ElemType > element_equivalence_map
Defines equivalence classes of Exodus element types that map to libmesh ElemTypes.
std::vector< int > num_sides_per_set
std::vector< std::string > elem_var_names
void print_header()
Prints the ExodusII mesh file header, which includes the mesh title, the number of nodes,...
std::map< dof_id_type, dof_id_type > libmesh_elem_num_to_exodus
void read_global_values(std::vector< Real > &values, int timestep)
Reads the vector of global variables.
void read_edge_blocks(MeshBase &mesh)
Read in edge blocks, storing information in the BoundaryInfo object.
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,...
void open(const char *filename, bool read_only)
Opens an ExodusII mesh file named filename.
virtual void write_elements(const MeshBase &mesh, bool use_discontinuous=false)
Writes the elements contained in "mesh".
std::vector< std::string > elemset_var_names
ExodusVarType
Wraps calls to exII::ex_get_var_names() and exII::ex_get_var_param().
int num_elem_all_elemsets
std::map< dof_id_type, dof_id_type > libmesh_node_num_to_exodus
std::vector< Real > time_steps
void init_conversion_map()
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...
unsigned int _max_name_length
std::map< int, std::map< ElemType, ExodusII_IO_Helper::Conversion > > conversion_map
Associates libMesh ElemTypes with node/face/edge/etc.
std::vector< int > block_ids
void initialize_global_variables(std::vector< std::string > names)
Sets up the global variables.
std::vector< int > connect
std::vector< int > edge_block_ids
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.
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 ...
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::vector< int > nodeset_ids
void set_coordinate_offset(Point p)
Allows you to set a vector that is added to the coordinates of all of the nodes.
void write_information_records(const std::vector< std::string > &records)
Writes the vector of information records.
std::vector< char > & title
int num_elem_all_sidesets
bool _use_mesh_dimension_instead_of_spatial_dimension
std::map< int, std::string > id_to_ss_names
std::vector< int > node_sets_node_index
void read_elem_num_map()
Reads the optional node_num_map from the ExodusII mesh file.
void read_face_blocks()
Reads NSIDED face blocks used by NFACED element blocks.
void read_num_time_steps()
Reads the number of timesteps currently stored in the Exodus file and stores it in the num_time_steps...
std::vector< int > node_sets_node_list
const ExodusII_IO_Helper::Conversion & get_conversion(const ElemType type) const
void initialize_nodal_variables(std::vector< std::string > names)
Sets up the nodal variables.
void write_global_values(const std::vector< Real > &values, int timestep)
Writes the vector of global variables.
std::vector< int > elemset_list
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,...
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.
std::vector< std::string > nodeset_var_names
void conditionally_set_node_unique_id(MeshBase &mesh, Node *node, int zero_based_node_num_map_index)
Helper function that conditionally sets the unique_id of the passed-in Node/Elem.
std::vector< int > num_node_df_per_set
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::vector< std::vector< long unsigned int > > bex_cv_conn
virtual void initialize(std::string title, const MeshBase &mesh, bool use_discontinuous=false)
Initializes the Exodus file.
std::map< int, std::string > id_to_block_names
std::map< int, std::string > id_to_elemset_names
std::vector< Real > node_sets_dist_fact
void write_elemsets(const MeshBase &mesh)
Write elemsets stored on the Mesh to the exo 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 read_elem_in_block(int block)
Reads all of the element connectivity for block block in the ExodusII mesh file.
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...
std::vector< int > elem_num_map
std::vector< char > elem_type
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
This is the MeshBase class.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
virtual const Node * node_ptr(const dof_id_type i) const =0
unsigned int mesh_dimension() const
virtual dof_id_type n_elem() const =0
unsigned int spatial_dimension() const
unsigned int get_elem_integer_index(std::string_view name) const
virtual dof_id_type max_node_id() const =0
virtual const Elem * elem_ptr(const dof_id_type i) const =0
virtual void set_next_unique_id(unique_id_type id)=0
Sets the next available unique id to be used.
bool has_elem_integer(std::string_view name) const
virtual dof_id_type max_elem_id() const =0
unsigned int n_elemsets() const
Returns the number of unique elemset ids which have been added via add_elemset_code(),...
std::string & subdomain_name(subdomain_id_type id)
virtual const Elem & elem_ref(const dof_id_type i) const
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.
std::set< elemset_id_type > elemset_type
Typedef for the "set" container used to store elemset ids.
unique_id_type next_unique_id() const
virtual dof_id_type n_active_elem() const =0
virtual bool is_serial_on_zero() const
A Node is like a Point, but with more information.
An object whose state is distributed along a set of processors.
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
The StoredRange class defines a contiguous, divisible set of objects.
Tnew cast_int(Told oldvar)
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
ElemType
Defines an enum for geometric element types.
void libmesh_ignore(const Args &...)
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
TestClass subdomain_id_type
Based on the 4-byte comment warning above, this probably doesn't work with exodusII at all....
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
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...
const boundary_id_type side_id
This class facilitates inline conversion of an input data vector to a different precision level,...
const std::vector< Real > & our_data
std::vector< float > float_vec
MappedOutputVector(const std::vector< Real > &vec_in, bool single_precision_in)
std::vector< double > double_vec
The FPEDisabler class puts Floating-Point Exception (FPE) trapping on hold during its lifetime,...