// Copyright(C) 1999-2023 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // // See packages/seacas/LICENSE for details #include "ED_SystemInterface.h" // for SystemInterface, etc #include "edge_block.h" // for Edge_Block #include "exoII_read.h" #include "exo_block.h" // for Exo_Block #include "exodusII.h" // for ex_init_params, ex_opts, etc #include "face_block.h" // for Face_Block #include "fmt/ostream.h" #include "node_set.h" // for Node_Set #include "side_set.h" // for Side_Set #include "smart_assert.h" // for SMART_ASSERT, Assert, etc #include "stringx.h" // for chop_whitespace #include "util.h" // for free_name_array, etc #include // for copy #include // for int64_t #include // for fclose, FILE, fopen #include // for exit #include // for strlen #include #include // for set #include // for string, char_traits, etc #include // for vector namespace { void read_vars(int file_id, EXOTYPE flag, const char *type, int num_vars, std::vector &varlist); } // namespace template ExoII_Read::ExoII_Read() = default; template ExoII_Read::ExoII_Read(const std::string &fname) : file_name(fname) {} template ExoII_Read::~ExoII_Read() { try { SMART_ASSERT(Check_State()); if (file_id >= 0) { std::string err = Close_File(); if (!err.empty()) { Error(fmt::format("ExoII_Read destructor(): closing file: \"{}\"\n", err)); } } delete[] eblocks; delete[] nsets; delete[] ssets; delete[] nodes; delete[] times; delete[] edge_blocks; delete[] face_blocks; if (results) { for (unsigned i = 0; i < nodal_vars.size(); ++i) { delete[] results[i]; } delete[] results; } delete[] global_vals; delete[] global_vals2; delete[] node_map; delete[] elmt_map; delete[] elmt_order; } catch (...) { } } template std::string ExoII_Read::Close_File() { SMART_ASSERT(Check_State()); if (file_id < 0) { return "exodiff: ERROR: File is not open!"; } int err = ex_close(file_id); if (err < 0) { Error(fmt::format("ExoII_Read::Close_File(): {}: Unable to close file! Aborting...\n", err)); } if (err > 0) { return fmt::format("WARNING: {} issued upon close", err); } file_id = -1; return ""; } template double ExoII_Read::Time(int time_num) const { SMART_ASSERT(Check_State()); SMART_ASSERT(time_num > 0 && time_num <= num_times)(time_num)(num_times); return times[time_num - 1]; } template const std::string &ExoII_Read::Global_Var_Name(int index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(index >= 0 && (unsigned)index < global_vars.size()); return global_vars[index]; } template const std::string &ExoII_Read::Nodal_Var_Name(int index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(index >= 0 && (unsigned)index < nodal_vars.size()); return nodal_vars[index]; } template const std::string &ExoII_Read::Element_Var_Name(int index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(index >= 0 && (unsigned)index < elmt_vars.size()); return elmt_vars[index]; } template const std::string &ExoII_Read::Element_Att_Name(int index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(index >= 0 && (unsigned)index < elmt_atts.size()); return elmt_atts[index]; } template const std::string &ExoII_Read::NS_Var_Name(int index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(index >= 0 && (unsigned)index < ns_vars.size()); return ns_vars[index]; } template const std::string &ExoII_Read::SS_Var_Name(int index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(index >= 0 && (unsigned)index < ss_vars.size()); return ss_vars[index]; } template const std::string &ExoII_Read::EB_Var_Name(int index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(index >= 0 && (unsigned)index < eb_vars.size()); return eb_vars[index]; } template const std::string &ExoII_Read::FB_Var_Name(int index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(index >= 0 && (unsigned)index < fb_vars.size()); return fb_vars[index]; } template Exo_Block *ExoII_Read::Get_Element_Block_by_Index(size_t block_index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(block_index < num_elmt_blocks); return &eblocks[block_index]; } template Exo_Block *ExoII_Read::Get_Element_Block_by_Id(size_t id) const { SMART_ASSERT(Check_State()); for (size_t i = 0; i < num_elmt_blocks; i++) { if (eblocks[i].Id() == id) { return &eblocks[i]; } } return nullptr; } template Exo_Block *ExoII_Read::Get_Element_Block_by_Name(const std::string &name) const { SMART_ASSERT(Check_State()); for (size_t i = 0; i < num_elmt_blocks; i++) { if (eblocks[i].Name() == name) { return &eblocks[i]; } } return nullptr; } template Exo_Entity *ExoII_Read::Get_Entity_by_Index(EXOTYPE type, size_t block_index) const { SMART_ASSERT(Check_State()); switch (type) { case EX_ELEM_BLOCK: SMART_ASSERT(block_index < num_elmt_blocks); return &eblocks[block_index]; case EX_NODE_SET: SMART_ASSERT(block_index < num_node_sets); return &nsets[block_index]; case EX_SIDE_SET: SMART_ASSERT(block_index < num_side_sets); return &ssets[block_index]; case EX_EDGE_BLOCK: SMART_ASSERT(block_index < num_edge_blocks); return &edge_blocks[block_index]; case EX_FACE_BLOCK: SMART_ASSERT(block_index < num_face_blocks); return &face_blocks[block_index]; default: return nullptr; } } template Exo_Entity *ExoII_Read::Get_Entity_by_Id(EXOTYPE type, size_t id) const { SMART_ASSERT(Check_State()); switch (type) { case EX_ELEM_BLOCK: for (size_t i = 0; i < num_elmt_blocks; i++) { if (eblocks[i].Id() == id) { return &eblocks[i]; } } break; case EX_NODE_SET: for (size_t i = 0; i < num_node_sets; i++) { if (nsets[i].Id() == id) { return &nsets[i]; } } break; case EX_SIDE_SET: for (size_t i = 0; i < num_side_sets; i++) { if (ssets[i].Id() == id) { return &ssets[i]; } } break; case EX_EDGE_BLOCK: for (size_t i = 0; i < num_edge_blocks; i++) { if (edge_blocks[i].Id() == id) { return &edge_blocks[i]; } } break; case EX_FACE_BLOCK: for (size_t i = 0; i < num_face_blocks; i++) { if (face_blocks[i].Id() == id) { return &face_blocks[i]; } } break; default: return nullptr; } return nullptr; } template Exo_Entity *ExoII_Read::Get_Entity_by_Name(EXOTYPE type, const std::string &name) const { SMART_ASSERT(Check_State()); switch (type) { case EX_ELEM_BLOCK: for (size_t i = 0; i < num_elmt_blocks; i++) { if (eblocks[i].Name() == name) { return &eblocks[i]; } } break; case EX_NODE_SET: for (size_t i = 0; i < num_node_sets; i++) { if (nsets[i].Name() == name) { return &nsets[i]; } } break; case EX_SIDE_SET: for (size_t i = 0; i < num_side_sets; i++) { if (ssets[i].Name() == name) { return &ssets[i]; } } break; case EX_EDGE_BLOCK: for (size_t i = 0; i < num_edge_blocks; i++) { if (edge_blocks[i].Name() == name) { return &edge_blocks[i]; } } break; case EX_FACE_BLOCK: for (size_t i = 0; i < num_face_blocks; i++) { if (face_blocks[i].Name() == name) { return &face_blocks[i]; } } break; default: return nullptr; } return nullptr; } template Node_Set *ExoII_Read::Get_Node_Set_by_Id(size_t set_id) const { SMART_ASSERT(Check_State()); for (size_t i = 0; i < num_node_sets; i++) { if (nsets[i].Id() == set_id) { return &nsets[i]; } } return nullptr; } template Node_Set *ExoII_Read::Get_Node_Set_by_Name(const std::string &name) const { SMART_ASSERT(Check_State()); for (size_t i = 0; i < num_node_sets; i++) { if (nsets[i].Name() == name) { return &nsets[i]; } } return nullptr; } template Side_Set *ExoII_Read::Get_Side_Set_by_Id(size_t set_id) const { SMART_ASSERT(Check_State()); for (size_t i = 0; i < num_side_sets; i++) { if (ssets[i].Id() == set_id) { return &ssets[i]; } } return nullptr; } template Side_Set *ExoII_Read::Get_Side_Set_by_Name(const std::string &name) const { SMART_ASSERT(Check_State()); for (size_t i = 0; i < num_side_sets; i++) { if (ssets[i].Name() == name) { return &ssets[i]; } } return nullptr; } template Edge_Block *ExoII_Read::Get_Edge_Block_by_Id(size_t block_id) const { SMART_ASSERT(Check_State()); for (size_t i = 0; i < num_edge_blocks; i++) { if (edge_blocks[i].Id() == block_id) { return &edge_blocks[i]; } } return nullptr; } template Edge_Block *ExoII_Read::Get_Edge_Block_by_Name(const std::string &name) const { SMART_ASSERT(Check_State()); for (size_t i = 0; i < num_edge_blocks; i++) { if (edge_blocks[i].Name() == name) { return &edge_blocks[i]; } } return nullptr; } template Face_Block *ExoII_Read::Get_Face_Block_by_Id(size_t block_id) const { SMART_ASSERT(Check_State()); for (size_t i = 0; i < num_face_blocks; i++) { if (face_blocks[i].Id() == block_id) { return &face_blocks[i]; } } return nullptr; } template Face_Block *ExoII_Read::Get_Face_Block_by_Name(const std::string &name) const { SMART_ASSERT(Check_State()); for (size_t i = 0; i < num_face_blocks; i++) { if (face_blocks[i].Name() == name) { return &face_blocks[i]; } } return nullptr; } template std::string ExoII_Read::Load_Element_Block_Description(size_t block_index) const { SMART_ASSERT(Check_State()); if (!Open()) { return "exodiff: ERROR: Must open file before loading blocks!"; } SMART_ASSERT(block_index < num_elmt_blocks); eblocks[block_index].Load_Connectivity(); // eblocks[idx].Load_Connectivity(); // eblocks[idx].Load_Attributes(); return ""; } template std::string ExoII_Read::Load_Element_Block_Descriptions() const { SMART_ASSERT(Check_State()); if (!Open()) { return "exodiff: ERROR: Must open file before loading blocks!"; } for (size_t b = 0; b < num_elmt_blocks; ++b) { eblocks[b].Load_Connectivity(); } return ""; } template std::string ExoII_Read::Free_Element_Block(size_t block_index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(block_index < num_elmt_blocks); eblocks[block_index].Free_Connectivity(); eblocks[block_index].Free_Attributes(); return ""; } template std::string ExoII_Read::Free_Element_Blocks() const { SMART_ASSERT(Check_State()); for (size_t b = 0; b < num_elmt_blocks; ++b) { eblocks[b].Free_Connectivity(); eblocks[b].Free_Attributes(); } return ""; } template size_t ExoII_Read::Block_Id(size_t block_index) const { SMART_ASSERT(Check_State()); SMART_ASSERT(block_index < num_elmt_blocks); return eblocks[block_index].Id(); } template std::string ExoII_Read::Load_Node_Map() { SMART_ASSERT(Check_State()); if (!Open()) { return "WARNING: File not open!"; } delete[] node_map; node_map = nullptr; if (num_nodes == 0) { return "WARNING: There are no nodes!"; } node_map = new INT[num_nodes]; SMART_ASSERT(node_map != nullptr); ex_opts(0); // Temporarily turn off error reporting in case map isn't stored. int err = ex_get_id_map(file_id, EX_NODE_MAP, node_map); ex_opts(EX_VERBOSE); if (err < 0) { Error(fmt::format("Unable to load node map; Exodus error = {}. Aborting...\n", err)); } else if (err > 0) { return "WARNING: Default node map being used."; } return ""; } template std::string ExoII_Read::Free_Node_Map() { SMART_ASSERT(Check_State()); delete[] node_map; node_map = nullptr; return ""; } template std::string ExoII_Read::Load_Element_Map() { SMART_ASSERT(Check_State()); if (!Open()) { return "WARNING: File not open!"; } delete[] elmt_map; elmt_map = nullptr; if (num_elmts == 0) { return "WARNING: There are no elements!"; } elmt_map = new INT[num_elmts]; SMART_ASSERT(elmt_map != nullptr); ex_opts(0); // Temporarily turn off error reporting in case map isn't stored. int err = ex_get_id_map(file_id, EX_ELEM_MAP, elmt_map); ex_opts(EX_VERBOSE); if (err < 0) { Error(fmt::format("Unable to load element map; Exodus error = {}. Aborting...\n", err)); } else if (err > 0) { return "WARNING: Default element map being used."; } return ""; } template std::string ExoII_Read::Free_Element_Map() { SMART_ASSERT(Check_State()); delete[] elmt_map; elmt_map = nullptr; return ""; } template std::string ExoII_Read::Load_Nodal_Coordinates() { SMART_ASSERT(Check_State()); if (!Open()) { return "WARNING: File not open!"; } if (num_nodes) { size_t count = num_nodes * dimension; nodes = new double[count]; SMART_ASSERT(nodes != nullptr); double *x = nodes, *y = nodes, *z = nodes; if (dimension > 1) { y = nodes + num_nodes; } if (dimension > 2) { z = nodes + (2 * num_nodes); } int err = ex_get_coord(file_id, x, y, z); if (err < 0) { Error("Failed to get nodal coordinates! Aborting...\n"); } else if (err > 0) { delete[] nodes; nodes = nullptr; return fmt::format("exodiff: WARNING: " "Exodus issued warning \"{}\" on call to ex_get_coord()!" " I'm not going to keep what it gave me for coordinates.", err); } } else { return "WARNING: There are no nodes!"; } return ""; } template void ExoII_Read::Free_Nodal_Coordinates() { SMART_ASSERT(Check_State()); delete[] nodes; nodes = nullptr; } template std::string ExoII_Read::Load_Nodal_Results(int time_step_num, int var_index) { SMART_ASSERT(Check_State()); SMART_ASSERT(time_step_num > 0 && time_step_num <= num_times); SMART_ASSERT(var_index >= 0 && (unsigned)var_index < nodal_vars.size()); if (!Open()) { return "WARNING: File not open!"; } if (cur_time != time_step_num) { for (unsigned i = 0; i < nodal_vars.size(); ++i) { delete[] results[i]; results[i] = nullptr; } cur_time = time_step_num; } if (num_nodes) { results[var_index] = new double[num_nodes]; int err = ex_get_var(file_id, cur_time, EX_NODAL, var_index + 1, 0, num_nodes, results[var_index]); if (err < 0) { Error("ExoII_Read::Load_Nodal_Results(): Failed to get " "nodal variable values! Aborting...\n"); } else if (err > 0) { delete[] results[var_index]; results[var_index] = nullptr; return fmt::format("ExoII_Read::Load_Nodal_Results(): WARNING: " "Exodus issued warning \"{}\" on call to ex_get_var()!" " I'm not going to keep what it gave me for values.", err); } } else { return "WARNING: There are no nodes!"; } return ""; } template const double *ExoII_Read::Get_Nodal_Results(int t1, int t2, double proportion, int var_index) const // Interpolated results. { static double *st_results = nullptr; static double *st_results2 = nullptr; SMART_ASSERT(Check_State()); SMART_ASSERT(t1 > 0 && t1 <= num_times); SMART_ASSERT(t2 > 0 && t2 <= num_times); SMART_ASSERT(var_index >= 0 && (unsigned)var_index < nodal_vars.size()); if (!Open()) { return nullptr; } if (st_results == nullptr) { st_results = new double[num_nodes]; } int err = ex_get_var(file_id, t1, EX_NODAL, var_index + 1, 0, num_nodes, st_results); if (err < 0) { Error("ExoII_Read::Get_Nodal_Results(): Failed to get " "nodal variable values! Aborting...\n"); } if (t1 != t2) { if (st_results2 == nullptr) { st_results2 = new double[num_nodes]; } err = ex_get_var(file_id, t2, EX_NODAL, var_index + 1, 0, num_nodes, st_results2); if (err < 0) { Error("ExoII_Read::Load_Nodal_Results(): Failed to get " "nodal variable values! Aborting...\n"); } // Interpolate the values... for (size_t i = 0; i < num_nodes; i++) { st_results[i] = (1.0 - proportion) * st_results[i] + proportion * st_results2[i]; } } return st_results; } template void ExoII_Read::Free_Nodal_Results() { SMART_ASSERT(Check_State()); if (results) { for (unsigned i = 0; i < nodal_vars.size(); ++i) { delete[] results[i]; results[i] = nullptr; } } } template void ExoII_Read::Free_Nodal_Results(int var_index) { SMART_ASSERT(Check_State()); if (results) { if (results[var_index]) { delete[] results[var_index]; results[var_index] = nullptr; } } } template const double *ExoII_Read::Get_Nodal_Results(int var_index) const { SMART_ASSERT(Check_State()); if (cur_time == 0) { return nullptr; } SMART_ASSERT(var_index >= 0 && (unsigned)var_index < nodal_vars.size()); return results[var_index]; } template std::string ExoII_Read::Load_Global_Results(int time_step_num) { SMART_ASSERT(Check_State()); SMART_ASSERT(time_step_num > 0 && time_step_num <= num_times); if (!Open()) { return "WARNING: File not open!"; } if (global_vars.empty()) { return "WARNING: No global variables! (doing nothing)"; } if (global_vals == nullptr) { global_vals = new double[global_vars.size()]; SMART_ASSERT(global_vals != nullptr); } for (unsigned j = 0; j < global_vars.size(); ++j) { global_vals[j] = 0.0; } int err = ex_get_var(file_id, time_step_num, EX_GLOBAL, 1, 1, global_vars.size(), global_vals); if (err < 0) { Error("ExoII_Read::Load_Global_Results(): Failed to get " "global variable values! Aborting...\n"); } else if (err > 0) { return fmt::format("ExoII_Read::Load_Global_Results(): WARNING: " "Exodus issued warning \"{}\" on call to ex_get_glob_vars()!", err); } return ""; } template std::string ExoII_Read::Load_Global_Results(int t1, int t2, double proportion) { SMART_ASSERT(Check_State()); SMART_ASSERT(t1 > 0 && t1 <= num_times); SMART_ASSERT(t2 > 0 && t2 <= num_times); if (!Open()) { return "WARNING: File not open!"; } if (global_vars.empty()) { return "WARNING: No global variables! (doing nothing)"; } if (global_vals == nullptr) { global_vals = new double[global_vars.size()]; SMART_ASSERT(global_vals != nullptr); } if (t2 != t1 && (global_vals2 == nullptr)) { global_vals2 = new double[global_vars.size()]; SMART_ASSERT(global_vals2 != nullptr); } for (unsigned j = 0; j < global_vars.size(); ++j) { global_vals[j] = 0.0; } int err = ex_get_var(file_id, t1, EX_GLOBAL, 1, 1, global_vars.size(), global_vals); if (err < 0) { Error("ExoII_Read::Load_Global_Results(): Failed to get " "global variable values! Aborting...\n"); } if (t2 != t1) { err = ex_get_var(file_id, t2, EX_GLOBAL, 1, 1, global_vars.size(), global_vals2); if (err < 0) { Error("ExoII_Read::Load_Global_Results(): Failed to get " "global variable values! Aborting...\n"); } // Do the interpolation... for (size_t j = 0; j < global_vars.size(); j++) { global_vals[j] = (1.0 - proportion) * global_vals[j] + proportion * global_vals2[j]; } } return ""; } template Side_Set *ExoII_Read::Get_Side_Set_by_Index(size_t side_set_index) const { SMART_ASSERT(Check_State()); if (side_set_index >= num_side_sets) { return nullptr; } return &ssets[side_set_index]; } template Node_Set *ExoII_Read::Get_Node_Set_by_Index(size_t set_index) const { SMART_ASSERT(Check_State()); if (set_index >= num_node_sets) { return nullptr; } return &nsets[set_index]; } template Edge_Block *ExoII_Read::Get_Edge_Block_by_Index(size_t edge_block_index) const { SMART_ASSERT(Check_State()); if (edge_block_index >= num_edge_blocks) { return nullptr; } return &edge_blocks[edge_block_index]; } template Face_Block *ExoII_Read::Get_Face_Block_by_Index(size_t face_block_index) const { SMART_ASSERT(Check_State()); if (face_block_index >= num_face_blocks) { return nullptr; } return &face_blocks[face_block_index]; } // ********************** Misc functions *************************** // // This function converts an Exodus global element number (1-offset) into // its block index (0-offset) and block element index (0-offset). template std::pair ExoII_Read::Global_to_Block_Local(size_t global_elmt_num) const { SMART_ASSERT(Check_State()); if (!Open()) { Error("exodiff: ERROR: File not open!"); } if (global_elmt_num < 1 || global_elmt_num > num_elmts) { Error(fmt::format("exodiff: ERROR: global_elmt_num = {} is out of bounds [1, {}]!", fmt::group_digits(global_elmt_num), fmt::group_digits(num_elmts))); } int block_index = 0; size_t total = 0; while (total + eblocks[block_index].Size() < global_elmt_num) { total += eblocks[block_index++].Size(); } return std::make_pair(block_index, global_elmt_num - total - 1); } template int ExoII_Read::Check_State() const { SMART_ASSERT(file_id >= -1); SMART_ASSERT(db_version >= 0.0); SMART_ASSERT(api_version >= 0.0); SMART_ASSERT(io_word_size == 0 || io_word_size == 4 || io_word_size == 8); SMART_ASSERT(!(file_id >= 0 && io_word_size == 0)); SMART_ASSERT(!(file_id >= 0 && file_name == "")); SMART_ASSERT(!(num_elmt_blocks > 0 && !eblocks)); SMART_ASSERT(!(num_node_sets > 0 && !nsets)); SMART_ASSERT(!(num_side_sets > 0 && !ssets)); SMART_ASSERT(!(num_nodes == 0 && nodes)); SMART_ASSERT(num_times >= 0); SMART_ASSERT(!(num_times > 0 && !times)); SMART_ASSERT(cur_time >= 0 && cur_time <= num_times); SMART_ASSERT(!(!nodal_vars.empty() && !results)); SMART_ASSERT(!(nodal_vars.empty() && results)); return 1; } template std::string ExoII_Read::File_Name(const char *fname) { SMART_ASSERT(Check_State()); if (Open()) { return "exodiff: ERROR: File is already open!"; } if ((fname == nullptr) || std::strlen(fname) == 0) { return "exodiff: ERROR: File name is empty!"; } file_name = fname; return ""; } template std::string ExoII_Read::Open_File(const char *fname) { SMART_ASSERT(Check_State()); if (Open()) { return "exodiff: ERROR: File already open!"; } if ((fname != nullptr) && std::strlen(fname) > 0) { file_name = fname; } else if (file_name == "") { return "No file name to open!"; } int ws = 0, comp_ws = 8; float dumb = 0.0; int mode = EX_READ; if (sizeof(INT) == 8) { mode |= EX_ALL_INT64_API; } auto old_opt = ex_opts(EX_VERBOSE); int err = ex_open(file_name.c_str(), mode, &comp_ws, &ws, &dumb); ex_opts(old_opt); if (err < 0) { std::ostringstream oss; fmt::print(oss, "Couldn't open file \"{}\".", file_name); // ExodusII library could not open file. See if a file (exodusII // or not) exists with the specified name. FILE *fid = fopen(file_name.c_str(), "r"); if (fid != nullptr) { fmt::print(oss, " File exists, but library could not open."); fclose(fid); } else { fmt::print(oss, " File does not exist."); } return oss.str(); } file_id = err; io_word_size = ws; Get_Init_Data(); return ""; } template void ExoII_Read::Get_Init_Data() { SMART_ASSERT(Check_State()); SMART_ASSERT(file_id >= 0); // Determine max size of entity and variable names on the database int length_name = ex_inquire_int(file_id, EX_INQ_DB_MAX_USED_NAME_LENGTH); ex_set_max_name_length(file_id, length_name); ex_init_params info{}; info.title[0] = '\0'; int err = ex_get_init_ext(file_id, &info); if (err < 0) { Error(fmt::format("Failed to get init data!" " Error number = {}. Aborting...\n", err)); } dimension = info.num_dim; num_nodes = info.num_nodes; num_elmts = info.num_elem; num_faces = info.num_face; num_edges = info.num_edge; num_elmt_blocks = info.num_elem_blk; num_node_sets = info.num_node_sets; num_side_sets = info.num_side_sets; num_edge_blocks = info.num_edge_blk; num_face_blocks = info.num_face_blk; title = info.title; if (err > 0 && !interFace.quiet_flag) { fmt::print(stderr, "exodiff: WARNING: was issued, number = {}\n", err); } if (dimension < 1 || dimension > 3) { Error(fmt::format("Init data appears corrupt:\n" " dimension = {}\n" " num_nodes = {}\n" " num_elmts = {}\n" " num_elmt_blocks = {}\n" " num_node_sets = {}\n" " num_side_sets = {}\n" " num_edge_blocks = {}\n" " num_face_blocks = {}\n" " ... Aborting...\n", dimension, fmt::group_digits(num_nodes), fmt::group_digits(num_elmts), num_elmt_blocks, num_node_sets, num_edge_blocks, num_face_blocks, num_side_sets)); } int num_qa = ex_inquire_int(file_id, EX_INQ_QA); int num_info = ex_inquire_int(file_id, EX_INQ_INFO); if (num_qa < 0 || num_info < 0) { Error(fmt::format("inquire data appears corrupt:\n" " num_qa = {}\n" " num_info = {}\n" " ... Aborting...\n", num_qa, num_info)); } // Coordinate Names... char **coords = get_name_array(3, length_name); err = ex_get_coord_names(file_id, coords); if (err < 0) { Error("Failed to get coordinate names! Aborting...\n"); } coord_names.clear(); for (int i = 0; i < dimension; ++i) { coord_names.push_back(coords[i]); } free_name_array(coords, 3); // Element Block Data... if (eblocks) { delete[] eblocks; } eblocks = nullptr; if (num_elmt_blocks > 0) { eblocks = new Exo_Block[num_elmt_blocks]; SMART_ASSERT(eblocks != nullptr); std::vector ids(num_elmt_blocks); err = ex_get_ids(file_id, EX_ELEM_BLOCK, ids.data()); if (err < 0) { Error("Failed to get element block ids! Aborting...\n"); } size_t e_count = 0; for (size_t b = 0; b < num_elmt_blocks; ++b) { if (ids[b] <= EX_INVALID_ID) { fmt::print(stderr, "EXODIFF WARNING: Element block Id " "for block index {} is {} which is negative. This was returned by call to " "ex_get_elem_blk_ids().\n", b, ids[b]); } eblocks[b].initialize(file_id, ids[b]); eblocks[b].offset(e_count); e_count += eblocks[b].Size(); } if (e_count != num_elmts && !interFace.quiet_flag) { fmt::print(stderr, "exodiff: WARNING: Total number of elements {}" " does not equal the sum of the number of elements " "in each block {}\n", fmt::group_digits(num_elmts), fmt::group_digits(e_count)); } // Gather the attribute names (even though not all attributes are on all blocks) std::set names; for (size_t b = 0; b < num_elmt_blocks; ++b) { for (int a = 0; a < eblocks[b].attr_count(); a++) { names.insert(eblocks[b].Get_Attribute_Name(a)); } } elmt_atts.resize(names.size()); std::copy(names.begin(), names.end(), elmt_atts.begin()); } // Node & Side sets... if (nsets) { delete[] nsets; } nsets = nullptr; if (num_node_sets > 0) { nsets = new Node_Set[num_node_sets]; SMART_ASSERT(nsets != nullptr); std::vector ids(num_node_sets); err = ex_get_ids(file_id, EX_NODE_SET, ids.data()); if (err < 0) { Error("Failed to get nodeset ids! Aborting...\n"); } for (size_t nset = 0; nset < num_node_sets; ++nset) { if (ids[nset] <= EX_INVALID_ID) { fmt::print(stderr, "EXODIFF WARNING: Nodeset Id " "for nodeset index {} is {}" " which is negative. This was returned by call to ex_get_ids().\n", nset, ids[nset]); } nsets[nset].initialize(file_id, ids[nset]); } } if (ssets) { delete[] ssets; } ssets = nullptr; if (num_side_sets) { ssets = new Side_Set[num_side_sets]; SMART_ASSERT(ssets != nullptr); std::vector ids(num_side_sets); err = ex_get_ids(file_id, EX_SIDE_SET, ids.data()); if (err < 0) { Error("Failed to get sideset ids! Aborting...\n"); } for (size_t sset = 0; sset < num_side_sets; ++sset) { if (ids[sset] <= EX_INVALID_ID) { fmt::print(stderr, "EXODIFF WARNING: Sideset Id for sideset index {} is {}" " which is negative. This was returned by call to ex_get_ids().\n", sset, ids[sset]); } ssets[sset].initialize(file_id, ids[sset]); } } // Edge & Face blocks... if (edge_blocks) { delete[] edge_blocks; } edge_blocks = nullptr; if (num_edge_blocks > 0) { edge_blocks = new Edge_Block[num_edge_blocks]; SMART_ASSERT(edge_blocks != nullptr); std::vector ids(num_edge_blocks); err = ex_get_ids(file_id, EX_EDGE_BLOCK, ids.data()); if (err < 0) { Error("Failed to get edgeblock ids! Aborting...\n"); } for (size_t edge_block = 0; edge_block < num_edge_blocks; ++edge_block) { if (ids[edge_block] <= EX_INVALID_ID) { fmt::print(stderr, "EXODIFF WARNING: Edgeblock Id " "for edgeblock index {} is {}" " which is negative. This was returned by call to ex_get_ids().\n", edge_block, ids[edge_block]); } edge_blocks[edge_block].initialize(file_id, ids[edge_block]); } } if (face_blocks) { delete[] face_blocks; } face_blocks = nullptr; if (num_face_blocks > 0) { face_blocks = new Face_Block[num_face_blocks]; SMART_ASSERT(face_blocks != nullptr); std::vector ids(num_face_blocks); err = ex_get_ids(file_id, EX_FACE_BLOCK, ids.data()); if (err < 0) { Error("Failed to get faceblock ids! Aborting...\n"); } for (size_t face_block = 0; face_block < num_face_blocks; ++face_block) { if (ids[face_block] <= EX_INVALID_ID) { fmt::print(stderr, "EXODIFF WARNING: Faceblock Id " "for faceblock index {} is {}" " which is negative. This was returned by call to ex_get_ids().\n", face_block, ids[face_block]); } face_blocks[face_block].initialize(file_id, ids[face_block]); } } // ************** RESULTS info *************** // int num_global_vars, num_nodal_vars, num_elmt_vars, num_ns_vars, num_ss_vars, num_edge_vars, num_face_vars; err = ex_get_variable_param(file_id, EX_GLOBAL, &num_global_vars); if (err < 0) { Error("Failed to get number of global variables! Aborting...\n"); } err = ex_get_variable_param(file_id, EX_NODAL, &num_nodal_vars); if (err < 0) { Error("Failed to get number of nodal variables! Aborting...\n"); } err = ex_get_variable_param(file_id, EX_ELEM_BLOCK, &num_elmt_vars); if (err < 0) { Error("Failed to get number of element variables! Aborting...\n"); } err = ex_get_variable_param(file_id, EX_NODE_SET, &num_ns_vars); if (err < 0) { Error("Failed to get number of nodeset variables! Aborting...\n"); } err = ex_get_variable_param(file_id, EX_SIDE_SET, &num_ss_vars); if (err < 0) { Error("Failed to get number of sideset variables! Aborting...\n"); } err = ex_get_variable_param(file_id, EX_EDGE_BLOCK, &num_edge_vars); if (err < 0) { Error("Failed to get number of edgeblock variables! Aborting...\n"); } err = ex_get_variable_param(file_id, EX_FACE_BLOCK, &num_face_vars); if (err < 0) { Error("Failed to get number of faceblock variables! Aborting...\n"); } if (num_global_vars < 0 || num_nodal_vars < 0 || num_elmt_vars < 0 || num_ns_vars < 0 || num_ss_vars < 0 || num_edge_vars < 0 || num_face_vars < 0) { Error(fmt::format("Data appears corrupt for" " number of variables !\n" "\tnum global vars = {}\n" "\tnum nodal vars = {}\n" "\tnum element vars = {}\n" "\tnum nodeset vars = {}\n" "\tnum sideset vars = {}\n" "\tnum edgeblock vars = {}\n" "\tnum faceblock vars = {}\n" " ... Aborting...\n", num_global_vars, num_nodal_vars, num_elmt_vars, num_ns_vars, num_ss_vars, num_edge_vars, num_face_vars)); } read_vars(file_id, EX_GLOBAL, "Global", num_global_vars, global_vars); read_vars(file_id, EX_NODAL, "Nodal", num_nodal_vars, nodal_vars); read_vars(file_id, EX_ELEM_BLOCK, "Element", num_elmt_vars, elmt_vars); read_vars(file_id, EX_NODE_SET, "Nodeset", num_ns_vars, ns_vars); read_vars(file_id, EX_SIDE_SET, "Sideset", num_ss_vars, ss_vars); read_vars(file_id, EX_EDGE_BLOCK, "Edgeblock", num_edge_vars, eb_vars); read_vars(file_id, EX_FACE_BLOCK, "Faceblock", num_face_vars, fb_vars); // Times: num_times = ex_inquire_int(file_id, EX_INQ_TIME); if (num_times < 0) { Error(fmt::format("Number of time steps came back negative ({})! Aborting...\n", num_times)); } if ((num_global_vars > 0 || num_nodal_vars > 0 || num_elmt_vars > 0 || num_ns_vars > 0 || num_ss_vars > 0 || num_edge_vars > 0 || num_face_vars > 0) && num_times == 0) { Warning("Consistency error -- The database contains transient variables, but no " "timesteps!\n"); } if (num_times) { times = new double[num_times]; SMART_ASSERT(times != nullptr); ex_get_all_times(file_id, times); if (time_scale != 1.0 || time_offset != 0.0) { for (int i = 0; i < num_times; i++) { times[i] = time_scale * times[i] + time_offset; } } } if (num_nodal_vars != 0) { if (num_times == 0) { Warning(fmt::format("Consistency error--The database contains {}" " nodal variables, but there are no time steps defined.\n", num_nodal_vars)); } if (num_times) { results = new double *[num_nodal_vars]; for (int i = 0; i < num_nodal_vars; ++i) { results[i] = nullptr; } } } } // End of EXODIFF namespace { void read_vars(int file_id, EXOTYPE flag, const char *type, int num_vars, std::vector &varlist) { if (num_vars != 0) { int name_size = ex_inquire_int(file_id, EX_INQ_MAX_READ_NAME_LENGTH); char **varnames = get_name_array(num_vars, name_size); int err = ex_get_variable_names(file_id, flag, num_vars, varnames); if (err < 0) { Error(fmt::format("Failed to get {} variable names! Aborting...\n", type)); } else if (err > 0 && !interFace.quiet_flag) { fmt::print( stderr, "exodiff: WARNING: Exodus issued warning \"{}\" on call to ex_get_var_names()!\n", err); } for (int vg = 0; vg < num_vars; ++vg) { SMART_ASSERT(varnames[vg] != nullptr); if (std::strlen(varnames[vg]) == 0 || static_cast(std::strlen(varnames[vg])) > name_size) { std::ostringstream out; fmt::print(out, "exodiff: ERROR: {} variable names appear corrupt\n" " A length is 0 or greater than name_size({})\n" " Here are the names that I received from" " a call to ex_get_var_names(...):\n", type, name_size); for (int k = 1; k <= num_vars; ++k) { fmt::print(out, "\t\t{}) \"{}\"\n", k, varnames[k - 1]); } fmt::print(out, " Aborting...\n"); Error(out); } std::string n(varnames[vg]); chop_whitespace(n); varlist.push_back(n); } free_name_array(varnames, num_vars); } } } // namespace template class ExoII_Read; template class ExoII_Read;