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>>
209 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
215 std::set<subdomain_id_type> sbd_ids;
217 if (!sbd_ids.empty())
218 subdomain_id_end = *sbd_ids.rbegin()+1;
222 for (
const auto & elem :
mesh.active_element_ptr_range())
227 if (elem->infinite())
230 subdomain_map[ elem->subdomain_id() ].push_back(elem->id());
237 for (
auto s : elem->side_index_range())
243 subdomain_map[subdomain_id_end + elem->side_type(s)];
251 if (!add_sides && !subdomain_map.empty())
252 subdomain_id_end = subdomain_map.rbegin()->first + 1;
256 if (!subdomain_map.empty())
257 next_block_id = cast_int<int>(subdomain_map.rbegin()->first) + 1;
259 return subdomain_map;
273 bool run_only_on_proc0,
274 bool single_precision) :
279 title(header_info.title),
280 num_dim(header_info.num_dim),
281 num_nodes(header_info.num_nodes),
282 num_elem(header_info.num_elem),
283 num_elem_blk(header_info.num_elem_blk),
284 num_edge(header_info.num_edge),
285 num_edge_blk(header_info.num_edge_blk),
286 num_face(header_info.num_face),
287 num_face_blk(header_info.num_face_blk),
288 num_node_sets(header_info.num_node_sets),
289 num_side_sets(header_info.num_side_sets),
290 num_elem_sets(header_info.num_elem_sets),
295 num_elem_this_blk(0),
296 num_nodes_per_elem(0),
298 num_elem_all_sidesets(0),
299 num_elem_all_elemsets(0),
305 set_unique_ids_from_maps(false),
306 opened_for_writing(false),
307 opened_for_reading(false),
308 _run_only_on_proc0(run_only_on_proc0),
309 _opened_by_create(false),
310 _elem_vars_initialized(false),
311 _global_vars_initialized(false),
312 _nodal_vars_initialized(false),
313 _use_mesh_dimension_instead_of_spatial_dimension(false),
315 _max_name_length(32),
317 _write_as_dimension(0),
318 _single_precision(single_precision)
320 title.resize(MAX_LINE_LENGTH+1);
321 elem_type.resize(libmesh_max_str_length);
334 return EX_API_VERS_NODOT;
342 auto convert_type = [
this](
ElemType type,
343 std::string_view exodus_type,
344 const std::vector<int> * node_map =
nullptr,
345 const std::vector<int> * inverse_node_map =
nullptr,
346 const std::vector<int> * side_map =
nullptr,
347 const std::vector<int> * inverse_side_map =
nullptr,
348 const std::vector<int> * shellface_map =
nullptr,
349 const std::vector<int> * inverse_shellface_map =
nullptr,
350 size_t shellface_index_offset = 0)
354 conv.libmesh_type = type;
355 conv.exodus_type = exodus_type;
356 conv.node_map = node_map;
357 conv.inverse_node_map = inverse_node_map;
358 conv.side_map = side_map;
359 conv.inverse_side_map = inverse_side_map;
360 conv.shellface_map = shellface_map;
361 conv.inverse_shellface_map = inverse_shellface_map;
362 conv.shellface_index_offset = shellface_index_offset;
363 conv.n_nodes = elem->n_nodes();
364 for (
int d = elem->dim()+1; d <= 3; ++d)
369 convert_type(
EDGE2,
"EDGE2");
370 convert_type(
EDGE3,
"EDGE3");
371 convert_type(
EDGE4,
"EDGE4");
372 convert_type(
QUAD4,
"QUAD4");
373 convert_type(
QUAD8,
"QUAD8");
374 convert_type(
QUAD9,
"QUAD9");
379 conv.exodus_type =
"NFACED";
383 convert_type(
QUADSHELL4,
"SHELL4",
nullptr,
nullptr,
nullptr,
384 &quadshell4_inverse_edge_map,
385 nullptr,
nullptr, 2);
386 convert_type(
QUADSHELL8,
"SHELL8",
nullptr,
nullptr,
nullptr,
387 &quadshell4_inverse_edge_map,
388 nullptr,
nullptr, 2);
389 convert_type(
QUADSHELL9,
"SHELL9",
nullptr,
nullptr,
nullptr,
390 &quadshell4_inverse_edge_map,
391 nullptr,
nullptr, 2);
393 convert_type(
TRI3,
"TRI3");
394 convert_type(
TRI6,
"TRI6");
395 convert_type(
TRI7,
"TRI7");
405 convert_type(
TRISHELL3,
"TRISHELL3",
nullptr,
nullptr,
nullptr,
406 &trishell3_inverse_edge_map,
407 nullptr,
nullptr, 2);
409 convert_type(
HEX8,
"HEX8",
nullptr,
nullptr,
410 &hex_face_map, &hex_inverse_face_map);
411 convert_type(
HEX20,
"HEX20",
nullptr,
nullptr,
412 &hex_face_map, &hex_inverse_face_map);
413 convert_type(
HEX27,
"HEX27", &hex27_node_map,
414 &hex27_inverse_node_map,
415 &hex_face_map, &hex_inverse_face_map);
416 convert_type(
TET4,
"TETRA4",
nullptr,
nullptr,
417 &tet_face_map, &tet_inverse_face_map);
418 convert_type(
TET10,
"TETRA10",
nullptr,
nullptr,
419 &tet_face_map, &tet_inverse_face_map);
420 convert_type(
TET14,
"TETRA14", &tet14_node_map,
421 &tet14_inverse_node_map,
422 &tet_face_map, &tet_inverse_face_map);
423 convert_type(
PRISM6,
"WEDGE",
nullptr,
nullptr,
424 &prism_face_map, &prism_inverse_face_map);
425 convert_type(
PRISM15,
"WEDGE15",
nullptr,
nullptr,
426 &prism_face_map, &prism_inverse_face_map);
427 convert_type(
PRISM18,
"WEDGE18",
nullptr,
nullptr,
428 &prism_face_map, &prism_inverse_face_map);
429 convert_type(
PRISM20,
"WEDGE20", &prism20_node_map,
430 &prism20_inverse_node_map,
431 &prism_face_map, &prism_inverse_face_map);
432 convert_type(
PRISM21,
"WEDGE21", &prism21_node_map,
433 &prism21_inverse_node_map,
434 &prism_face_map, &prism_inverse_face_map);
575 return libmesh_map_find(maps_for_dim, type);
582 std::transform(type_str.begin(), type_str.end(), type_str.begin(), ::toupper);
608 bool single_precision_in)
609 : our_data(our_data_in),
610 single_precision(single_precision_in)
614 if (
sizeof(
Real) !=
sizeof(
float))
623 else if (
sizeof(
Real) !=
sizeof(double))
635 if (single_precision)
637 if (
sizeof(
Real) !=
sizeof(
float))
638 return static_cast<void*
>(float_vec.data());
641 else if (
sizeof(
Real) !=
sizeof(double))
642 return static_cast<void*
>(double_vec.data());
645 return const_cast<void *
>(
static_cast<const void *
>(our_data.data()));
650 bool single_precision_in)
651 : our_data(our_data_in),
652 single_precision(single_precision_in)
657 if (
sizeof(
Real) !=
sizeof(
float))
660 else if (
sizeof(
Real) !=
sizeof(
double))
667 if (single_precision)
669 if (
sizeof(
Real) !=
sizeof(
float))
670 our_data.assign(float_vec.begin(), float_vec.end());
672 else if (
sizeof(
Real) !=
sizeof(
double))
673 our_data.assign(double_vec.begin(), double_vec.end());
679 if (single_precision)
681 if (
sizeof(
Real) !=
sizeof(
float))
682 return static_cast<void*
>(float_vec.data());
685 else if (
sizeof(
Real) !=
sizeof(double))
686 return static_cast<void*
>(double_vec.data());
689 return static_cast<void *
>(our_data.data());
695 float ex_version = 0.;
700 comp_ws = cast_int<int>(
sizeof(
float));
705 comp_ws = cast_int<int>(std::min(
sizeof(
Real),
sizeof(
double)));
714 ex_id = exII::ex_open(filename,
715 read_only ? EX_READ : EX_WRITE,
721 std::string err_msg = std::string(
"Error opening ExodusII mesh file: ") + std::string(filename);
722 EX_CHECK_ERR(
ex_id, err_msg);
739 int max_name_length = exII::ex_inquire_int(
ex_id, exII::EX_INQ_DB_MAX_USED_NAME_LENGTH);
741 libmesh_error_msg_if(max_name_length > MAX_LINE_LENGTH,
742 "Unexpected maximum name length of " <<
743 max_name_length <<
" in file " << filename <<
744 " exceeds expected " << MAX_LINE_LENGTH);
748 max_name_length_to_set = std::max(max_name_length, 32);
753 ex_err = exII::ex_set_max_name_length(
ex_id, max_name_length_to_set);
754 EX_CHECK_ERR(
ex_err,
"Error setting max ExodusII name length.");
769 exII::ex_init_params params = {};
770 int err_flag = exII::ex_get_init_ext(
ex_id, ¶ms);
771 EX_CHECK_ERR(err_flag,
"Error retrieving header info.");
775 h.
title.assign(params.title, params.title + MAX_LINE_LENGTH);
805 EX_CHECK_ERR(
ex_err,
"Error reading number of nodal variables.");
808 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
811 EX_CHECK_ERR(
ex_err,
"Error reading number of global variables.");
814 EX_CHECK_ERR(
ex_err,
"Error reading number of sideset variables.");
817 EX_CHECK_ERR(
ex_err,
"Error reading number of nodeset variables.");
820 EX_CHECK_ERR(
ex_err,
"Error reading number of elemset variables.");
822 message(
"Exodus header info retrieved successfully.");
832 inquire(*
this, exII::EX_INQ_QA,
"Error retrieving number of QA records");
837 <<
" QA record(s) in the Exodus file."
846 std::vector<std::vector<std::vector<char>>> qa_storage(num_qa_rec);
849 qa_storage[i].resize(4);
851 qa_storage[i][j].resize(libmesh_max_str_length+1);
855 typedef char * inner_array_t[4];
862 auto qa_record = std::make_unique<inner_array_t[]>(num_qa_rec);
868 qa_record[i][j] = qa_storage[i][j].data();
871 EX_CHECK_ERR(
ex_err,
"Error reading the QA records.");
893 <<
"Mesh Dimension: \t" <<
num_dim << std::endl
894 <<
"Number of Nodes: \t" <<
num_nodes << std::endl
895 <<
"Number of elements: \t" <<
num_elem << std::endl
896 <<
"Number of elt blocks: \t" <<
num_elem_blk << std::endl
906 LOG_SCOPE(
"read_nodes()",
"ExodusII_IO_Helper");
914 ex_err = exII::ex_get_coord
920 EX_CHECK_ERR(
ex_err,
"Error retrieving nodal data.");
921 message(
"Nodal data retrieved successfully.");
926 int n_nodal_attr = 0;
927 ex_err = exII::ex_get_attr_param(
ex_id, exII::EX_NODAL, 0, & n_nodal_attr);
928 EX_CHECK_ERR(
ex_err,
"Error getting number of nodal attributes.");
930 if (n_nodal_attr > 0)
932 std::vector<std::vector<char>> attr_name_data
933 (n_nodal_attr, std::vector<char>(libmesh_max_str_length + 1));
934 std::vector<char *> attr_names(n_nodal_attr);
936 attr_names[i] = attr_name_data[i].data();
938 ex_err = exII::ex_get_attr_names(
ex_id, exII::EX_NODAL, 0, attr_names.data());
939 EX_CHECK_ERR(
ex_err,
"Error getting nodal attribute names.");
942 if (std::string(
"bex_weight") == attr_names[i])
946 exII::ex_get_one_attr (
ex_id, exII::EX_NODAL, 0, i+1,
948 EX_CHECK_ERR(
ex_err,
"Error getting Bezier Extraction nodal weights");
963 ex_err = exII::ex_get_node_num_map
966 EX_CHECK_ERR(
ex_err,
"Error retrieving nodal number map.");
967 message(
"Nodal numbering map retrieved successfully.");
972 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_nodes-1)); ++i)
985#if EX_API_VERS_NODOT >= 800
986 int n_blobs = exII::ex_inquire_int(
ex_id, exII::EX_INQ_BLOB);
990 std::vector<exII::ex_blob> blobs(n_blobs);
991 std::vector<std::vector<char>> blob_names(n_blobs);
994 blob_names[i].resize(libmesh_max_str_length+1);
995 blobs[i].name = blob_names[i].data();
999 EX_CHECK_ERR(
ex_err,
"Error getting blobs.");
1001 bool found_blob =
false;
1002 const exII::ex_blob * my_blob = &blobs[0];
1003 for (
const auto & blob : blobs)
1005 if (std::string(
"bex_cv_blob") == blob.name)
1013 libmesh_error_msg(
"Found no bex_cv_blob for bezier elements");
1015 const int n_blob_attr =
1016 exII::ex_get_attribute_count(
ex_id, exII::EX_BLOB,
1019 std::vector<exII::ex_attribute> attributes(n_blob_attr);
1020 ex_err = exII::ex_get_attribute_param(
ex_id, exII::EX_BLOB,
1023 EX_CHECK_ERR(
ex_err,
"Error getting bex blob attribute parameters.");
1025 int bex_num_dense_cv_blocks = 0;
1026 std::vector<int> bex_dense_cv_info;
1027 for (
auto & attr : attributes)
1029 if (std::string(
"bex_dense_cv_info") == attr.name)
1031 const std::size_t value_count = attr.value_count;
1032 if (value_count % 2)
1033 libmesh_error_msg(
"Found odd number of bex_dense_cv_info");
1035 bex_dense_cv_info.resize(value_count);
1036 attr.values = bex_dense_cv_info.data();
1037 exII::ex_get_attribute(
ex_id, &attr);
1039 bex_num_dense_cv_blocks = value_count / 2;
1041 libmesh_error_msg_if(bex_num_dense_cv_blocks > 1,
1042 "Found more than 1 dense bex CV block; unsure how to handle that");
1046 if (bex_dense_cv_info.empty())
1047 libmesh_error_msg(
"No bex_dense_cv_info found");
1050 exII::ex_get_variable_param(
ex_id, exII::EX_BLOB, &n_blob_vars);
1051 std::vector<char> var_name (libmesh_max_str_length + 1);
1052 for (
auto v_id :
make_range(1,n_blob_vars+1))
1054 ex_err = exII::ex_get_variable_name(
ex_id, exII::EX_BLOB, v_id, var_name.data());
1055 EX_CHECK_ERR(
ex_err,
"Error reading bex blob var name.");
1057 if (std::string(
"bex_dense_cv_blocks") == var_name.data())
1059 std::vector<double> bex_dense_cv_blocks(my_blob->num_entry);
1061 ex_err = exII::ex_get_var(
ex_id, 1, exII::EX_BLOB, v_id,
1062 my_blob->id, my_blob->num_entry,
1063 bex_dense_cv_blocks.data());
1064 EX_CHECK_ERR(
ex_err,
"Error reading bex_dense_cv_blocks.");
1069 std::size_t offset = 0;
1073 const int vecsize = bex_dense_cv_info[2*i+1];
1076 vec.resize(vecsize);
1077 std::copy(std::next(bex_dense_cv_blocks.begin(), offset),
1078 std::next(bex_dense_cv_blocks.begin(), offset + vecsize),
1094 out_stream <<
"(" <<
x[i] <<
", " <<
y[i] <<
", " <<
z[i] <<
")" << std::endl;
1106 exII::EX_ELEM_BLOCK,
1109 EX_CHECK_ERR(
ex_err,
"Error getting block IDs.");
1110 message(
"All block IDs retrieved successfully.");
1112 char name_buffer[libmesh_max_str_length+1];
1115 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_BLOCK,
1117 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
1120 message(
"All block names retrieved successfully.");
1128 exII::EX_EDGE_BLOCK,
1131 EX_CHECK_ERR(
ex_err,
"Error getting edge block IDs.");
1132 message(
"All edge block IDs retrieved successfully.");
1135 char name_buffer[libmesh_max_str_length+1];
1138 ex_err = exII::ex_get_name(
ex_id, exII::EX_EDGE_BLOCK,
1140 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
1143 message(
"All edge block names retrieved successfully.");
1151 libmesh_assert_less (index,
block_ids.size());
1160 libmesh_assert_less (index,
block_ids.size());
1169 libmesh_assert_less (index,
ss_ids.size());
1178 libmesh_assert_less (index,
ss_ids.size());
1204 LOG_SCOPE(
"read_face_blocks()",
"ExodusII_IO_Helper");
1210 "Error: Exodus NFACED element block found, "
1211 "but the file has no face blocks.");
1215 exII::EX_FACE_BLOCK,
1216 face_block_ids.data());
1217 EX_CHECK_ERR(
ex_err,
"Error getting face block IDs.");
1224 std::vector<char> face_type(libmesh_max_str_length+1);
1225 int num_face_this_blk = 0;
1226 int num_node_data_this_blk = 0;
1227 int num_edges_per_face = 0;
1228 int num_faces_per_face = 0;
1229 int num_attr_face = 0;
1232 exII::EX_FACE_BLOCK,
1233 face_block_ids[block],
1236 &num_node_data_this_blk,
1237 &num_edges_per_face,
1238 &num_faces_per_face,
1240 EX_CHECK_ERR(
ex_err,
"Error getting face block info.");
1242 const auto & conv =
get_conversion(std::string(face_type.data()));
1243 libmesh_error_msg_if(conv.libmesh_elem_type() !=
C0POLYGON,
1244 "Error: NFACED polyhedron input currently expects "
1245 "NSIDED face blocks, but face block "
1246 << face_block_ids[block] <<
" has Exodus type "
1247 << face_type.data() <<
".");
1249 libmesh_error_msg_if
1250 (!(num_edges_per_face == 0) && !(num_edges_per_face == -1),
1251 "Error: Exodus NSIDED face block "
1252 << face_block_ids[block]
1253 <<
" has edge connectivity, which NFACED polyhedron input "
1254 <<
"does not currently support.");
1255 libmesh_error_msg_if
1256 (!(num_faces_per_face == 0) && !(num_faces_per_face == -1),
1257 "Error: Exodus NSIDED face block "
1258 << face_block_ids[block]
1259 <<
" has face-in-face connectivity, which NFACED polyhedron "
1260 <<
"input does not currently support.");
1262 std::vector<int> face_node_counts(num_face_this_blk);
1263 if (!face_node_counts.empty())
1265 ex_err = exII::ex_get_entity_count_per_polyhedra
1267 exII::EX_FACE_BLOCK,
1268 face_block_ids[block],
1269 face_node_counts.data());
1270 EX_CHECK_ERR(
ex_err,
"Error reading polyhedron face node counts");
1273 int counted_nodes = 0;
1274 for (
const auto count : face_node_counts)
1275 counted_nodes += count;
1277 libmesh_error_msg_if(counted_nodes != num_node_data_this_blk,
1278 "Error: Exodus NSIDED face block "
1279 << face_block_ids[block]
1280 <<
" says it has " << num_node_data_this_blk
1281 <<
" total node entries, but its per-face "
1282 <<
"node counts sum to " << counted_nodes <<
".");
1284 std::vector<int> face_connect(num_node_data_this_blk);
1285 if (!face_connect.empty())
1288 exII::EX_FACE_BLOCK,
1289 face_block_ids[block],
1290 face_connect.data(),
1293 EX_CHECK_ERR(
ex_err,
"Error reading polyhedron face connectivity.");
1296 std::size_t offset = 0;
1297 for (
const auto count : face_node_counts)
1299 libmesh_error_msg_if(count < 3,
1300 "Error: Exodus NSIDED face block "
1301 << face_block_ids[block]
1302 <<
" has a face with only "
1303 << count <<
" nodes.");
1306 (face_connect.begin() + offset,
1307 face_connect.begin() + offset + count);
1314 "Error: Exodus file says it has "
1315 <<
num_face <<
" faces, but its face blocks contain "
1324 LOG_SCOPE(
"read_elem_in_block()",
"ExodusII_IO_Helper");
1326 libmesh_assert_less (block,
block_ids.size());
1331 int num_edges_per_elem = 0;
1332 int num_faces_per_elem = 0;
1333 int num_node_data_per_elem = 0;
1335 exII::EX_ELEM_BLOCK,
1339 &num_node_data_per_elem,
1340 &num_edges_per_elem,
1341 &num_faces_per_elem,
1344 EX_CHECK_ERR(
ex_err,
"Error getting block info.");
1345 message(
"Info retrieved successfully for block: ", block);
1350 const bool is_bezier = is_bezier_elem(
elem_type.data());
1355 const bool is_c0polygon =
1357 const bool is_c0polyhedron =
1363 if (is_c0polyhedron && !(num_edges_per_elem == 0) && !(num_edges_per_elem == -1))
1364 libmesh_error_msg(
"Error: Exodus NFACED element blocks with edge "
1365 "connectivity are not currently supported.");
1366 else if (!(num_edges_per_elem == 0) && !(num_edges_per_elem == -1))
1367 libmesh_warning(
"Exodus files with extended edge connectivity not currently supported.");
1368 if (!is_c0polyhedron && !(num_faces_per_elem == 0) && !(num_faces_per_elem == -1))
1369 libmesh_warning(
"Exodus files with extended face connectivity not currently supported.");
1379 else if (is_c0polygon)
1385 ex_err = exII::ex_get_entity_count_per_polyhedra
1387 exII::EX_ELEM_BLOCK,
1390 EX_CHECK_ERR(
ex_err,
"Error reading polygon node counts");
1393 int counted_nodes = 0;
1395 counted_nodes += count;
1397 libmesh_error_msg_if(counted_nodes != num_node_data_per_elem,
1398 "Error: Exodus NSIDED block "
1400 <<
" says it has " << num_node_data_per_elem
1401 <<
" total node entries, but its per-element "
1402 <<
"node counts sum to " << counted_nodes <<
".");
1406 else if (is_c0polyhedron)
1415 ex_err = exII::ex_get_entity_count_per_polyhedra
1417 exII::EX_ELEM_BLOCK,
1420 EX_CHECK_ERR(
ex_err,
"Error reading polyhedron face counts");
1423 int counted_faces = 0;
1425 counted_faces += count;
1427 libmesh_error_msg_if(counted_faces != num_faces_per_elem,
1428 "Error: Exodus NFACED block "
1430 <<
" says it has " << num_faces_per_elem
1431 <<
" total face entries, but its per-element "
1432 <<
"face counts sum to " << counted_faces <<
".");
1445 <<
" total node entries.";
1446 else if (is_c0polyhedron)
1448 <<
" total face entries.";
1451 <<
" nodes per element.";
1459 num_node_data_per_elem :
1461 num_faces_per_elem :
1467 exII::EX_ELEM_BLOCK,
1469 is_c0polyhedron ?
nullptr :
connect.data(),
1471 is_c0polyhedron ?
connect.data() :
nullptr);
1473 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
1474 message(
"Connectivity retrieved successfully for block: ", block);
1482#if EX_API_VERS_NODOT >= 800
1483 int real_n_attr = exII::ex_get_attribute_count(
ex_id, exII::EX_ELEM_BLOCK,
block_ids[block]);
1484 EX_CHECK_ERR(real_n_attr,
"Error getting number of element block attributes.");
1486 if (real_n_attr > 0)
1488 std::vector<exII::ex_attribute> attributes(real_n_attr);
1490 ex_err = exII::ex_get_attribute_param(
ex_id, exII::EX_ELEM_BLOCK,
block_ids[block], attributes.data());
1491 EX_CHECK_ERR(
ex_err,
"Error getting element block attribute parameters.");
1493 ex_err = exII::ex_get_attributes(
ex_id, real_n_attr, attributes.data());
1494 EX_CHECK_ERR(
ex_err,
"Error getting element block attribute values.");
1496 for (
auto attr : attributes)
1498 if (std::string(
"bex_elem_degrees") == attr.name)
1500 if (attr.type != exII::EX_INTEGER)
1501 libmesh_error_msg(
"Found non-integer bex_elem_degrees");
1503 if (attr.value_count > 3)
1504 libmesh_error_msg(
"Looking for at most 3 bex_elem_degrees; found " << attr.value_count);
1508 std::vector<int> bex_elem_degrees(3);
1510 const int * as_int =
static_cast<int *
>(attr.values);
1511 std::copy(as_int, as_int+attr.value_count, bex_elem_degrees.begin());
1520 libmesh_assert_equal_to(bex_elem_degrees[d], 2);
1546 auto src = old_connect.data();
1569 LOG_SCOPE(
"read_edge_blocks()",
"ExodusII_IO_Helper");
1585 typedef std::pair<dof_id_type, unsigned int> ElemEdgePair;
1586 std::unordered_map<dof_id_type, std::vector<ElemEdgePair>> edge_map;
1587 std::unique_ptr<Elem> edge_ptr;
1588 for (
const auto & elem :
mesh.element_ptr_range())
1589 for (
auto e : elem->edge_index_range())
1591 elem->build_edge_ptr(edge_ptr, e);
1595 auto & vec = edge_map[edge_key];
1596 vec.emplace_back(elem->id(), e);
1603 if (edge_ptr->default_order() !=
FIRST)
1606 auto low_order_edge =
1610 for (
unsigned int v=0; v<edge_ptr->n_vertices(); ++v)
1611 low_order_edge->set_node(v, edge_ptr->node_ptr(v));
1614 dof_id_type low_order_edge_key = low_order_edge->key();
1618 auto & low_order_vec = edge_map[low_order_edge_key];
1619 low_order_vec.emplace_back(elem->id(), e);
1632 int num_edge_this_blk = 0;
1633 int num_nodes_per_edge = 0;
1634 int num_edges_per_edge = 0;
1635 int num_faces_per_edge = 0;
1636 int num_attr_per_edge = 0;
1638 exII::EX_EDGE_BLOCK,
1642 &num_nodes_per_edge,
1643 &num_edges_per_edge,
1644 &num_faces_per_edge,
1645 &num_attr_per_edge);
1647 EX_CHECK_ERR(
ex_err,
"Error getting edge block info.");
1648 message(
"Info retrieved successfully for block: ", edge_block_id);
1653 connect.resize(num_nodes_per_edge * num_edge_this_blk);
1658 exII::EX_EDGE_BLOCK,
1664 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
1665 message(
"Connectivity retrieved successfully for block: ", edge_block_id);
1674 for (
auto [i, sz] = std::make_tuple(0u,
connect.size()); i<sz; i+=num_nodes_per_edge)
1676 auto edge =
Elem::build(conv.libmesh_elem_type());
1677 for (
int n=0; n<num_nodes_per_edge; ++n)
1679 auto exodus_node_id = this->
connect[i+n];
1690 auto & elem_edge_pair_vec =
1691 libmesh_map_find(edge_map, edge_key);
1693 for (
const auto & elem_edge_pair : elem_edge_pair_vec)
1705 build_edge_ptr(edge_ptr, elem_edge_pair.second);
1714 ((edge_ptr->node_id(0) == edge->node_id(0)) && (edge_ptr->node_id(1) == edge->node_id(1))) ||
1715 ((edge_ptr->node_id(0) == edge->node_id(1)) && (edge_ptr->node_id(1) == edge->node_id(0)));
1721 elem_edge_pair.second,
1743 ex_err = exII::ex_get_elem_num_map
1746 EX_CHECK_ERR(
ex_err,
"Error retrieving element number map.");
1747 message(
"Element numbering map retrieved successfully.");
1766 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_elem-1)); ++i)
1782 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset information.");
1783 message(
"All sideset information retrieved successfully.");
1790 num_elem_all_sidesets = inquire(*
this, exII::EX_INQ_SS_ELEM_LEN,
"Error retrieving length of the concatenated side sets element list!");
1797 char name_buffer[libmesh_max_str_length+1];
1800 ex_err = exII::ex_get_name(
ex_id, exII::EX_SIDE_SET,
1802 EX_CHECK_ERR(
ex_err,
"Error getting side set name.");
1805 message(
"All side set names retrieved successfully.");
1817 EX_CHECK_ERR(
ex_err,
"Error retrieving nodeset information.");
1818 message(
"All nodeset information retrieved successfully.");
1825 char name_buffer[libmesh_max_str_length+1];
1828 ex_err = exII::ex_get_name(
ex_id, exII::EX_NODE_SET,
1830 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1833 message(
"All node set names retrieved successfully.");
1846 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset information.");
1847 message(
"All elemset information retrieved successfully.");
1855 inquire(*
this, exII::EX_INQ_ELS_LEN,
1856 "Error retrieving length of the concatenated elem sets element list!");
1865 char name_buffer[libmesh_max_str_length+1];
1868 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_SET,
1870 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1873 message(
"All elem set names retrieved successfully.");
1880 LOG_SCOPE(
"read_sideset()",
"ExodusII_IO_Helper");
1882 libmesh_assert_less (
id,
ss_ids.size());
1885 libmesh_assert_less_equal (offset,
elem_list.size());
1886 libmesh_assert_less_equal (offset,
side_list.size());
1893 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset parameters.");
1894 message(
"Parameters retrieved successfully for sideset: ",
id);
1900 if (
static_cast<unsigned int>(offset) ==
elem_list.size() ||
1901 static_cast<unsigned int>(offset) ==
side_list.size() )
1915 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset data.");
1916 message(
"Data retrieved successfully for sideset: ",
id);
1927 LOG_SCOPE(
"read_elemset()",
"ExodusII_IO_Helper");
1932 libmesh_assert_less_equal (offset,
elemset_list.size());
1939 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset parameters.");
1940 message(
"Parameters retrieved successfully for elemset: ",
id);
1946 if (
static_cast<unsigned int>(offset) ==
elemset_list.size())
1959 EX_CHECK_ERR(
ex_err,
"Error retrieving elemset data.");
1960 message(
"Data retrieved successfully for elemset: ",
id);
1972 LOG_SCOPE(
"read_all_nodesets()",
"ExodusII_IO_Helper");
1978 (*
this, exII::EX_INQ_NODE_SETS,
1979 "Error retrieving number of node sets");
1982 int total_nodes_in_all_sets =
1984 (*
this, exII::EX_INQ_NS_NODE_LEN,
1985 "Error retrieving number of nodes in all node sets.");
1988 int total_df_in_all_sets =
1990 (*
this, exII::EX_INQ_NS_DF_LEN,
1991 "Error retrieving number of distribution factors in all node sets.");
2011 exII::ex_set_specs set_specs = {};
2018 set_specs.sets_extra_list =
nullptr;
2019 set_specs.sets_dist_fact = total_df_in_all_sets ? mapped_node_sets_dist_fact.
data() :
nullptr;
2021 ex_err = exII::ex_get_concat_sets(
ex_id, exII::EX_NODE_SET, &set_specs);
2022 EX_CHECK_ERR(
ex_err,
"Error reading concatenated nodesets");
2025 char name_buffer[libmesh_max_str_length+1];
2028 ex_err = exII::ex_get_name
2033 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
2064 message(
"Error closing Exodus file.");
2066 message(
"Exodus file closed successfully.");
2087 ex_err = exII::ex_get_all_times
2090 EX_CHECK_ERR(
ex_err,
"Error reading timesteps!");
2099 inquire(*
this, exII::EX_INQ_TIME,
"Error retrieving number of time steps");
2106 LOG_SCOPE(
"read_nodal_var_values()",
"ExodusII_IO_Helper");
2112 unsigned int var_index = 0;
2129 libmesh_error_msg(
"Unable to locate variable named: " << nodal_var_name);
2135 std::vector<Real> unmapped_nodal_var_values(
num_nodes);
2138 ex_err = exII::ex_get_var
2146 EX_CHECK_ERR(
ex_err,
"Error reading nodal variable values!");
2191 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
2199 std::vector<std::string> & result)
2202 ex_err = exII::ex_get_var_param(
ex_id, var_type, &count);
2203 EX_CHECK_ERR(
ex_err,
"Error reading number of variables.");
2210 NamesData names_table(count, libmesh_max_str_length);
2217 EX_CHECK_ERR(
ex_err,
"Error reading variable names!");
2221 libMesh::out <<
"Read the variable(s) from the file:" << std::endl;
2222 for (
int i=0; i<count; i++)
2227 result.resize(count);
2230 for (
int i=0; i<count; i++)
2239 const std::vector<std::string> & names)
2271 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
2280 const std::vector<std::string> & names)
2283 count = cast_int<int>(names.size());
2286 ex_err = exII::ex_put_var_param(
ex_id, var_type, count);
2287 EX_CHECK_ERR(
ex_err,
"Error setting number of vars.");
2299 for (
int i=0; i != count; ++i)
2303 "*** Warning, Exodus variable name \"" <<
2304 names[i] <<
"\" too long (current max " <<
2306 " characters). Name will be truncated. ");
2312 libMesh::out <<
"Writing variable name(s) to file: " << std::endl;
2313 for (
int i=0; i != count; ++i)
2323 EX_CHECK_ERR(
ex_err,
"Error writing variable names.");
2331 std::map<dof_id_type, Real> & elem_var_value_map)
2333 LOG_SCOPE(
"read_elemental_var_values()",
"ExodusII_IO_Helper");
2338 unsigned int var_index = 0;
2355 libmesh_error_msg(
"Unable to locate variable named: " << elemental_var_name);
2359 unsigned ex_el_num = 0;
2365 for (
unsigned i=0; i<static_cast<unsigned>(
num_elem_blk); i++)
2368 exII::EX_ELEM_BLOCK,
2376 EX_CHECK_ERR(
ex_err,
"Error getting number of elements in block.");
2389 ex_err = exII::ex_get_var
2392 exII::EX_ELEM_BLOCK,
2397 EX_CHECK_ERR(
ex_err,
"Error getting elemental values.");
2404 auto libmesh_elem_id =
2408 elem_var_value_map[libmesh_elem_id] = block_elem_var_values[j];
2430 const std::vector<int> & num_map)
2435 auto exodus_id_zero_based =
2436 cast_int<dof_id_type>(exodus_id - 1);
2442 libmesh_error_msg_if(exodus_id_zero_based >= num_map.size(),
2443 "Cannot get LibMesh id for Exodus id: " << exodus_id);
2453 cast_int<dof_id_type>(exodus_id_zero_based) :
2454 cast_int<dof_id_type>(num_map[exodus_id_zero_based] - 1);
2479 int exodus_mapped_id)
2486 auto exodus_mapped_id_zero_based =
2487 cast_int<dof_id_type>(exodus_mapped_id - 1);
2490 dof_object->
set_unique_id(cast_int<unique_id_type>(exodus_mapped_id_zero_based));
2500#ifdef LIBMESH_ENABLE_UNIQUE_ID
2526 comp_ws = cast_int<int>(
sizeof(
float));
2527 io_ws = cast_int<int>(
sizeof(
float));
2533 comp_ws = cast_int<int>
2534 (std::min(
sizeof(
Real),
sizeof(
double)));
2535 io_ws = cast_int<int>
2536 (std::min(
sizeof(
Real),
sizeof(
double)));
2542 int mode = EX_CLOBBER;
2547#ifdef LIBMESH_HAVE_HDF5
2551 mode |= EX_NOCLASSIC;
2557 ex_id = exII::ex_create(filename.c_str(), mode, &comp_ws, &io_ws);
2560 EX_CHECK_ERR(
ex_id,
"Error creating ExodusII/Nemesis mesh file.");
2567 EX_CHECK_ERR(
ex_err,
"Error setting max ExodusII name length.");
2570 libMesh::out <<
"File created successfully." << std::endl;
2585 libmesh_parallel_only(
mesh.
comm());
2593 int c0polyhedron_face_block_id = -1;
2594 auto subdomain_map = build_subdomain_map(
mesh,
2597 c0polyhedron_face_block_id);
2605 bool has_c0polyhedron =
false;
2606 for (
const auto & elem :
mesh.active_local_element_ptr_range())
2609 has_c0polyhedron =
true;
2610 local_num_c0polyhedron_faces += elem->n_sides();
2615 if (has_c0polyhedron)
2617 num_face = cast_int<int>(local_num_c0polyhedron_faces);
2631 for (
const auto & elem :
mesh.active_local_element_ptr_range())
2633 for (
auto s : elem->side_index_range())
2639 num_local_side_nodes += elem->nodes_on_side(s).size();
2656 (std::distance(
mesh.local_nodes_begin(),
2657 mesh.local_nodes_end()));
2662 const dof_id_type n_gaps = max_nn - n_total_nodes;
2663 const dof_id_type gaps_per_processor = n_gaps / n_proc;
2664 const dof_id_type remainder_gaps = n_gaps % n_proc;
2666 n_local_nodes = n_local_nodes +
2667 gaps_per_processor +
2687 if (!use_discontinuous)
2692 num_nodes += cast_int<int>(std::distance(
mesh.nodes_begin(),
2697 for (
const auto & elem :
mesh.active_element_ptr_range())
2701 std::set<boundary_id_type> unique_side_boundaries;
2702 std::vector<boundary_id_type> unique_node_boundaries;
2707 std::vector<boundary_id_type> side_boundaries;
2709 unique_side_boundaries.insert(side_boundaries.begin(), side_boundaries.end());
2713 std::vector<boundary_id_type> shellface_boundaries;
2715 unique_side_boundaries.insert(shellface_boundaries.begin(), shellface_boundaries.end());
2719 unique_side_boundaries.insert(pr.first);
2728 if (std::find(unique_node_boundaries.begin(),
2729 unique_node_boundaries.end(),
id)
2730 == unique_node_boundaries.end())
2731 unique_node_boundaries.push_back(
id);
2734 num_side_sets = cast_int<int>(unique_side_boundaries.size());
2735 num_node_sets = cast_int<int>(unique_node_boundaries.size());
2739 if (str_title.size() > MAX_LINE_LENGTH)
2741 libMesh::err <<
"Warning, Exodus files cannot have titles longer than "
2743 <<
" characters. Your title will be truncated."
2745 str_title.resize(MAX_LINE_LENGTH);
2782 exII::ex_init_params params = {};
2783 params.title[str_title.copy(params.title, MAX_LINE_LENGTH)] =
'\0';
2797 EX_CHECK_ERR(
ex_err,
"Error initializing new Exodus file.");
2820 auto push_node = [
this](
const Point & p) {
2864 if (!use_discontinuous)
2866 for (
const auto & node_ptr :
mesh.node_ptr_range())
2868 const Node & node = *node_ptr;
2896 for (
const auto & elem :
mesh.active_element_ptr_range())
2897 for (
const Node & node : elem->node_ref_range())
2915 std::vector<std::vector<const Elem *>>
2918 for (
const auto & elem :
mesh.active_element_ptr_range())
2919 elems_by_pid[elem->processor_id()].push_back(elem);
2922 for (
const Elem * elem : elems_by_pid[p])
2923 for (
auto s : elem->side_index_range())
2928 const std::vector<unsigned int> side_nodes =
2929 elem->nodes_on_side(s);
2931 for (
auto n : side_nodes)
2932 push_node(elem->point(n));
2941 ex_err = exII::ex_put_coord
2947 EX_CHECK_ERR(
ex_err,
"Error writing coordinates to Exodus file.");
2953 EX_CHECK_ERR(
ex_err,
"Error writing node_num_map");
2961 LOG_SCOPE(
"write_elements()",
"ExodusII_IO_Helper");
2966 int c0polyhedron_face_block_id = -1;
2967 auto subdomain_map = build_subdomain_map(
mesh,
2970 c0polyhedron_face_block_id);
2979 std::vector<int> elem_blk_id;
2980 std::vector<int> num_elem_this_blk_vec;
2981 std::vector<int> num_nodes_per_elem_vec;
2982 std::vector<int> num_edges_per_elem_vec;
2983 std::vector<int> num_faces_per_elem_vec;
2984 std::vector<int> num_attr_vec;
2994 bool has_c0polygon_blocks =
false;
2995 bool has_c0polyhedron_blocks =
false;
2996 int c0polyhedron_total_faces = 0;
2997 int c0polyhedron_total_face_nodes = 0;
3000 unsigned int counter = 0;
3001 for (
auto & [subdomain_id, element_id_vec] : subdomain_map)
3005 const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
3006 ElemType(subdomain_id - subdomain_id_end) :
3009 if (subdomain_id >= subdomain_id_end)
3013 num_elem_this_blk_vec.push_back
3014 (cast_int<int>(element_id_vec[0]));
3016 (Utility::enum_to_string<ElemType>(elem_t));
3021 num_elem_this_blk_vec.push_back
3022 (cast_int<int>(element_id_vec.size()));
3025 if (block_name.empty() && elem_t ==
C0POLYGON)
3026 block_name =
"NSIDED_" + std::to_string(counter + 1);
3028 block_name =
"NFACED_" + std::to_string(counter + 1);
3032 num_elem += num_elem_this_blk_vec.back();
3038 int num_edges_per_elem = 0;
3039 int num_faces_per_elem = 0;
3042 if (subdomain_id >= subdomain_id_end)
3043 libmesh_not_implemented_msg(
"Support for C0POLYGON side blocks not yet implemented");
3045 has_c0polygon_blocks =
true;
3048 for (
auto elem_id : element_id_vec)
3053 "Error: Exodus requires all elements with a given subdomain ID "
3054 "to be the same type.\n"
3055 <<
"Can't write both "
3057 <<
" and C0POLYGON in the same block!");
3064 if (subdomain_id >= subdomain_id_end)
3065 libmesh_not_implemented_msg(
"Support for C0POLYHEDRON side blocks not yet implemented");
3067 has_c0polyhedron_blocks =
true;
3070 for (
auto elem_id : element_id_vec)
3075 "Error: Exodus requires all elements with a given subdomain ID "
3076 "to be the same type.\n"
3077 <<
"Can't write both "
3079 <<
" and C0POLYHEDRON in the same block!");
3081 const int elem_n_sides = cast_int<int>(elem.
n_sides());
3082 num_faces_per_elem += elem_n_sides;
3083 c0polyhedron_total_faces += elem_n_sides;
3086 c0polyhedron_total_face_nodes += cast_int<int>(elem.
nodes_on_side(s).size());
3093 libmesh_not_implemented_msg(
"Support for Polygons/Polyhedra not yet implemented");
3096 elem_blk_id.push_back(subdomain_id);
3099 num_attr_vec.push_back(0);
3100 num_edges_per_elem_vec.push_back(num_edges_per_elem);
3101 num_faces_per_elem_vec.push_back(num_faces_per_elem);
3105 if (has_c0polyhedron_blocks)
3108 libmesh_assert_equal_to(
num_face, c0polyhedron_total_faces);
3121 std::map<std::pair<dof_id_type, unsigned int>,
dof_id_type> discontinuous_node_indices;
3123 if (use_discontinuous)
3125 for (
const auto & elem :
mesh.active_element_ptr_range())
3126 for (
auto n : elem->node_index_range())
3127 discontinuous_node_indices[std::make_pair(elem->id(),n)] =
3135 for (
const Elem * elem :
mesh.active_element_ptr_range())
3139 unsigned int local_node_index = elem->n_nodes();
3141 for (
auto s : elem->side_index_range())
3146 const std::vector<unsigned int> side_nodes =
3147 elem->nodes_on_side(s);
3152 discontinuous_node_indices
3153 [std::make_pair(elem->id(),local_node_index++)] =
3164 std::vector<BoundaryInfo::BCTuple> edge_tuples = bi.
build_edge_list();
3172 std::map<boundary_id_type, std::vector<int>> edge_id_to_conn;
3173 std::map<boundary_id_type, std::pair<ElemType, unsigned int>> edge_id_to_elem_type;
3175 std::unique_ptr<const Elem> edge;
3176 for (
const auto & t : edge_tuples)
3179 unsigned int edge_id = std::get<1>(t);
3187 if (
const auto check_it = edge_id_to_elem_type.find(b_id);
3188 check_it == edge_id_to_elem_type.end())
3191 edge_id_to_elem_type[b_id] = std::make_pair(edge->type(), edge->n_nodes());
3196 const auto & val_pair = check_it->second;
3197 libmesh_error_msg_if(val_pair.first != edge->type() || val_pair.second != edge->n_nodes(),
3198 "All edges in a block must have same geometric type.");
3202 auto & conn = edge_id_to_conn[b_id];
3208 for (
auto n : edge->node_index_range())
3212 int exodus_node_id = -1;
3214 if (!use_discontinuous)
3216 dof_id_type libmesh_node_id = edge->node_ptr(n)->id();
3217 exodus_node_id = libmesh_map_find
3226 exodus_node_id = libmesh_map_find
3227 (discontinuous_node_indices, std::make_pair(elem_id, pn));
3230 conn.push_back(exodus_node_id);
3240 std::vector<int> edge_blk_id;
3242 std::vector<int> num_edge_this_blk_vec;
3243 std::vector<int> num_nodes_per_edge_vec;
3244 std::vector<int> num_attr_edge_vec;
3250 if (has_c0polyhedron_blocks)
3254 for (
const auto & pr : edge_id_to_conn)
3258 edge_blk_id.push_back(
id);
3261 const auto & elem_type_node_count = edge_id_to_elem_type[id];
3264 num_nodes_per_edge_vec.push_back(elem_type_node_count.second);
3268 num_edge_this_blk_vec.push_back(pr.second.size() / elem_type_node_count.second);
3271 num_attr_edge_vec.push_back(0);
3277 if (has_c0polygon_blocks || has_c0polyhedron_blocks)
3282 if (has_c0polyhedron_blocks)
3285 exII::EX_FACE_BLOCK,
3286 c0polyhedron_face_block_id,
3288 c0polyhedron_total_faces,
3289 c0polyhedron_total_face_nodes,
3293 EX_CHECK_ERR(
ex_err,
"Error writing polyhedron face block.");
3299 exII::EX_ELEM_BLOCK,
3302 num_elem_this_blk_vec[i],
3303 num_nodes_per_elem_vec[i],
3304 num_edges_per_elem_vec[i],
3305 num_faces_per_elem_vec[i],
3307 EX_CHECK_ERR(
ex_err,
"Error writing element block.");
3313 exII::EX_EDGE_BLOCK,
3316 num_edge_this_blk_vec[i],
3317 num_nodes_per_edge_vec[i],
3320 num_attr_edge_vec[i]);
3321 EX_CHECK_ERR(
ex_err,
"Error writing edge block.");
3337 exII::ex_block_params params = {};
3340 params.elem_blk_id = elem_blk_id.data();
3342 params.num_elem_this_blk = num_elem_this_blk_vec.data();
3343 params.num_nodes_per_elem = num_nodes_per_elem_vec.data();
3344 params.num_edges_per_elem = num_edges_per_elem_vec.data();
3345 params.num_faces_per_elem = num_faces_per_elem_vec.data();
3346 params.num_attr_elem = num_attr_vec.data();
3347 params.define_maps = 0;
3352 params.edge_blk_id = edge_blk_id.data();
3354 params.num_edge_this_blk = num_edge_this_blk_vec.data();
3355 params.num_nodes_per_edge = num_nodes_per_edge_vec.data();
3356 params.num_attr_edge = num_attr_edge_vec.data();
3359 ex_err = exII::ex_put_concat_all_blocks(
ex_id, ¶ms);
3360 EX_CHECK_ERR(
ex_err,
"Error writing element blocks.");
3364 unsigned libmesh_elem_num_to_exodus_counter = 0;
3368 auto num_elem_this_blk_it = num_elem_this_blk_vec.begin();
3375#ifdef LIBMESH_ENABLE_UNIQUE_ID
3380 std::vector<int> face_connect;
3381 std::vector<int> c0polyhedron_face_node_counts;
3382 face_connect.reserve(c0polyhedron_total_face_nodes);
3383 c0polyhedron_face_node_counts.reserve(c0polyhedron_total_faces);
3384 int next_c0polyhedron_face_id = 1;
3386 const auto get_exodus_node_id = [&](
const Elem &elem,
3388 unsigned int elem_node_index)
3391 if (!use_discontinuous)
3393 cast_int<int>(elem.
node_id(elem_node_index)));
3395 return cast_int<int>(libmesh_map_find(discontinuous_node_indices,
3396 std::make_pair(elem_id, elem_node_index)));
3399 for (
auto & [subdomain_id, element_id_vec] : subdomain_map)
3405 const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
3406 ElemType(subdomain_id - subdomain_id_end) :
3410 const bool is_c0polygon_block = (elem_t ==
C0POLYGON);
3411 const bool is_c0polyhedron_block = (elem_t ==
C0POLYHEDRON);
3412 const bool is_variable_connectivity_block =
3413 is_c0polygon_block || is_c0polyhedron_block;
3414 std::vector<int> c0polygon_node_counts;
3415 std::vector<int> c0polyhedron_face_counts;
3417 if (is_variable_connectivity_block && subdomain_id >= subdomain_id_end)
3418 libmesh_not_implemented_msg(
"Support for " <<
3420 " side blocks not yet implemented");
3422 if (!is_variable_connectivity_block)
3426 libmesh_not_implemented_msg(
"Support for Polygons/Polyhedra not yet implemented");
3431 if (subdomain_id < subdomain_id_end)
3433 if (is_variable_connectivity_block)
3435 if (is_c0polygon_block)
3436 c0polygon_node_counts.reserve(element_id_vec.size());
3437 else if (is_c0polyhedron_block)
3438 c0polyhedron_face_counts.reserve(element_id_vec.size());
3442 const auto add_c0polygon_connectivity =
3445 c0polygon_node_counts.push_back(cast_int<int>(elem.
n_nodes()));
3447 connect.push_back(get_exodus_node_id(elem, elem_id, elem_node_index));
3451 const auto add_c0polyhedron_connectivity =
3454 c0polyhedron_face_counts.push_back(cast_int<int>(elem.
n_sides()));
3458 connect.push_back(next_c0polyhedron_face_id++);
3460 const std::vector<unsigned int> side_nodes = elem.
nodes_on_side(s);
3461 c0polyhedron_face_node_counts.push_back(cast_int<int>(side_nodes.size()));
3463 for (
const auto elem_node_index : side_nodes)
3464 face_connect.push_back(
3465 get_exodus_node_id(elem, elem_id, elem_node_index));
3469 const auto add_fixed_connectivity =
3472 for (
unsigned int j = 0;
3476 const auto connect_index =
3478 const auto elem_node_index = conv.get_inverse_node_map(j);
3480 get_exodus_node_id(elem, elem_id, elem_node_index);
3486 unsigned int elem_id = element_id_vec[i];
3501 libmesh_error_msg_if(elem.
type() != conv.libmesh_elem_type(),
3502 "Error: Exodus requires all elements with a given subdomain ID to be the same type.\n"
3503 <<
"Can't write both "
3507 <<
" in the same block!");
3509 if (is_c0polygon_block)
3510 add_c0polygon_connectivity(elem, elem_id);
3511 else if (is_c0polyhedron_block)
3512 add_c0polyhedron_connectivity(elem, elem_id);
3514 add_fixed_connectivity(elem, elem_id, i);
3532 libmesh_assert(num_elem_this_blk_it != num_elem_this_blk_vec.end());
3537 std::size_t connect_index = 0;
3538 for (
const auto & elem :
mesh.active_element_ptr_range())
3540 unsigned int local_node_index = elem->
n_nodes();
3550 const std::vector<unsigned int> side_nodes =
3556 const int exodus_node_id = libmesh_map_find
3557 (discontinuous_node_indices,
3558 std::make_pair(elem->
id(), local_node_index++));
3559 libmesh_assert_less(connect_index,
connect.size());
3560 connect[connect_index++] = exodus_node_id;
3572 ++num_elem_this_blk_it;
3574 ex_err = exII::ex_put_conn
3576 exII::EX_ELEM_BLOCK,
3578 is_c0polyhedron_block ?
nullptr :
connect.data(),
3580 is_c0polyhedron_block ?
connect.data() :
nullptr);
3581 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
3583 if (is_c0polygon_block)
3585 ex_err = exII::ex_put_entity_count_per_polyhedra
3587 exII::EX_ELEM_BLOCK,
3589 c0polygon_node_counts.data());
3590 EX_CHECK_ERR(
ex_err,
"Error writing polygon node counts");
3592 if (is_c0polyhedron_block)
3594 ex_err = exII::ex_put_entity_count_per_polyhedra
3596 exII::EX_ELEM_BLOCK,
3598 c0polyhedron_face_counts.data());
3599 EX_CHECK_ERR(
ex_err,
"Error writing polyhedron face counts");
3603 if (has_c0polyhedron_blocks)
3605 libmesh_assert_equal_to(c0polyhedron_face_node_counts.size(),
3607 libmesh_assert_equal_to(next_c0polyhedron_face_id,
num_face + 1);
3609 ex_err = exII::ex_put_conn
3611 exII::EX_FACE_BLOCK,
3612 c0polyhedron_face_block_id,
3613 face_connect.data(),
3616 EX_CHECK_ERR(
ex_err,
"Error writing polyhedron face connectivities");
3618 ex_err = exII::ex_put_entity_count_per_polyhedra
3620 exII::EX_FACE_BLOCK,
3621 c0polyhedron_face_block_id,
3622 c0polyhedron_face_node_counts.data());
3623 EX_CHECK_ERR(
ex_err,
"Error writing polyhedron face node counts");
3628 EX_CHECK_ERR(
ex_err,
"Error writing element map");
3634 EX_CHECK_ERR(
ex_err,
"Error writing element block names");
3639 ex_err = exII::ex_put_names
3641 exII::EX_FACE_BLOCK,
3643 EX_CHECK_ERR(
ex_err,
"Error writing face block names");
3647 for (
const auto & pr : edge_id_to_conn)
3649 ex_err = exII::ex_put_conn
3651 exII::EX_EDGE_BLOCK,
3656 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
3662 ex_err = exII::ex_put_names
3664 exII::EX_EDGE_BLOCK,
3666 EX_CHECK_ERR(
ex_err,
"Error writing edge block names");
3675 LOG_SCOPE(
"write_sidesets()",
"ExodusII_IO_Helper");
3681 std::map<int, std::vector<int>> elem_lists;
3682 std::map<int, std::vector<int>> side_lists;
3683 std::set<boundary_id_type> side_boundary_ids;
3690 std::vector<const Elem *> family;
3691#ifdef LIBMESH_ENABLE_AMR
3696 mesh.
elem_ref(std::get<0>(t)).active_family_tree_by_side(family, std::get<1>(t),
false);
3701 for (
const auto & f : family)
3708 side_lists[std::get<2>(t)].push_back(conv.get_inverse_side_map(std::get<1>(t)));
3712 std::vector<boundary_id_type> tmp;
3714 side_boundary_ids.insert(tmp.begin(), tmp.end());
3723 std::vector<const Elem *> family;
3724#ifdef LIBMESH_ENABLE_AMR
3729 mesh.
elem_ref(std::get<0>(t)).active_family_tree_by_side(family, std::get<1>(t),
false);
3734 for (
const auto & f : family)
3741 side_lists[std::get<2>(t)].push_back(conv.get_inverse_shellface_map(std::get<1>(t)));
3745 std::vector<boundary_id_type> tmp;
3747 side_boundary_ids.insert(tmp.begin(), tmp.end());
3752 side_boundary_ids.insert(pr.first);
3755 if (side_boundary_ids.size() > 0)
3759 std::vector<exII::ex_set> sets(side_boundary_ids.size());
3762 for (
auto [i, it] = std::tuple{0u, side_boundary_ids.begin()}; i<sets.size(); ++i, ++it)
3768 sets[i].type = exII::EX_SIDE_SET;
3769 sets[i].num_distribution_factor = 0;
3770 sets[i].distribution_factor_list =
nullptr;
3772 if (
const auto elem_it = elem_lists.find(ss_id);
3773 elem_it == elem_lists.end())
3775 sets[i].num_entry = 0;
3776 sets[i].entry_list =
nullptr;
3777 sets[i].extra_list =
nullptr;
3781 sets[i].num_entry = elem_it->second.size();
3782 sets[i].entry_list = elem_it->second.data();
3783 sets[i].extra_list = libmesh_map_find(side_lists, ss_id).data();
3787 ex_err = exII::ex_put_sets(
ex_id, side_boundary_ids.size(), sets.data());
3788 EX_CHECK_ERR(
ex_err,
"Error writing sidesets");
3791 EX_CHECK_ERR(
ex_err,
"Error writing sideset names");
3799 LOG_SCOPE(
"write_nodesets()",
"ExodusII_IO_Helper");
3816 std::stable_sort(bc_tuples.begin(), bc_tuples.end(),
3819 { return std::get<1>(t1) < std::get<1>(t2); });
3821 std::vector<boundary_id_type> node_boundary_ids;
3829 if (std::find(node_boundary_ids.begin(),
3830 node_boundary_ids.end(),
id)
3831 == node_boundary_ids.end())
3832 node_boundary_ids.push_back(
id);
3836 if (node_boundary_ids.size() > 0)
3856 std::map<boundary_id_type, unsigned int> nodeset_counts;
3857 for (
auto id : node_boundary_ids)
3858 nodeset_counts[
id] = 0;
3860 for (
const auto & t : bc_tuples)
3865 nodeset_counts[nodeset_id] += 1;
3869 unsigned int running_sum = 0;
3870 for (
const auto & pr : nodeset_counts)
3876 running_sum += pr.second;
3881 exII::ex_set_specs set_data = {};
3890 ex_err = exII::ex_put_concat_sets(
ex_id, exII::EX_NODE_SET, &set_data);
3891 EX_CHECK_ERR(
ex_err,
"Error writing concatenated nodesets");
3895 EX_CHECK_ERR(
ex_err,
"Error writing nodeset names");
3902 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
3908 if (names.size() == 0)
3931 for (
auto var_num :
index_range(vars_active_subdomains))
3935 std::set<subdomain_id_type> current_set;
3936 if (vars_active_subdomains[var_num].empty())
3938 current_set.insert(restrict_int<subdomain_id_type>(block_id));
3940 current_set = vars_active_subdomains[var_num];
3943 for (
auto block_id : current_set)
3946 libmesh_error_msg_if(it ==
block_ids.end(),
3947 "ExodusII_IO_Helper: block id " << block_id <<
" not found in block_ids.");
3949 std::size_t block_index =
3952 std::size_t truth_tab_index = block_index*
num_elem_vars + var_num;
3953 truth_tab[truth_tab_index] = 1;
3957 ex_err = exII::ex_put_truth_table
3959 exII::EX_ELEM_BLOCK,
3963 EX_CHECK_ERR(
ex_err,
"Error writing element truth table.");
3974 if (names.size() == 0)
4002 if (names.size() == 0)
4023 std::vector<std::string> & names,
4024 std::vector<std::string> & names_from_file)
4038 std::equal(names.begin(), names.end(),
4039 names_from_file.begin(),
4040 [
this](
const std::string & a,
4041 const std::string &
b) ->
bool
4043 return a.compare(0, _max_name_length, b) == 0;
4048 libMesh::err <<
"Error! The Exodus file already contains the variables:" << std::endl;
4049 for (
const auto & name : names_from_file)
4052 libMesh::err <<
"And you asked to write:" << std::endl;
4053 for (
const auto & name : names)
4056 libmesh_error_msg(
"Cannot overwrite existing variables in Exodus II file.");
4069 float cast_time = float(time);
4070 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
4074 double cast_time = double(time);
4075 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
4077 EX_CHECK_ERR(
ex_err,
"Error writing timestep.");
4087 LOG_SCOPE(
"write_elemsets()",
"ExodusII_IO_Helper");
4099 std::map<elemset_id_type, std::vector<int>> exodus_elemsets;
4101 unsigned int elemset_index =
4106 for (
const auto & elem :
mesh.element_ptr_range())
4109 elem->get_extra_integer(elemset_index);
4121 for (
const auto & set_id : set_ids)
4135 if (!exodus_elemsets.empty())
4141 std::vector<exII::ex_set> sets;
4142 sets.reserve(exodus_elemsets.size());
4144 for (
auto & [elem_set_id, ids_vec] : exodus_elemsets)
4149 exII::ex_set & current_set = sets.emplace_back();
4150 current_set.id = elem_set_id;
4151 current_set.type = exII::EX_ELEM_SET;
4152 current_set.num_entry = ids_vec.size();
4153 current_set.num_distribution_factor = 0;
4154 current_set.entry_list = ids_vec.data();
4155 current_set.extra_list =
nullptr;
4156 current_set.distribution_factor_list =
nullptr;
4161 libmesh_assert_msg(
num_elem_sets == cast_int<int>(exodus_elemsets.size()),
4162 "Mesh has " << exodus_elemsets.size()
4163 <<
" elemsets, but header was written with num_elem_sets == " <<
num_elem_sets);
4166 <<
", but header was written with num_elem_sets == " <<
num_elem_sets);
4168 ex_err = exII::ex_put_sets(
ex_id, exodus_elemsets.size(), sets.data());
4169 EX_CHECK_ERR(
ex_err,
"Error writing elemsets");
4184 const std::vector<std::string> & var_names,
4185 const std::vector<std::set<boundary_id_type>> & side_ids,
4186 const std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
4188 LOG_SCOPE(
"write_sideset_data()",
"ExodusII_IO_Helper");
4214 std::vector<int> sset_var_tab(
num_side_sets * var_names.size());
4233 if (!side_ids[var].count(
ss_ids[ss]))
4237 sset_var_tab[ss*var_names.size() + var] = 1;
4243 const auto & data_map = bc_vals[var];
4266 libmesh_error_msg_if
4268 cast_int<dof_id_type>(
elem_list[i + offset]),
4269 "Error mapping Exodus elem id to libmesh elem id.");
4275 unsigned int converted_side_id = conv.get_side_map(
side_id);
4287 sset_var_vals[i] = libmesh_map_find(data_map, key);
4293 if (sset_var_vals.size() > 0)
4295 ex_err = exII::ex_put_var
4303 EX_CHECK_ERR(
ex_err,
"Error writing sideset vars.");
4310 exII::ex_put_truth_table(
ex_id,
4313 cast_int<int>(var_names.size()),
4314 sset_var_tab.data());
4315 EX_CHECK_ERR(
ex_err,
"Error writing sideset var truth table.");
4324 std::vector<std::string> & var_names,
4325 std::vector<std::set<boundary_id_type>> & side_ids,
4326 std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
4328 LOG_SCOPE(
"read_sideset_data()",
"ExodusII_IO_Helper");
4338 ex_err = exII::ex_get_truth_table
4343 sset_var_tab.data());
4344 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable truth table.");
4373 side_ids[var].insert(
ss_ids[ss]);
4379 ex_err = exII::ex_get_var
4387 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable.");
4392 unsigned int exodus_side_id =
side_list[i + offset];
4397 dof_id_type converted_elem_id = exodus_elem_id - 1;
4406 unsigned int converted_side_id = conv.get_side_map(exodus_side_id - 1);
4415 bc_vals[var].emplace(key, sset_var_vals[i]);
4427 std::map<BoundaryInfo::BCTuple, unsigned int> & bc_array_indices)
4430 bc_array_indices.clear();
4444 unsigned int exodus_side_id =
side_list[i + offset];
4449 dof_id_type converted_elem_id = exodus_elem_id - 1;
4457 unsigned int converted_side_id = conv.get_side_map(exodus_side_id - 1);
4466 bc_array_indices.emplace(key, cast_int<unsigned int>(i));
4475 const std::vector<std::string> & var_names,
4476 const std::vector<std::set<boundary_id_type>> & node_boundary_ids,
4477 const std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals)
4479 LOG_SCOPE(
"write_nodeset_data()",
"ExodusII_IO_Helper");
4503 std::vector<int> nset_var_tab(
num_node_sets * var_names.size());
4515 if (!node_boundary_ids[var].count(
nodeset_ids[ns]))
4519 nset_var_tab[ns*var_names.size() + var] = 1;
4525 const auto & data_map = bc_vals[var];
4539 std::make_tuple(libmesh_node_id,
nodeset_ids[ns]);
4546 nset_var_vals[i] = libmesh_map_find(data_map, key);
4550 if (nset_var_vals.size() > 0)
4552 ex_err = exII::ex_put_var
4560 EX_CHECK_ERR(
ex_err,
"Error writing nodeset vars.");
4567 exII::ex_put_truth_table(
ex_id,
4570 cast_int<int>(var_names.size()),
4571 nset_var_tab.data());
4572 EX_CHECK_ERR(
ex_err,
"Error writing nodeset var truth table.");
4580 const std::vector<std::string> & var_names,
4581 const std::vector<std::set<elemset_id_type>> & elemset_ids_in,
4582 const std::vector<std::map<std::pair<dof_id_type, elemset_id_type>,
Real>> & elemset_vals)
4584 LOG_SCOPE(
"write_elemset_data()",
"ExodusII_IO_Helper");
4613 std::vector<int> elemset_var_tab(
num_elem_sets * var_names.size());
4639 elemset_var_tab[es*var_names.size() + var] = 1;
4645 const auto & data_map = elemset_vals[var];
4658 std::pair<dof_id_type, elemset_id_type> key =
4669 elemset_var_vals[i] = libmesh_map_find(data_map, key);
4673 if (elemset_var_vals.size() > 0)
4675 ex_err = exII::ex_put_var
4683 EX_CHECK_ERR(
ex_err,
"Error writing elemset vars.");
4690 exII::ex_put_truth_table(
ex_id,
4693 cast_int<int>(var_names.size()),
4694 elemset_var_tab.data());
4695 EX_CHECK_ERR(
ex_err,
"Error writing elemset var truth table.");
4703 std::vector<std::string> & var_names,
4704 std::vector<std::set<elemset_id_type>> & elemset_ids_in,
4705 std::vector<std::map<std::pair<dof_id_type, elemset_id_type>,
Real>> & elemset_vals)
4707 LOG_SCOPE(
"read_elemset_data()",
"ExodusII_IO_Helper");
4728 exII::ex_get_truth_table(
ex_id,
4732 elemset_var_tab.data());
4733 EX_CHECK_ERR(
ex_err,
"Error reading elemset variable truth table.");
4776 ex_err = exII::ex_get_var
4784 EX_CHECK_ERR(
ex_err,
"Error reading elemset variable.");
4793 dof_id_type converted_elem_id = exodus_elem_id - 1;
4796 auto key = std::make_pair(converted_elem_id,
4800 elemset_vals[var].emplace(key, elemset_var_vals[i]);
4814 elemset_array_indices.clear();
4838 dof_id_type converted_elem_id = exodus_elem_id - 1;
4842 auto key = std::make_pair(converted_elem_id,
4846 elemset_array_indices.emplace(key, cast_int<unsigned int>(i));
4855 std::vector<std::string> & var_names,
4856 std::vector<std::set<boundary_id_type>> & node_boundary_ids,
4857 std::vector<std::map<BoundaryInfo::NodeBCTuple, Real>> & bc_vals)
4859 LOG_SCOPE(
"read_nodeset_data()",
"ExodusII_IO_Helper");
4869 ex_err = exII::ex_get_truth_table
4874 nset_var_tab.data());
4875 EX_CHECK_ERR(
ex_err,
"Error reading nodeset variable truth table.");
4911 ex_err = exII::ex_get_var
4919 EX_CHECK_ERR(
ex_err,
"Error reading nodeset variable.");
4934 dof_id_type converted_node_id = exodus_node_id - 1;
4941 bc_vals[var].emplace(key, nset_var_vals[i]);
4956 bc_array_indices.clear();
4985 dof_id_type converted_node_id = exodus_node_id - 1;
4992 bc_array_indices.emplace(key, cast_int<unsigned int>(i));
4999 const std::vector<Real> & values,
5001 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
5003 LOG_SCOPE(
"write_element_values()",
"ExodusII_IO_Helper");
5010 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
5015 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
5016 for (
const auto & elem :
mesh.active_element_ptr_range())
5017 subdomain_map[elem->subdomain_id()].push_back(elem->id());
5026 libmesh_assert_equal_to
5027 (vars_active_subdomains.size(),
5033 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
5036 auto it = subdomain_map.begin();
5039 const auto & active_subdomains
5040 = vars_active_subdomains[var_id];
5042 for (
unsigned int j=0; it!=subdomain_map.end(); ++it, ++j)
5047 if (!(active_subdomains.empty() || active_subdomains.count(it->first)))
5053 const auto & elem_nums = it->second;
5054 const unsigned int num_elems_this_block =
5055 cast_int<unsigned int>(elem_nums.size());
5056 std::vector<Real> data(num_elems_this_block);
5061 for (
unsigned int k=0; k<num_elems_this_block; ++k)
5062 data[k] = values[var_id*n_elem + elem_nums[k]];
5064 ex_err = exII::ex_put_var
5067 exII::EX_ELEM_BLOCK,
5070 num_elems_this_block,
5073 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
5084 const std::vector<Real> & values,
5086 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
5087 const std::vector<std::string> & derived_var_names,
5088 const std::map<
subdomain_id_type, std::vector<std::string>> & subdomain_to_var_names)
5095 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
5102 std::map<subdomain_id_type, unsigned int> subdomain_to_n_elem;
5103 for (
const auto & elem :
mesh.active_element_ptr_range())
5104 subdomain_to_n_elem[elem->subdomain_id()] += 1;
5108 libmesh_assert_equal_to
5109 (vars_active_subdomains.size(),
5113 auto subdomain_to_n_elem_iter = subdomain_to_n_elem.begin();
5119 (
mesh.active_elements_begin(),
5120 mesh.active_elements_end());
5122 for (
unsigned int sbd_idx=0;
5123 subdomain_to_n_elem_iter != subdomain_to_n_elem.end();
5124 ++subdomain_to_n_elem_iter, ++sbd_idx)
5125 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
5128 const auto & active_subdomains
5129 = vars_active_subdomains[var_id];
5136 if (!active_subdomains.count(subdomain_to_n_elem_iter->first))
5140 std::vector<Real> data;
5141 data.reserve(subdomain_to_n_elem_iter->second);
5143 unsigned int values_offset = 0;
5144 for (
auto & elem : elem_range)
5151 auto subdomain_to_var_names_iter =
5152 subdomain_to_var_names.find(sbd_id);
5160 if (subdomain_to_var_names_iter == subdomain_to_var_names.end())
5163 const auto & var_names_this_sbd
5164 = subdomain_to_var_names_iter->second;
5167 if (sbd_id == subdomain_to_n_elem_iter->first)
5175 std::find(var_names_this_sbd.begin(),
5176 var_names_this_sbd.end(),
5177 derived_var_names[var_id]);
5179 libmesh_error_msg_if(pos == var_names_this_sbd.end(),
5180 "Derived name " << derived_var_names[var_id] <<
" not found!");
5185 std::distance(var_names_this_sbd.begin(), pos);
5187 data.push_back(values[values_offset + true_index]);
5192 auto true_offset = var_names_this_sbd.size();
5195 values_offset += true_offset;
5201 ex_err = exII::ex_put_var
5204 exII::EX_ELEM_BLOCK,
5210 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
5221 const std::vector<Real> & values,
5227 if (!values.empty())
5229 libmesh_assert_equal_to(values.size(), std::size_t(
num_nodes));
5231 ex_err = exII::ex_put_var
5240 EX_CHECK_ERR(
ex_err,
"Error writing nodal values.");
5257 int num_info = inquire(*
this, exII::EX_INQ_INFO,
"Error retrieving the number of information records from file!");
5260 libMesh::err <<
"Warning! The Exodus file already contains information records.\n"
5261 <<
"Exodus does not support writing additional records in this situation."
5266 int num_records = cast_int<int>(records.size());
5268 if (num_records > 0)
5270 NamesData info(num_records, MAX_LINE_LENGTH);
5274 for (
const auto & record : records)
5275 info.push_back_entry(record);
5277 ex_err = exII::ex_put_info(
ex_id, num_records, info.get_char_star_star());
5278 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
5291 if (!values.empty())
5293 ex_err = exII::ex_put_var
5302 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
5313 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
5325 ex_err = exII::ex_get_var
5334 EX_CHECK_ERR(
ex_err,
"Error reading global values.");
5354 libmesh_error_msg_if (max_length > libmesh_max_str_length,
5355 "Exodus maximum name length is limited to " <<
5356 libmesh_max_str_length <<
" characters");
5378std::vector<std::string>
5380 bool write_complex_abs)
const
5382 std::vector<std::string> complex_names;
5386 for (
const auto & name : names)
5388 complex_names.push_back(
"r_" + name);
5389 complex_names.push_back(
"i_" + name);
5390 if (write_complex_abs)
5391 complex_names.push_back(
"a_" + name);
5394 return complex_names;
5399std::vector<std::set<subdomain_id_type>>
5402(
const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
5403 bool write_complex_abs)
const
5405 std::vector<std::set<subdomain_id_type>> complex_vars_active_subdomains;
5407 for (
auto & s : vars_active_subdomains)
5411 complex_vars_active_subdomains.push_back(s);
5412 complex_vars_active_subdomains.push_back(s);
5413 if (write_complex_abs)
5414 complex_vars_active_subdomains.push_back(s);
5417 return complex_vars_active_subdomains;
5422std::map<subdomain_id_type, std::vector<std::string>>
5425(
const std::map<
subdomain_id_type, std::vector<std::string>> & subdomain_to_var_names,
5426 bool write_complex_abs)
const
5429 std::map<subdomain_id_type, std::vector<std::string>> ret;
5431 unsigned int num_complex_outputs = write_complex_abs ? 3 : 2;
5433 for (
const auto & pr : subdomain_to_var_names)
5436 auto & vec = ret[pr.first];
5439 const auto & varnames = pr.second;
5442 vec.reserve(num_complex_outputs * varnames.size());
5447 for (
const auto & varname : varnames)
5449 vec.push_back(
"r_" + varname);
5450 vec.push_back(
"i_" + varname);
5451 if (write_complex_abs)
5452 vec.push_back(
"a_" + varname);
5465 libmesh_assert_less (i, node_map->size());
5466 return (*node_map)[i];
5473 if (!inverse_node_map)
5476 libmesh_assert_less (i, inverse_node_map->size());
5477 return (*inverse_node_map)[i];
5489 if (
static_cast<size_t>(i) >= side_map->size())
5492 return (*side_map)[i];
5500 if (!inverse_side_map)
5503 libmesh_assert_less (i, inverse_side_map->size());
5504 return (*inverse_side_map)[i];
5518 libmesh_assert_less (i, shellface_map->size());
5519 return (*shellface_map)[i];
5526 if (!inverse_shellface_map)
5529 libmesh_assert_less (i, inverse_shellface_map->size());
5530 return (*inverse_shellface_map)[i];
5537 return libmesh_type;
5554 return shellface_index_offset;
5558 data_table(n_strings),
5559 data_table_pointers(n_strings),
5561 table_size(n_strings)
5563 for (
size_t i=0; i<n_strings; ++i)
5579 libmesh_assert_less (counter, table_size);
5582 size_t num_copied = name.copy(data_table[counter].data(), data_table[counter].size()-1);
5585 data_table[counter][num_copied] =
'\0';
5595 return data_table_pointers.data();
5602 libmesh_error_msg_if(
static_cast<unsigned>(i) >= table_size,
5603 "Requested char * " << i <<
" but only have " << table_size <<
"!");
5605 return data_table[i].data();
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...
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.
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...
virtual unsigned int n_nodes() const =0
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 ...
virtual std::unique_ptr< Elem > build_edge_ptr(const unsigned int i)=0
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
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
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,...
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
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.
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...
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,...