19 #include "libmesh/exodusII_io_helper.h"
22 #ifdef LIBMESH_HAVE_EXODUS_API
27 #include <unordered_map>
29 #include "libmesh/boundary_info.h"
30 #include "libmesh/enum_elem_type.h"
31 #include "libmesh/elem.h"
32 #include "libmesh/system.h"
33 #include "libmesh/numeric_vector.h"
34 #include "libmesh/enum_to_string.h"
35 #include "libmesh/enum_elem_type.h"
36 #include "libmesh/int_range.h"
37 #include "libmesh/utility.h"
40 #include "libmesh/mesh_tools.h"
50 const std::vector<int> trishell3_inverse_edge_map = {3, 4, 5};
51 const std::vector<int> quadshell4_inverse_edge_map = {3, 4, 5, 6};
56 const std::vector<int> hex27_node_map = {
58 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
60 21, 25, 24, 26, 23, 22, 20};
63 const std::vector<int> hex27_inverse_node_map = {
65 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
67 26, 20, 25, 24, 22, 21, 23};
71 const std::vector<int> tet_face_map = {1, 2, 3, 0};
72 const std::vector<int> hex_face_map = {1, 2, 3, 4, 0, 5};
73 const std::vector<int> prism_face_map = {1, 2, 3, 0, 4};
76 const std::vector<int> tet_inverse_face_map = {4, 1, 2, 3};
77 const std::vector<int> hex_inverse_face_map = {5, 1, 2, 3, 4, 6};
78 const std::vector<int> prism_inverse_face_map = {4, 1, 2, 3, 5};
81 const std::vector<int> hex_edge_map =
82 {0,1,2,3,8,9,10,11,4,5,7,6};
85 const std::vector<int> hex_inverse_edge_map =
86 {1,2,3,4,9,10,12,11,5,6,7,8};
100 bool run_only_on_proc0,
101 bool single_precision) :
115 num_elem_this_blk(0),
116 num_nodes_per_elem(0),
118 num_elem_all_sidesets(0),
123 opened_for_writing(false),
124 opened_for_reading(false),
125 _run_only_on_proc0(run_only_on_proc0),
126 _elem_vars_initialized(false),
127 _global_vars_initialized(false),
128 _nodal_vars_initialized(false),
129 _use_mesh_dimension_instead_of_spatial_dimension(false),
130 _write_as_dimension(0),
131 _single_precision(single_precision)
133 title.resize(MAX_LINE_LENGTH+1);
151 conv.exodus_type =
"SPHERE";
155 conv.libmesh_type =
EDGE2;
156 conv.exodus_type =
"EDGE2";
160 conv.libmesh_type =
EDGE3;
161 conv.exodus_type =
"EDGE3";
165 conv.libmesh_type =
QUAD4;
166 conv.exodus_type =
"QUAD4";
170 conv.inverse_side_map = &quadshell4_inverse_edge_map;
171 conv.shellface_index_offset = 2;
173 conv.exodus_type =
"SHELL4";
177 conv.libmesh_type =
QUAD8;
178 conv.exodus_type =
"QUAD8";
182 conv.inverse_side_map = &quadshell4_inverse_edge_map;
183 conv.shellface_index_offset = 2;
185 conv.exodus_type =
"SHELL8";
189 conv.libmesh_type =
QUAD9;
190 conv.exodus_type =
"QUAD9";
194 conv.libmesh_type =
TRI3;
195 conv.exodus_type =
"TRI3";
199 conv.inverse_side_map = &trishell3_inverse_edge_map;
200 conv.shellface_index_offset = 2;
202 conv.exodus_type =
"TRISHELL3";
207 conv.exodus_type =
"TRI3";
211 conv.libmesh_type =
TRI6;
212 conv.exodus_type =
"TRI6";
216 conv.side_map = &hex_face_map;
217 conv.inverse_side_map = &hex_inverse_face_map;
218 conv.libmesh_type =
HEX8;
219 conv.exodus_type =
"HEX8";
223 conv.side_map = &hex_face_map;
224 conv.inverse_side_map = &hex_inverse_face_map;
225 conv.libmesh_type =
HEX20;
226 conv.exodus_type =
"HEX20";
230 conv.node_map = &hex27_node_map;
231 conv.inverse_node_map = &hex27_inverse_node_map;
232 conv.side_map = &hex_face_map;
233 conv.inverse_side_map = &hex_inverse_face_map;
234 conv.libmesh_type =
HEX27;
235 conv.exodus_type =
"HEX27";
239 conv.side_map = &tet_face_map;
240 conv.inverse_side_map = &tet_inverse_face_map;
241 conv.libmesh_type =
TET4;
242 conv.exodus_type =
"TETRA4";
246 conv.side_map = &tet_face_map;
247 conv.inverse_side_map = &tet_inverse_face_map;
248 conv.libmesh_type =
TET10;
249 conv.exodus_type =
"TETRA10";
253 conv.side_map = &prism_face_map;
254 conv.inverse_side_map = &prism_inverse_face_map;
255 conv.libmesh_type =
PRISM6;
256 conv.exodus_type =
"WEDGE";
260 conv.side_map = &prism_face_map;
261 conv.inverse_side_map = &prism_inverse_face_map;
263 conv.exodus_type =
"WEDGE15";
267 conv.side_map = &prism_face_map;
268 conv.inverse_side_map = &prism_inverse_face_map;
270 conv.exodus_type =
"WEDGE18";
275 conv.exodus_type =
"PYRAMID5";
280 conv.exodus_type =
"PYRAMID13";
285 conv.exodus_type =
"PYRAMID14";
392 std::transform(type_str.begin(), type_str.end(), type_str.begin(), ::toupper);
418 bool single_precision_in)
419 : our_data(our_data_in),
420 single_precision(single_precision_in)
424 if (
sizeof(
Real) !=
sizeof(
float))
428 else if (
sizeof(
Real) !=
sizeof(double))
435 if (single_precision)
437 if (
sizeof(
Real) !=
sizeof(
float))
438 return static_cast<void*>(float_vec.data());
441 else if (
sizeof(
Real) !=
sizeof(double))
442 return static_cast<void*>(double_vec.data());
445 return const_cast<void *>(static_cast<const void *>(our_data.data()));
450 bool single_precision_in)
451 : our_data(our_data_in),
452 single_precision(single_precision_in)
457 if (
sizeof(
Real) !=
sizeof(
float))
460 else if (
sizeof(
Real) !=
sizeof(double))
467 if (single_precision)
469 if (
sizeof(
Real) !=
sizeof(
float))
470 our_data.assign(float_vec.begin(), float_vec.end());
472 else if (
sizeof(
Real) !=
sizeof(double))
473 our_data.assign(double_vec.begin(), double_vec.end());
479 if (single_precision)
481 if (
sizeof(
Real) !=
sizeof(
float))
482 return static_cast<void*>(float_vec.data());
485 else if (
sizeof(
Real) !=
sizeof(double))
486 return static_cast<void*>(double_vec.data());
489 return static_cast<void *>(our_data.data());
495 float ex_version = 0.;
500 comp_ws = cast_int<int>(
sizeof(
float));
505 comp_ws = cast_int<int>(std::min(
sizeof(
Real),
sizeof(
double)));
512 ex_id = exII::ex_open(filename,
513 read_only ? EX_READ : EX_WRITE,
518 std::string err_msg = std::string(
"Error opening ExodusII mesh file: ") + std::string(filename);
519 EX_CHECK_ERR(
ex_id, err_msg);
539 exII::ex_init_params params = {};
541 EX_CHECK_ERR(
ex_err,
"Error retrieving header info.");
545 title.assign(params.title, params.title + MAX_LINE_LENGTH);
558 EX_CHECK_ERR(
ex_err,
"Error reading number of nodal variables.");
561 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
564 EX_CHECK_ERR(
ex_err,
"Error reading number of global variables.");
567 EX_CHECK_ERR(
ex_err,
"Error reading number of sideset variables.");
569 message(
"Exodus header info retrieved successfully.");
579 this->
inquire(exII::EX_INQ_QA,
"Error retrieving number of QA records");
584 <<
" QA record(s) in the Exodus file."
591 typedef char * inner_array_t[4];
592 inner_array_t * qa_record =
new inner_array_t[num_qa_rec];
594 for (
int i=0; i<num_qa_rec; i++)
595 for (
int j=0; j<4; j++)
596 qa_record[i][j] =
new char[MAX_STR_LENGTH+1];
599 EX_CHECK_ERR(
ex_err,
"Error reading the QA records.");
604 for (
int i=0; i<num_qa_rec; i++)
607 for (
int j=0; j<4; j++)
614 for (
int i=0; i<num_qa_rec; i++)
615 for (
int j=0; j<4; j++)
616 delete [] qa_record[i][j];
629 <<
"Mesh Dimension: \t" <<
num_dim << std::endl
630 <<
"Number of Nodes: \t" <<
num_nodes << std::endl
631 <<
"Number of elements: \t" <<
num_elem << std::endl
632 <<
"Number of elt blocks: \t" <<
num_elem_blk << std::endl
647 ex_err = exII::ex_get_coord
653 EX_CHECK_ERR(
ex_err,
"Error retrieving nodal data.");
654 message(
"Nodal data retrieved successfully.");
668 ex_err = exII::ex_get_node_num_map
671 EX_CHECK_ERR(
ex_err,
"Error retrieving nodal number map.");
672 message(
"Nodal numbering map retrieved successfully.");
677 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_nodes-1)); ++i)
687 out_stream <<
"(" <<
x[i] <<
", " <<
y[i] <<
", " <<
z[i] <<
")" << std::endl;
702 EX_CHECK_ERR(
ex_err,
"Error getting block IDs.");
703 message(
"All block IDs retrieved successfully.");
705 char name_buffer[MAX_STR_LENGTH+1];
708 ex_err = exII::ex_get_name(
ex_id, exII::EX_ELEM_BLOCK,
710 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
713 message(
"All block names retrieved successfully.");
724 EX_CHECK_ERR(
ex_err,
"Error getting edge block IDs.");
725 message(
"All edge block IDs retrieved successfully.");
728 char name_buffer[MAX_STR_LENGTH+1];
731 ex_err = exII::ex_get_name(
ex_id, exII::EX_EDGE_BLOCK,
733 EX_CHECK_ERR(
ex_err,
"Error getting block name.");
736 message(
"All edge block names retrieved successfully.");
744 libmesh_assert_less (index,
block_ids.size());
753 libmesh_assert_less (index,
block_ids.size());
762 libmesh_assert_less (index,
ss_ids.size());
771 libmesh_assert_less (index,
ss_ids.size());
799 libmesh_assert_less (block,
block_ids.size());
802 int num_edges_per_elem = 0;
803 int num_faces_per_elem = 0;
814 EX_CHECK_ERR(
ex_err,
"Error getting block info.");
815 message(
"Info retrieved successfully for block: ", block);
820 if (!(num_edges_per_elem == 0) && !(num_edges_per_elem == -1))
821 libmesh_warning(
"Exodus files with extended edge connectivity not currently supported.");
822 if (!(num_faces_per_elem == 0) && !(num_faces_per_elem == -1))
823 libmesh_warning(
"Exodus files with extended face connectivity not currently supported.");
829 <<
" nodes per element." << std::endl;
845 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
846 message(
"Connectivity retrieved successfully for block: ", block);
864 typedef std::pair<dof_id_type, unsigned int> ElemEdgePair;
865 std::unordered_map<dof_id_type, std::vector<ElemEdgePair>> edge_map;
866 for (
const auto & elem :
mesh.element_ptr_range())
867 for (
auto e : elem->edge_index_range())
873 std::unique_ptr<Elem> edge = elem->build_edge_ptr(e);
877 auto & vec = edge_map[edge_key];
878 vec.push_back(std::make_pair(elem->id(), e));
890 int num_edge_this_blk = 0;
891 int num_nodes_per_edge = 0;
892 int num_edges_per_edge = 0;
893 int num_faces_per_edge = 0;
894 int num_attr_per_edge = 0;
905 EX_CHECK_ERR(
ex_err,
"Error getting edge block info.");
906 message(
"Info retrieved successfully for block: ", edge_block_id);
911 connect.resize(num_nodes_per_edge * num_edge_this_blk);
922 EX_CHECK_ERR(
ex_err,
"Error reading block connectivity.");
923 message(
"Connectivity retrieved successfully for block: ", edge_block_id);
932 for (
unsigned int i=0, sz=
connect.size(); i<sz; i+=num_nodes_per_edge)
935 for (
int n=0; n<num_nodes_per_edge; ++n)
937 int exodus_node_id =
connect[i+n];
938 int exodus_node_id_zero_based = exodus_node_id - 1;
939 int libmesh_node_id =
node_num_map[exodus_node_id_zero_based] - 1;
941 edge->set_node(n) =
mesh.node_ptr(libmesh_node_id);
950 auto & elem_edge_pair_vec =
951 libmesh_map_find(edge_map, edge_key);
953 for (
const auto & elem_edge_pair : elem_edge_pair_vec)
964 auto candidate_edge =
965 mesh.elem_ptr(elem_edge_pair.first)->
966 build_edge_ptr(elem_edge_pair.second);
970 bool is_match =
true;
971 for (
int n=0; n<num_nodes_per_edge; ++n)
972 if (candidate_edge->node_id(n) != edge->node_id(n))
982 elem_edge_pair.second,
1004 ex_err = exII::ex_get_elem_num_map
1007 EX_CHECK_ERR(
ex_err,
"Error retrieving element number map.");
1008 message(
"Element numbering map retrieved successfully.");
1014 for (
unsigned int i=0; i<static_cast<unsigned int>(std::min(10,
num_elem-1)); ++i)
1030 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset information.");
1031 message(
"All sideset information retrieved successfully.");
1045 char name_buffer[MAX_STR_LENGTH+1];
1048 ex_err = exII::ex_get_name(
ex_id, exII::EX_SIDE_SET,
1050 EX_CHECK_ERR(
ex_err,
"Error getting side set name.");
1053 message(
"All side set names retrieved successfully.");
1065 EX_CHECK_ERR(
ex_err,
"Error retrieving nodeset information.");
1066 message(
"All nodeset information retrieved successfully.");
1073 char name_buffer[MAX_STR_LENGTH+1];
1076 ex_err = exII::ex_get_name(
ex_id, exII::EX_NODE_SET,
1078 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1081 message(
"All node set names retrieved successfully.");
1088 libmesh_assert_less (
id,
ss_ids.size());
1091 libmesh_assert_less_equal (offset,
elem_list.size());
1092 libmesh_assert_less_equal (offset,
side_list.size());
1099 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset parameters.");
1100 message(
"Parameters retrieved successfully for sideset: ",
id);
1106 if (static_cast<unsigned int>(offset) ==
elem_list.size() ||
1107 static_cast<unsigned int>(offset) ==
side_list.size() )
1121 EX_CHECK_ERR(
ex_err,
"Error retrieving sideset data.");
1122 message(
"Data retrieved successfully for sideset: ",
id);
1142 EX_CHECK_ERR(
ex_err,
"Error retrieving nodeset parameters.");
1143 message(
"Parameters retrieved successfully for nodeset: ",
id);
1157 EX_CHECK_ERR(
ex_err,
"Error retrieving nodeset data.");
1158 message(
"Data retrieved successfully for nodeset: ",
id);
1170 (exII::EX_INQ_NODE_SETS,
1171 "Error retrieving number of node sets");
1174 int total_nodes_in_all_sets =
1176 (exII::EX_INQ_NS_NODE_LEN,
1177 "Error retrieving number of nodes in all node sets.");
1180 int total_df_in_all_sets =
1182 (exII::EX_INQ_NS_DF_LEN,
1183 "Error retrieving number of distribution factors in all node sets.");
1199 ex_err = exII::ex_get_concat_node_sets
1207 total_df_in_all_sets ?
1210 EX_CHECK_ERR(
ex_err,
"Error reading concatenated nodesets");
1213 char name_buffer[MAX_STR_LENGTH+1];
1216 ex_err = exII::ex_get_name
1221 EX_CHECK_ERR(
ex_err,
"Error getting node set name.");
1239 EX_CHECK_ERR(
ex_err,
"Error closing Exodus file.");
1240 message(
"Exodus file closed successfully.");
1251 float ret_float = 0.;
1259 EX_CHECK_ERR(
ex_err, error_msg);
1274 ex_err = exII::ex_get_all_times
1277 EX_CHECK_ERR(
ex_err,
"Error reading timesteps!");
1286 this->
inquire(exII::EX_INQ_TIME,
"Error retrieving number of time steps");
1297 unsigned int var_index = 0;
1314 libmesh_error_msg(
"Unable to locate variable named: " << nodal_var_name);
1320 std::vector<Real> unmapped_nodal_var_values(
num_nodes);
1323 ex_err = exII::ex_get_nodal_var
1329 EX_CHECK_ERR(
ex_err,
"Error reading nodal variable values!");
1331 for (
unsigned i=0; i<static_cast<unsigned>(
num_nodes); i++)
1361 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
1369 std::vector<std::string> & result)
1372 ex_err = exII::ex_get_var_param(
ex_id, var_type, &count);
1373 EX_CHECK_ERR(
ex_err,
"Error reading number of variables.");
1380 NamesData names_table(count, MAX_STR_LENGTH);
1387 EX_CHECK_ERR(
ex_err,
"Error reading variable names!");
1391 libMesh::out <<
"Read the variable(s) from the file:" << std::endl;
1392 for (
int i=0; i<count; i++)
1397 result.resize(count);
1400 for (
int i=0; i<count; i++)
1409 const std::vector<std::string> & names)
1431 libmesh_error_msg(
"Unrecognized ExodusVarType " << type);
1440 const std::vector<std::string> & names)
1443 count = cast_int<int>(names.size());
1446 ex_err = exII::ex_put_var_param(
ex_id, var_type, count);
1447 EX_CHECK_ERR(
ex_err,
"Error setting number of vars.");
1451 NamesData names_table(count, MAX_STR_LENGTH);
1454 for (
int i=0; i != count; ++i)
1459 libMesh::out <<
"Writing variable name(s) to file: " << std::endl;
1460 for (
int i=0; i != count; ++i)
1470 EX_CHECK_ERR(
ex_err,
"Error writing variable names.");
1478 std::map<dof_id_type, Real> & elem_var_value_map)
1483 unsigned int var_index = 0;
1500 libmesh_error_msg(
"Unable to locate variable named: " << elemental_var_name);
1504 unsigned ex_el_num = 0;
1510 for (
unsigned i=0; i<static_cast<unsigned>(
num_elem_blk); i++)
1518 EX_CHECK_ERR(
ex_err,
"Error getting number of elements in block.");
1531 ex_err = exII::ex_get_elem_var
1538 EX_CHECK_ERR(
ex_err,
"Error getting elemental values.");
1544 unsigned mapped_elem_id = this->
elem_num_map[ex_el_num] - 1;
1547 elem_var_value_map[mapped_elem_id] = block_elem_var_values[j];
1571 comp_ws = cast_int<int>(
sizeof(
float));
1572 io_ws = cast_int<int>(
sizeof(
float));
1578 comp_ws = cast_int<int>
1579 (std::min(
sizeof(
Real),
sizeof(
double)));
1580 io_ws = cast_int<int>
1581 (std::min(
sizeof(
Real),
sizeof(
double)));
1587 int mode = EX_CLOBBER;
1592 #ifdef LIBMESH_HAVE_HDF5
1594 mode |= EX_NOCLASSIC;
1597 ex_id = exII::ex_create(filename.c_str(), mode, &comp_ws, &io_ws);
1599 EX_CHECK_ERR(
ex_id,
"Error creating ExodusII mesh file.");
1602 libMesh::out <<
"File created successfully." << std::endl;
1616 unsigned int n_active_elem =
mesh.n_active_elem();
1633 if (!use_discontinuous)
1642 for (
const auto & elem :
mesh.active_element_ptr_range())
1646 std::vector<boundary_id_type> unique_side_boundaries;
1647 std::vector<boundary_id_type> unique_node_boundaries;
1653 std::vector<boundary_id_type> shellface_boundaries;
1655 for (
const auto &
id : shellface_boundaries)
1656 unique_side_boundaries.push_back(
id);
1660 num_side_sets = cast_int<int>(unique_side_boundaries.size());
1661 num_node_sets = cast_int<int>(unique_node_boundaries.size());
1664 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
1666 for (
const auto & elem :
mesh.active_element_ptr_range())
1671 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1672 if (elem->infinite())
1677 subdomain_map[cur_subdomain].push_back(elem->id());
1681 if (str_title.size() > MAX_LINE_LENGTH)
1683 libMesh::err <<
"Warning, Exodus files cannot have titles longer than "
1685 <<
" characters. Your title will be truncated."
1687 str_title.resize(MAX_LINE_LENGTH);
1709 exII::ex_init_params params = {};
1710 params.title[str_title.copy(params.title, MAX_LINE_LENGTH)] =
'\0';
1713 params.num_elem = n_active_elem;
1721 EX_CHECK_ERR(
ex_err,
"Error initializing new Exodus file.");
1755 if (!use_discontinuous)
1757 for (
const auto & node_ptr :
mesh.node_ptr_range())
1759 const Node & node = *node_ptr;
1785 for (
const auto & elem :
mesh.active_element_ptr_range())
1786 for (
const Node & node : elem->node_ref_range())
1788 x.push_back(node(0));
1790 y.push_back(node(1));
1795 z.push_back(node(2));
1809 ex_err = exII::ex_put_coord
1815 EX_CHECK_ERR(
ex_err,
"Error writing coordinates to Exodus file.");
1817 if (!use_discontinuous)
1821 EX_CHECK_ERR(
ex_err,
"Error writing node_num_map");
1830 unsigned int n_active_elem =
mesh.n_active_elem();
1837 typedef std::map<subdomain_id_type, std::vector<dof_id_type>> subdomain_map_type;
1838 subdomain_map_type subdomain_map;
1841 for (
const auto & elem :
mesh.active_element_ptr_range())
1846 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1847 if (elem->infinite())
1851 subdomain_map[ elem->subdomain_id() ].push_back(elem->id());
1858 std::vector<int>::iterator curr_elem_map_end =
elem_num_map.begin();
1860 std::vector<int> elem_blk_id;
1861 std::vector<int> num_elem_this_blk_vec;
1862 std::vector<int> num_nodes_per_elem_vec;
1863 std::vector<int> num_edges_per_elem_vec;
1864 std::vector<int> num_faces_per_elem_vec;
1865 std::vector<int> num_attr_vec;
1875 unsigned int counter = 0;
1876 for (
auto & pr : subdomain_map)
1882 subdomain_map_type::mapped_type & tmp_vec = pr.second;
1890 elem_blk_id.push_back(pr.first);
1892 num_elem_this_blk_vec.push_back(cast_int<int>(tmp_vec.size()));
1894 num_attr_vec.push_back(0);
1895 num_edges_per_elem_vec.push_back(0);
1896 num_faces_per_elem_vec.push_back(0);
1906 std::map<std::pair<dof_id_type, unsigned int>,
dof_id_type> discontinuous_node_indices;
1907 if (use_discontinuous)
1910 for (
const auto & elem :
mesh.active_element_ptr_range())
1911 for (
auto n : elem->node_index_range())
1913 std::pair<dof_id_type,unsigned int> id_pair;
1914 id_pair.first = elem->id();
1916 discontinuous_node_indices[id_pair] = node_counter;
1925 std::vector<BoundaryInfo::BCTuple> edge_tuples = bi.
build_edge_list();
1933 std::map<boundary_id_type, std::vector<int>> edge_id_to_conn;
1934 std::map<boundary_id_type, std::pair<ElemType, unsigned int>> edge_id_to_elem_type;
1936 for (
const auto & t : edge_tuples)
1939 unsigned int edge_id = std::get<1>(t);
1943 std::unique_ptr<const Elem> edge =
1944 mesh.elem_ptr(elem_id)->build_edge_ptr(edge_id);
1948 auto check_it = edge_id_to_elem_type.find(b_id);
1950 if (check_it == edge_id_to_elem_type.end())
1953 edge_id_to_elem_type[b_id] = std::make_pair(edge->type(), edge->n_nodes());
1958 auto & val_pair = check_it->second;
1959 if (val_pair.first != edge->type() || val_pair.second != edge->n_nodes())
1960 libmesh_error_msg(
"All edges in a block must have same geometric type.");
1964 auto & conn = edge_id_to_conn[b_id];
1970 for (
auto n : edge->node_index_range())
1972 dof_id_type libmesh_node_id = edge->node_ptr(n)->id();
1976 int exodus_node_id = -1;
1978 if (!use_discontinuous)
1979 exodus_node_id = libmesh_map_find
1991 const Elem * parent =
mesh.elem_ptr(elem_id);
1993 if (parent->
node_ptr(pn)->
id() == libmesh_node_id)
1995 exodus_node_id = libmesh_map_find
1996 (discontinuous_node_indices,
1997 std::make_pair(elem_id, pn));
2002 if (exodus_node_id == -1)
2003 libmesh_error_msg(
"Unable to map edge's libMesh node id to its Exodus node id.");
2005 conn.push_back(exodus_node_id);
2015 std::vector<int> edge_blk_id;
2017 std::vector<int> num_edge_this_blk_vec;
2018 std::vector<int> num_nodes_per_edge_vec;
2019 std::vector<int> num_attr_edge_vec;
2026 for (
const auto & pr : edge_id_to_conn)
2030 edge_blk_id.push_back(
id);
2033 const auto & elem_type_node_count = edge_id_to_elem_type[id];
2036 num_nodes_per_edge_vec.push_back(elem_type_node_count.second);
2040 num_edge_this_blk_vec.push_back(pr.second.size() / elem_type_node_count.second);
2043 num_attr_edge_vec.push_back(0);
2060 exII::ex_block_params params = {};
2063 params.elem_blk_id = elem_blk_id.data();
2065 params.num_elem_this_blk = num_elem_this_blk_vec.data();
2066 params.num_nodes_per_elem = num_nodes_per_elem_vec.data();
2067 params.num_edges_per_elem = num_edges_per_elem_vec.data();
2068 params.num_faces_per_elem = num_faces_per_elem_vec.data();
2069 params.num_attr_elem = num_attr_vec.data();
2070 params.define_maps = 0;
2075 params.edge_blk_id = edge_blk_id.data();
2077 params.num_edge_this_blk = num_edge_this_blk_vec.data();
2078 params.num_nodes_per_edge = num_nodes_per_edge_vec.data();
2079 params.num_attr_edge = num_attr_edge_vec.data();
2082 ex_err = exII::ex_put_concat_all_blocks(
ex_id, ¶ms);
2083 EX_CHECK_ERR(
ex_err,
"Error writing element blocks.");
2086 unsigned libmesh_elem_num_to_exodus_counter = 0;
2088 for (
auto & pr : subdomain_map)
2091 subdomain_map_type::mapped_type & tmp_vec = pr.second;
2103 unsigned int elem_id = tmp_vec[i];
2106 const Elem & elem =
mesh.elem_ref(elem_id);
2118 if (elem.
type() != conv.libmesh_elem_type())
2119 libmesh_error_msg(
"Error: Exodus requires all elements with a given subdomain ID to be the same type.\n" \
2120 <<
"Can't write both " \
2124 <<
" in the same block!");
2130 unsigned elem_node_index = conv.get_inverse_node_map(j);
2131 if (!use_discontinuous)
2141 cast_int<int>(libmesh_node_id));
2147 libmesh_map_find(discontinuous_node_indices,
2148 std::make_pair(elem_id, elem_node_index));
2153 ex_err = exII::ex_put_conn
2155 exII::EX_ELEM_BLOCK,
2160 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
2167 curr_elem_map_end = std::transform
2176 EX_CHECK_ERR(
ex_err,
"Error writing element map");
2182 EX_CHECK_ERR(
ex_err,
"Error writing element block names");
2186 for (
const auto & pr : edge_id_to_conn)
2188 ex_err = exII::ex_put_conn
2190 exII::EX_EDGE_BLOCK,
2195 EX_CHECK_ERR(
ex_err,
"Error writing element connectivities");
2201 ex_err = exII::ex_put_names
2203 exII::EX_EDGE_BLOCK,
2205 EX_CHECK_ERR(
ex_err,
"Error writing edge block names");
2218 std::map<int, std::vector<int>> elem;
2219 std::map<int, std::vector<int>> side;
2220 std::vector<boundary_id_type> side_boundary_ids;
2225 for (
const auto & t :
mesh.get_boundary_info().build_side_list())
2227 std::vector<const Elem *> family;
2228 #ifdef LIBMESH_ENABLE_AMR
2233 mesh.elem_ref(std::get<0>(t)).active_family_tree_by_side(family, std::get<1>(t),
false);
2235 family.push_back(
mesh.elem_ptr(std::get<0>(t)));
2238 for (
const auto & f : family)
2245 side[std::get<2>(t)].push_back(conv.get_inverse_side_map(std::get<1>(t)));
2249 mesh.get_boundary_info().build_side_boundary_ids(side_boundary_ids);
2256 for (
const auto & t :
mesh.get_boundary_info().build_shellface_list())
2258 std::vector<const Elem *> family;
2259 #ifdef LIBMESH_ENABLE_AMR
2264 mesh.elem_ref(std::get<0>(t)).active_family_tree_by_side(family, std::get<1>(t),
false);
2266 family.push_back(
mesh.elem_ptr(std::get<0>(t)));
2269 for (
const auto & f : family)
2276 side[std::get<2>(t)].push_back(conv.get_inverse_shellface_map(std::get<1>(t)));
2280 std::vector<boundary_id_type> shellface_boundary_ids;
2281 mesh.get_boundary_info().build_shellface_boundary_ids(shellface_boundary_ids);
2282 for (
const auto &
id : shellface_boundary_ids)
2283 side_boundary_ids.push_back(
id);
2287 if (side_boundary_ids.size() > 0)
2289 NamesData names_table(side_boundary_ids.size(), MAX_STR_LENGTH);
2291 std::vector<exII::ex_set> sets(side_boundary_ids.size());
2299 sets[i].type = exII::EX_SIDE_SET;
2300 sets[i].num_entry = elem[ss_id].size();
2301 sets[i].num_distribution_factor = 0;
2302 sets[i].entry_list = elem[ss_id].data();
2303 sets[i].extra_list = side[ss_id].data();
2304 sets[i].distribution_factor_list =
nullptr;
2307 ex_err = exII::ex_put_sets(
ex_id, side_boundary_ids.size(), sets.data());
2308 EX_CHECK_ERR(
ex_err,
"Error writing sidesets");
2310 ex_err = exII::ex_put_names(
ex_id, exII::EX_SIDE_SET, names_table.get_char_star_star());
2311 EX_CHECK_ERR(
ex_err,
"Error writing sideset names");
2325 typedef std::tuple<dof_id_type, boundary_id_type> tuple_t;
2326 std::vector<tuple_t> bc_tuples =
2327 mesh.get_boundary_info().build_node_list();
2331 std::stable_sort(bc_tuples.begin(), bc_tuples.end(),
2332 [](
const tuple_t & t1,
2334 {
return std::get<1>(t1) < std::get<1>(t2); });
2336 std::vector<boundary_id_type> node_boundary_ids;
2337 mesh.get_boundary_info().build_node_boundary_ids(node_boundary_ids);
2340 if (node_boundary_ids.size() > 0 &&
2341 bc_tuples.size() > 0)
2343 NamesData names_table(node_boundary_ids.size(), MAX_STR_LENGTH);
2361 std::map<boundary_id_type, unsigned int> nodeset_counts;
2362 for (
const auto & t : bc_tuples)
2367 nodeset_counts[nodeset_id] += 1;
2371 unsigned int running_sum = 0;
2372 for (
const auto & pr : nodeset_counts)
2377 names_table.push_back_entry(
mesh.get_boundary_info().get_nodeset_name(pr.first));
2378 running_sum += pr.second;
2383 exII::ex_set_specs set_data = {};
2392 ex_err = exII::ex_put_concat_sets(
ex_id, exII::EX_NODE_SET, &set_data);
2393 EX_CHECK_ERR(
ex_err,
"Error writing concatenated nodesets");
2396 ex_err = exII::ex_put_names(
ex_id, exII::EX_NODE_SET, names_table.get_char_star_star());
2397 EX_CHECK_ERR(
ex_err,
"Error writing nodeset names");
2404 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
2410 if (names.size() == 0)
2433 for (
auto var_num :
index_range(vars_active_subdomains))
2437 std::set<subdomain_id_type> current_set;
2438 if (vars_active_subdomains[var_num].empty())
2440 current_set.insert(cast_int<subdomain_id_type>(block_id));
2442 current_set = vars_active_subdomains[var_num];
2445 for (
auto block_id : current_set)
2449 libmesh_error_msg(
"ExodusII_IO_Helper: block id " << block_id <<
" not found in block_ids.");
2451 std::size_t block_index =
2454 std::size_t truth_tab_index = block_index*
num_elem_vars + var_num;
2455 truth_tab[truth_tab_index] = 1;
2463 EX_CHECK_ERR(
ex_err,
"Error writing element truth table.");
2474 if (names.size() == 0)
2502 if (names.size() == 0)
2523 std::vector<std::string> & names,
2524 std::vector<std::string> & names_from_file)
2539 names_from_file.begin(),
2540 [](
const std::string & a,
2541 const std::string & b) ->
bool
2543 return a.compare(0, MAX_STR_LENGTH, b) == 0;
2548 libMesh::err <<
"Error! The Exodus file already contains the variables:" << std::endl;
2549 for (
const auto &
name : names_from_file)
2552 libMesh::err <<
"And you asked to write:" << std::endl;
2553 for (
const auto &
name : names)
2556 libmesh_error_msg(
"Cannot overwrite existing variables in Exodus II file.");
2569 float cast_time = float(time);
2570 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
2574 double cast_time = double(time);
2575 ex_err = exII::ex_put_time(
ex_id, timestep, &cast_time);
2577 EX_CHECK_ERR(
ex_err,
"Error writing timestep.");
2580 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
2589 const std::vector<std::string> & var_names,
2590 const std::vector<std::set<boundary_id_type>> & side_ids,
2591 const std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
2620 std::vector<int> sset_var_tab(
num_side_sets * var_names.size());
2645 if (!side_ids[var].count(
ss_ids[ss]))
2649 sset_var_tab[ss*var_names.size() + var] = 1;
2655 const auto & data_map = bc_vals[var];
2674 unsigned int side_id =
side_list[i + offset] - 1;
2680 libmesh_error_msg(
"Error mapping Exodus elem id to libmesh elem id.");
2686 unsigned int converted_side_id = conv.
get_side_map(side_id);
2703 sset_var_vals[i] = libmesh_map_find(data_map, key);
2709 if (sset_var_vals.size() > 0)
2711 ex_err = exII::ex_put_sset_var
2718 EX_CHECK_ERR(
ex_err,
"Error writing sideset vars.");
2725 exII::ex_put_sset_var_tab(
ex_id,
2727 cast_int<int>(var_names.size()),
2728 sset_var_tab.data());
2729 EX_CHECK_ERR(
ex_err,
"Error writing sideset var truth table.");
2738 std::vector<std::string> & var_names,
2739 std::vector<std::set<boundary_id_type>> & side_ids,
2740 std::vector<std::map<BoundaryInfo::BCTuple, Real>> & bc_vals)
2750 ex_err = exII::ex_get_sset_var_tab
2754 sset_var_tab.data());
2755 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable truth table.");
2784 side_ids[var].insert(
ss_ids[ss]);
2790 ex_err = exII::ex_get_sset_var
2797 EX_CHECK_ERR(
ex_err,
"Error reading sideset variable.");
2810 unsigned int exodus_side_id =
side_list[i + offset];
2815 dof_id_type converted_elem_id = exodus_elem_id - 1;
2824 unsigned int converted_side_id = conv.
get_side_map(exodus_side_id - 1);
2843 bc_vals[var].insert(std::make_pair(key, sset_var_vals[i]));
2855 const std::vector<Real> & values,
2857 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
2864 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
2869 std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
2870 for (
const auto & elem :
mesh.active_element_ptr_range())
2871 subdomain_map[elem->subdomain_id()].push_back(elem->id());
2880 libmesh_assert_equal_to
2881 (vars_active_subdomains.size(),
2887 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
2890 auto it = subdomain_map.begin();
2893 const auto & active_subdomains
2894 = vars_active_subdomains[var_id];
2896 for (
unsigned int j=0; it!=subdomain_map.end(); ++it, ++j)
2901 if (!(active_subdomains.empty() || active_subdomains.count(it->first)))
2907 const auto & elem_nums = it->second;
2908 const unsigned int num_elems_this_block =
2909 cast_int<unsigned int>(elem_nums.size());
2910 std::vector<Real>
data(num_elems_this_block);
2915 for (
unsigned int k=0; k<num_elems_this_block; ++k)
2916 data[k] = values[var_id*
n_elem + elem_nums[k]];
2918 ex_err = exII::ex_put_elem_var
2923 num_elems_this_block,
2926 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
2931 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
2938 const std::vector<Real> & values,
2940 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains,
2941 const std::vector<std::string> & derived_var_names,
2942 const std::map<
subdomain_id_type, std::vector<std::string>> & subdomain_to_var_names)
2949 EX_CHECK_ERR(
ex_err,
"Error reading number of elemental variables.");
2956 std::map<subdomain_id_type, unsigned int> subdomain_to_n_elem;
2957 for (
const auto & elem :
mesh.active_element_ptr_range())
2958 subdomain_to_n_elem[elem->subdomain_id()] += 1;
2962 libmesh_assert_equal_to
2963 (vars_active_subdomains.size(),
2967 auto subdomain_to_n_elem_iter = subdomain_to_n_elem.begin();
2973 (
mesh.active_elements_begin(),
2974 mesh.active_elements_end());
2976 for (
unsigned int sbd_idx=0;
2977 subdomain_to_n_elem_iter != subdomain_to_n_elem.end();
2978 ++subdomain_to_n_elem_iter, ++sbd_idx)
2979 for (
unsigned int var_id=0; var_id<static_cast<unsigned>(
num_elem_vars); ++var_id)
2982 const auto & active_subdomains
2983 = vars_active_subdomains[var_id];
2990 if (!active_subdomains.count(subdomain_to_n_elem_iter->first))
2994 std::vector<Real>
data;
2995 data.reserve(subdomain_to_n_elem_iter->second);
2997 unsigned int values_offset = 0;
2998 for (
auto & elem : elem_range)
3005 auto subdomain_to_var_names_iter =
3006 subdomain_to_var_names.find(sbd_id);
3014 if (subdomain_to_var_names_iter == subdomain_to_var_names.end())
3017 const auto & var_names_this_sbd
3018 = subdomain_to_var_names_iter->second;
3021 if (sbd_id == subdomain_to_n_elem_iter->first)
3029 std::find(var_names_this_sbd.begin(),
3030 var_names_this_sbd.end(),
3031 derived_var_names[var_id]);
3033 if (pos == var_names_this_sbd.end())
3034 libmesh_error_msg(
"Derived name " << derived_var_names[var_id] <<
" not found!");
3041 data.push_back(values[values_offset + true_index]);
3046 auto true_offset = var_names_this_sbd.size();
3049 values_offset += true_offset;
3055 ex_err = exII::ex_put_elem_var
3059 EX_CHECK_ERR(
ex_err,
"Error writing element values.");
3064 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
3071 const std::vector<Real> & values,
3077 if (!values.empty())
3079 ex_err = exII::ex_put_nodal_var
3083 EX_CHECK_ERR(
ex_err,
"Error writing nodal values.");
3086 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
3101 int num_info =
inquire(exII::EX_INQ_INFO,
"Error retrieving the number of information records from file!");
3104 libMesh::err <<
"Warning! The Exodus file already contains information records.\n"
3105 <<
"Exodus does not support writing additional records in this situation."
3110 int num_records = cast_int<int>(records.size());
3112 if (num_records > 0)
3114 NamesData info(num_records, MAX_LINE_LENGTH);
3118 for (
const auto & record : records)
3122 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
3125 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
3136 if (!values.empty())
3138 ex_err = exII::ex_put_glob_vars
3142 EX_CHECK_ERR(
ex_err,
"Error writing global values.");
3145 EX_CHECK_ERR(
ex_err,
"Error flushing buffers to file.");
3158 ex_err = exII::ex_get_glob_vars
3162 EX_CHECK_ERR(
ex_err,
"Error reading global values.");
3187 std::vector<std::string>
3190 std::vector<std::string> complex_names;
3194 for (
const auto &
name : names)
3196 complex_names.push_back(
"r_" +
name);
3197 complex_names.push_back(
"i_" +
name);
3198 complex_names.push_back(
"a_" +
name);
3201 return complex_names;
3207 const std::vector<std::set<subdomain_id_type>> & vars_active_subdomains)
const
3209 std::vector<std::set<subdomain_id_type>> complex_vars_active_subdomains;
3211 for (
auto & s : vars_active_subdomains)
3215 complex_vars_active_subdomains.push_back(s);
3216 complex_vars_active_subdomains.push_back(s);
3217 complex_vars_active_subdomains.push_back(s);
3220 return complex_vars_active_subdomains;
3225 std::map<subdomain_id_type, std::vector<std::string>>
3228 const std::map<
subdomain_id_type, std::vector<std::string>> & subdomain_to_var_names)
const
3231 std::map<subdomain_id_type, std::vector<std::string>> ret;
3233 for (
const auto & pr : subdomain_to_var_names)
3236 auto & vec = ret[pr.first];
3239 const auto & varnames = pr.second;
3242 vec.reserve(3 * varnames.size());
3247 for (
const auto & varname : varnames)
3249 vec.push_back(
"r_" + varname);
3250 vec.push_back(
"i_" + varname);
3251 vec.push_back(
"a_" + varname);
3264 libmesh_assert_less (i, node_map->size());
3265 return (*node_map)[i];
3272 if (!inverse_node_map)
3275 libmesh_assert_less (i, inverse_node_map->size());
3276 return (*inverse_node_map)[i];
3288 if (static_cast<size_t>(i) >= side_map->size())
3291 return (*side_map)[i];
3299 if (!inverse_side_map)
3302 libmesh_assert_less (i, inverse_side_map->size());
3303 return (*inverse_side_map)[i];
3317 libmesh_assert_less (i, shellface_map->size());
3318 return (*shellface_map)[i];
3325 if (!inverse_shellface_map)
3328 libmesh_assert_less (i, inverse_shellface_map->size());
3329 return (*inverse_shellface_map)[i];
3336 return libmesh_type;
3353 return shellface_index_offset;
3357 data_table(n_strings),
3358 data_table_pointers(n_strings),
3360 table_size(n_strings)
3362 for (
size_t i=0; i<n_strings; ++i)
3378 libmesh_assert_less (counter, table_size);
3381 size_t num_copied =
name.copy(data_table[counter].
data(), data_table[counter].size()-1);
3384 data_table[counter][num_copied] =
'\0';
3394 return data_table_pointers.data();
3401 if (static_cast<unsigned>(i) >= table_size)
3402 libmesh_error_msg(
"Requested char * " << i <<
" but only have " << table_size <<
"!");
3405 return data_table[i].data();
3413 #endif // #ifdef LIBMESH_HAVE_EXODUS_API