/* * 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 // for Block, Mesh #include // for Internals, Redefine #include // for sort #include #include // for size_t #include // for int64_t #include // for exit, EXIT_FAILURE #include // for strlen, memset #include #include // for SMART_ASSERT #include // for string, basic_string #include // for vector #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \ defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__) #include #endif extern "C" { #define NO_NETCDF_2 #include #include #include } // Explicit Initialization of the functions used... namespace Excn { template int Internals::write_meta_data(const Mesh &mesh, const std::vector &blocks, const std::vector> &nodesets, const std::vector> &sidesets, const std::vector> &edgeblock, const std::vector> &faceblock, const CommunicationMetaData &comm); template bool Internals::check_meta_data(const Mesh &mesh, const std::vector &blocks, const std::vector> &nodesets, const std::vector> &sidesets, const std::vector> &edgeblock, const std::vector> &faceblock, const CommunicationMetaData &comm); template int Internals::write_meta_data(const Mesh &mesh, const std::vector &blocks, const std::vector> &nodesets, const std::vector> &sidesets, const std::vector> &edgeblock, const std::vector> &faceblock, const CommunicationMetaData &comm); template bool Internals::check_meta_data( const Mesh &mesh, const std::vector &blocks, const std::vector> &nodesets, const std::vector> &sidesets, const std::vector> &edgeblock, const std::vector> &faceblock, const CommunicationMetaData &comm); } // namespace Excn namespace { bool lessOffset(const Excn::Block &b1, const Excn::Block &b2) { return b1.offset_ < b2.offset_; } nc_type get_type(int exoid, unsigned int type) { if ((ex_int64_status(exoid) & type) != 0U) { return NC_INT64; } return NC_INT; } int define_netcdf_vars(int exoid, const char *type, size_t count, const char *dim_num, const char *stat_var, const char *id_var, const char *name_var); template int put_array(int exoid, const char *var_type, const std::vector &array); int put_id_array(int exoid, const char *var_type, const std::vector &ids); int define_coordinate_vars(int exodusFilePtr, int64_t nodes, int node_dim, int dimension, int dim_dim, int str_dim); } // namespace bool Excn::is_path_absolute(const std::string &path) { #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \ defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__) return path[0] == '\\' || path[1] == ':'; #else return path[0] == '/'; #endif } Excn::Redefine::Redefine(int exoid) : exodusFilePtr(exoid) { // Enter define mode... int status = nc_redef(exodusFilePtr); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); std::string errmsg; errmsg = fmt::format("Error: failed to put file id {} into define mode", exodusFilePtr); ex_err_fn(exoid, __func__, errmsg.c_str(), status); exit(EXIT_FAILURE); } } Excn::Redefine::~Redefine() { try { int status = nc_enddef(exodusFilePtr); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); std::string errmsg; errmsg = fmt::format("Error: failed to complete variable definitions in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); exit(EXIT_FAILURE); } } catch (...) { } } template int Excn::Internals::write_meta_data(const Mesh &mesh, const std::vector &blocks, const std::vector> &nodesets, const std::vector> &sidesets, const std::vector> &edgeblocks, const std::vector> &faceblocks, const CommunicationMetaData &comm) { SMART_ASSERT((int)blocks.size() == mesh.blockCount); SMART_ASSERT((int)nodesets.size() == mesh.nodesetCount); SMART_ASSERT((int)sidesets.size() == mesh.sidesetCount); SMART_ASSERT((int)edgeblocks.size() == mesh.edgeBlockCount); SMART_ASSERT((int)faceblocks.size() == mesh.faceBlockCount); // May need to reorder the element blocks based on the 'offset_' // member. An element block contains the elements from 'offset_+1' // to 'offset_+elementCount'. Typically, this is the order that // they appear in the 'blocks' array, but not always... // // This is a very hard error to track down, so we just copy the // 'blocks' array to a new array and sort it on the 'offset_' // member... // // All block-related calls after these meta-data calls are based on // the block id and not the block order, so we don't need to fix // them. for (size_t i = 0; i < blocks.size(); i++) { const_cast(blocks[i]).position_ = i; } // Check whether current order is consistent. The problem with just // sorting the data is that if a subset of the entire model is being // joined, there may be zero-length element blocks. These blocks // have an offset of zero since there is no "lowest id" to get the // offset from. // // If all that is wanted is a single subset of the entire model, it // doesn't matter if the blocks are reordered due to the zero // offsets; however, if the user then later joins multiple subsets // together, there will be issues of block ordering mismatches. // // So, to avoid sorting the data into incorrect order, we check // whether the data are consistent before sorting and if so, don't // do the sort. Concsistent means that all blocks that have a // nonzero element count are in the correct order. int64_t last_offset = 0; bool order_ok = true; for (const auto &block : blocks) { if (block.elementCount > 0) { if (block.offset_ < last_offset) { order_ok = false; break; } last_offset = block.offset_; } } std::vector sorted_blocks(blocks); if (!order_ok) { std::sort(sorted_blocks.begin(), sorted_blocks.end(), lessOffset); // Now, update the position_ field based on the sorted order. for (size_t i = 0; i < blocks.size(); i++) { int orig_position = sorted_blocks[i].position_; const_cast(blocks[orig_position]).position_ = i; SMART_ASSERT(blocks[orig_position].id == sorted_blocks[i].id); } } int ierr; { Excn::Redefine the_database(exodusFilePtr); ierr = put_metadata(mesh, comm); if (ierr != EX_NOERR) { return ierr; } ierr = put_metadata(sorted_blocks); if (ierr != EX_NOERR) { return ierr; } ierr = put_metadata(nodesets); if (ierr != EX_NOERR) { return ierr; } ierr = put_metadata(sidesets); if (ierr != EX_NOERR) { return ierr; } ierr = put_metadata(edgeblocks); if (ierr != EX_NOERR) { return ierr; } ierr = put_metadata(faceblocks); if (ierr != EX_NOERR) { return ierr; } } // NON-Define mode output... ierr = put_non_define_data(mesh, comm); if (ierr != EX_NOERR) { return ierr; } ierr = put_non_define_data(sorted_blocks); if (ierr != EX_NOERR) { return ierr; } ierr = put_non_define_data(nodesets); if (ierr != EX_NOERR) { return ierr; } ierr = put_non_define_data(sidesets); if (ierr != EX_NOERR) { return ierr; } ierr = put_non_define_data(edgeblocks); if (ierr != EX_NOERR) { return ierr; } ierr = put_non_define_data(faceblocks); if (ierr != EX_NOERR) { return ierr; } // For now, put entity names using the ExodusII api... { int max_entity = mesh.blockCount; if (mesh.nodesetCount > max_entity) { max_entity = mesh.nodesetCount; } if (mesh.sidesetCount > max_entity) { max_entity = mesh.sidesetCount; } if (mesh.edgeBlockCount > max_entity) { max_entity = mesh.edgeBlockCount; } if (mesh.faceBlockCount > max_entity) { max_entity = mesh.faceBlockCount; } if (mesh.blockCount > 0) { for (int i = 0; i < mesh.blockCount; i++) { if (blocks[i].attributeCount > max_entity) { max_entity = blocks[i].attributeCount; } } } size_t name_size = ex_inquire_int(exodusFilePtr, EX_INQ_MAX_READ_NAME_LENGTH); auto names = new char *[max_entity]; for (int i = 0; i < max_entity; i++) { names[i] = new char[name_size + 1]; } if (mesh.blockCount > 0) { for (int i = 0; i < mesh.blockCount; i++) { copy_string(names[i], sorted_blocks[i].name_, name_size + 1); } ex_put_names(exodusFilePtr, EX_ELEM_BLOCK, names); for (int i = 0; i < mesh.blockCount; i++) { if (blocks[i].attributeCount > 0) { SMART_ASSERT((size_t)blocks[i].attributeCount == blocks[i].attributeNames.size()); for (int j = 0; j < blocks[i].attributeCount; j++) { std::memset(names[j], '\0', name_size + 1); if (!blocks[i].attributeNames[j].empty()) { copy_string(names[j], blocks[i].attributeNames[j], name_size + 1); } } ierr = ex_put_attr_names(exodusFilePtr, EX_ELEM_BLOCK, blocks[i].id, names); SMART_ASSERT(ierr == 0); } } } if (mesh.nodesetCount > 0) { for (int i = 0; i < mesh.nodesetCount; i++) { copy_string(names[i], nodesets[i].name_, name_size + 1); } ex_put_names(exodusFilePtr, EX_NODE_SET, names); } if (mesh.sidesetCount > 0) { for (int i = 0; i < mesh.sidesetCount; i++) { copy_string(names[i], sidesets[i].name_, name_size + 1); } ex_put_names(exodusFilePtr, EX_SIDE_SET, names); } if (mesh.edgeBlockCount > 0) { for (int i = 0; i < mesh.edgeBlockCount; i++) { copy_string(names[i], edgeblocks[i].name_, name_size + 1); } ex_put_names(exodusFilePtr, EX_EDGE_BLOCK, names); } if (mesh.faceBlockCount > 0) { for (int i = 0; i < mesh.faceBlockCount; i++) { copy_string(names[i], faceblocks[i].name_, name_size + 1); } ex_put_names(exodusFilePtr, EX_FACE_BLOCK, names); } for (int i = 0; i < max_entity; i++) { delete[] names[i]; } delete[] names; } ex_update(exodusFilePtr); return EX_NOERR; } template bool Excn::Internals::check_meta_data(const Mesh &mesh, const std::vector & /*unused*/, const std::vector> & /*unused*/, const std::vector> & /*unused*/, const std::vector> & /*unused*/, const std::vector> & /*unused*/, const CommunicationMetaData & /*unused*/) { ex_init_params init_data{}; ex_get_init_ext(exodusFilePtr, &init_data); bool matches = true; if (mesh.dimensionality != init_data.num_dim) { fmt::print(stderr, "ERROR: (EPU) original mesh dimensionality ({}) does not match current " "dimensionality ({})\n", mesh.dimensionality, init_data.num_dim); matches = false; } if (mesh.nodeCount != init_data.num_nodes) { fmt::print( stderr, "ERROR: (EPU) original mesh node count ({}) does not match current node count ({})\n", mesh.nodeCount, init_data.num_nodes); matches = false; } if (mesh.elementCount != init_data.num_elem) { fmt::print( stderr, "ERROR: (EPU) original mesh element count ({}) does not match current element count ({})\n", mesh.elementCount, init_data.num_elem); matches = false; } if (mesh.blockCount != init_data.num_elem_blk) { fmt::print(stderr, "ERROR: (EPU) original mesh element block count ({}) does not match current element " "block count ({})\n", mesh.blockCount, init_data.num_elem_blk); matches = false; } if (mesh.nodesetCount != init_data.num_node_sets) { fmt::print( stderr, "ERROR: (EPU) original mesh nodeset count ({}) does not match current nodeset count ({})\n", mesh.nodesetCount, init_data.num_node_sets); matches = false; } if (mesh.sidesetCount != init_data.num_side_sets) { fmt::print( stderr, "ERROR: (EPU) original mesh sideset count ({}) does not match current sideset count ({})\n", mesh.sidesetCount, init_data.num_side_sets); matches = false; } if (mesh.edgeBlockCount != init_data.num_edge_blk) { fmt::print(stderr, "ERROR: (EPU) original mesh edgeblock count ({}) does not match current edgeblock " "count ({})\n", mesh.edgeBlockCount, init_data.num_edge_blk); matches = false; } if (mesh.faceBlockCount != init_data.num_face_blk) { fmt::print(stderr, "ERROR: (EPU) original mesh faceblock count ({}) does not match current faceblock " "count ({})\n", mesh.faceBlockCount, init_data.num_face_blk); matches = false; } return matches; } template int Excn::Internals::put_metadata(const Mesh &mesh, const CommunicationMetaData & /*unused*/) { int numdimdim = 0; int timedim = 0; int numnoddim = 0; int namestrdim = 0; int map_type = get_type(exodusFilePtr, EX_MAPS_INT64_DB); std::string errmsg; // define some attributes... int status = nc_put_att_text(exodusFilePtr, NC_GLOBAL, ATT_TITLE, mesh.title.length() + 1, mesh.title.c_str()); if (status != NC_NOERR) { errmsg = fmt::format("Error: failed to define title attribute to file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } // For use later to help readers know how much memory to allocate // for name storage, we define an attribute containing the maximum // size of any name. { int current_len = 0; status = nc_put_att_int(exodusFilePtr, NC_GLOBAL, ATT_MAX_NAME_LENGTH, NC_INT, 1, ¤t_len); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define ATT_MAX_NAME_LENGTH attribute to file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } } // create name string length dimension if (maximumNameLength < 32) { maximumNameLength = 32; } status = nc_def_dim(exodusFilePtr, DIM_STR_NAME, maximumNameLength + 1, &namestrdim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define name string length in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } // ...and some dimensions.. status = nc_def_dim(exodusFilePtr, DIM_NUM_DIM, mesh.dimensionality, &numdimdim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define number of dimensions in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } if ((status = nc_def_dim(exodusFilePtr, DIM_TIME, NC_UNLIMITED, &timedim)) != NC_NOERR) { errmsg = fmt::format("Error: failed to define time dimension in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } { int dim[1]; int varid = 0; dim[0] = timedim; if ((status = nc_def_var(exodusFilePtr, VAR_WHOLE_TIME, nc_flt_code(exodusFilePtr), 1, dim, &varid)) != NC_NOERR) { errmsg = fmt::format("Error: failed to define whole time step variable in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } struct ex__file_item *file = ex__find_file_item(exodusFilePtr); if (file) { file->time_varid = varid; } ex__compress_variable(exodusFilePtr, varid, -2); /* don't compress, but do set collective io */ } if (mesh.nodeCount > 0) { status = nc_def_dim(exodusFilePtr, DIM_NUM_NODES, mesh.nodeCount, &numnoddim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define number of nodes in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } // Define the node map here to avoid a later redefine call if (mesh.needNodeMap) { int dims[1]; int varid = 0; dims[0] = numnoddim; status = nc_def_var(exodusFilePtr, VAR_NODE_NUM_MAP, map_type, 1, dims, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: node numbering map already exists in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to create node numbering map array in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 1); } } if (mesh.elementCount > 0) { int numelemdim = 0; status = nc_def_dim(exodusFilePtr, DIM_NUM_ELEM, mesh.elementCount, &numelemdim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define number of elements in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } // Define the element map here to avoid a later redefine call if (mesh.needElementMap) { int dims[1]; dims[0] = numelemdim; int varid = 0; status = nc_def_var(exodusFilePtr, VAR_ELEM_NUM_MAP, map_type, 1, dims, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: element numbering map already exists in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to create element numbering map in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 1); } } if (mesh.blockCount > 0) { status = define_netcdf_vars(exodusFilePtr, "element block", mesh.blockCount, DIM_NUM_EL_BLK, VAR_STAT_EL_BLK, VAR_ID_EL_BLK, VAR_NAME_EL_BLK); if (status != EX_NOERR) { return EX_FATAL; } } // node set id array: if (mesh.nodesetCount > 0) { status = define_netcdf_vars(exodusFilePtr, "node set", mesh.nodesetCount, DIM_NUM_NS, VAR_NS_STAT, VAR_NS_IDS, VAR_NAME_NS); if (status != EX_NOERR) { return EX_FATAL; } } // side set id array: if (mesh.sidesetCount > 0) { status = define_netcdf_vars(exodusFilePtr, "side set", mesh.sidesetCount, DIM_NUM_SS, VAR_SS_STAT, VAR_SS_IDS, VAR_NAME_SS); if (status != EX_NOERR) { return EX_FATAL; } } // edge block id array: if (mesh.edgeBlockCount > 0) { status = define_netcdf_vars(exodusFilePtr, "edge block", mesh.edgeBlockCount, DIM_NUM_ED_BLK, VAR_STAT_ED_BLK, VAR_ID_ED_BLK, VAR_NAME_ED_BLK); if (status != EX_NOERR) { return EX_FATAL; } } // face block id array: if (mesh.faceBlockCount > 0) { status = define_netcdf_vars(exodusFilePtr, "face block", mesh.faceBlockCount, DIM_NUM_FA_BLK, VAR_STAT_FA_BLK, VAR_ID_FA_BLK, VAR_NAME_FA_BLK); if (status != EX_NOERR) { return EX_FATAL; } } status = define_coordinate_vars(exodusFilePtr, mesh.nodeCount, numnoddim, mesh.dimensionality, numdimdim, namestrdim); if (status != EX_NOERR) { return EX_FATAL; } return EX_NOERR; } template int Excn::Internals::put_metadata(const std::vector &blocks) { std::string errmsg; int dims[2]; int bulk_type = get_type(exodusFilePtr, EX_BULK_INT64_DB); int status = 0; // clear error code if (blocks.empty()) { return EX_NOERR; } // Get number of element blocks defined for this file int dimid; size_t num_elem_blk = 0; status = nc_inq_dimid(exodusFilePtr, DIM_NUM_EL_BLK, &dimid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: no element blocks defined in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } int namestrdim; status = nc_inq_dimid(exodusFilePtr, DIM_STR_NAME, &namestrdim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to get name string length in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } status = nc_inq_dimlen(exodusFilePtr, dimid, &num_elem_blk); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to get number of element blocks in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } SMART_ASSERT(blocks.size() == num_elem_blk); // Iterate over element blocks ... for (size_t iblk = 0; iblk < num_elem_blk; iblk++) { ex__inc_file_item(exodusFilePtr, ex__get_counter_list(EX_ELEM_BLOCK)); if (blocks[iblk].elementCount == 0) { continue; } // define some dimensions and variables int numelbdim; status = nc_def_dim(exodusFilePtr, DIM_NUM_EL_IN_BLK(iblk + 1), blocks[iblk].elementCount, &numelbdim); if (status != NC_NOERR) { if (status == NC_ENAMEINUSE) { // duplicate entry ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: element block {} already defined in file id {}", blocks[iblk].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define number of elements/block for block {} file id {}", blocks[iblk].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } int nelnoddim; status = nc_def_dim(exodusFilePtr, DIM_NUM_NOD_PER_EL(iblk + 1), blocks[iblk].nodesPerElement, &nelnoddim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define number of nodes/element for block {} in file id {}", blocks[iblk].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } // element attribute array if (blocks[iblk].attributeCount > 0) { int numattrdim; status = nc_def_dim(exodusFilePtr, DIM_NUM_ATT_IN_BLK(iblk + 1), blocks[iblk].attributeCount, &numattrdim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define number of attributes in block {} in file id {}", blocks[iblk].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } dims[0] = numelbdim; dims[1] = numattrdim; int varid = 0; status = nc_def_var(exodusFilePtr, VAR_ATTRIB(iblk + 1), nc_flt_code(exodusFilePtr), 2, dims, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define attributes for element block {} in file id {}", blocks[iblk].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 2); // Attribute name array... dims[0] = numattrdim; dims[1] = namestrdim; status = nc_def_var(exodusFilePtr, VAR_NAME_ATTRIB(iblk + 1), NC_CHAR, 2, dims, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format( "Error: failed to define attribute name array for element block {} in file id {}", blocks[iblk].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } } // element connectivity array dims[0] = numelbdim; dims[1] = nelnoddim; int connid; status = nc_def_var(exodusFilePtr, VAR_CONN(iblk + 1), bulk_type, 2, dims, &connid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to create connectivity array for block {} in file id {}", blocks[iblk].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } ex__compress_variable(exodusFilePtr, connid, 1); // store element type as attribute of connectivity variable status = nc_put_att_text(exodusFilePtr, connid, ATT_NAME_ELB, static_cast(std::strlen(blocks[iblk].elType)) + 1, blocks[iblk].elType); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to store element type name {} in file id {}", blocks[iblk].elType, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } } return EX_NOERR; } template int Excn::Internals::put_non_define_data(const Mesh & /*unused*/, const CommunicationMetaData & /*unused*/) { return EX_NOERR; } template int Excn::Internals::put_non_define_data(const std::vector &blocks) { int num_elem_blk = blocks.size(); // Verified via SMART_ASSERT earlier... if (num_elem_blk > 0) { // first get id of element block ids array variable std::vector elem_blk_id(num_elem_blk); for (int iblk = 0; iblk < num_elem_blk; iblk++) { elem_blk_id[iblk] = blocks[iblk].id; } if (put_id_array(exodusFilePtr, VAR_ID_EL_BLK, elem_blk_id) != NC_NOERR) { return EX_FATAL; } // Now, write the element block status array std::vector elem_blk_status(num_elem_blk); for (int iblk = 0; iblk < num_elem_blk; iblk++) { elem_blk_status[iblk] = blocks[iblk].elementCount > 0 ? 1 : 0; } if (put_array(exodusFilePtr, VAR_STAT_EL_BLK, elem_blk_status) != NC_NOERR) { return EX_FATAL; } } return EX_NOERR; } // ======================================================================== template int Excn::Internals::put_metadata(const std::vector> &nodesets) { if (nodesets.empty()) { return EX_NOERR; } std::string errmsg; int dims[2]; int bulk_type = get_type(exodusFilePtr, EX_BULK_INT64_DB); int status = 0; // clear error code // Get number of node sets defined for this file int dimid; status = nc_inq_dimid(exodusFilePtr, DIM_NUM_NS, &dimid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_EBADDIM) { errmsg = fmt::format("Error: no node sets defined for file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to locate node sets defined in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } // inquire how many node sets are to be stored int num_node_sets = ex_inquire_int(exodusFilePtr, EX_INQ_NODE_SETS); SMART_ASSERT(static_cast(nodesets.size()) == num_node_sets); for (int i = 0; i < num_node_sets; i++) { // NOTE: ex__inc_file_item is used to find the number of node sets // for a specific file and returns that value incremented. int cur_num_node_sets = (int)ex__inc_file_item(exodusFilePtr, ex__get_counter_list(EX_NODE_SET)); if (nodesets[i].nodeCount == 0) { continue; } status = nc_def_dim(exodusFilePtr, DIM_NUM_NOD_NS(cur_num_node_sets + 1), nodesets[i].nodeCount, &dimid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: node set {} already defined in file id {}", nodesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to define number of nodes for set {} in file id {}", nodesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } // define variable to store node set node list here instead of in expns dims[0] = dimid; int varid = 0; status = nc_def_var(exodusFilePtr, VAR_NODE_NS(cur_num_node_sets + 1), bulk_type, 1, dims, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: node set {} node list already defined in file id {}", nodesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to create node set {} node list in file id {}", nodesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 1); // Create variable for distribution factors if required if (nodesets[i].dfCount > 0) { // num_dist_per_set should equal num_nodes_per_set if (nodesets[i].dfCount != nodesets[i].nodeCount) { status = EX_FATAL; ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: # dist fact ({}) not equal to # nodes ({}) " "in node set {} file id {}", nodesets[i].dfCount, nodesets[i].nodeCount, nodesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } // create variable for distribution factors status = nc_def_var(exodusFilePtr, VAR_FACT_NS(cur_num_node_sets + 1), nc_flt_code(exodusFilePtr), 1, dims, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: node set {} dist factors already exist in file id {}", nodesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to create node set {} dist factors in file id {}", nodesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 2); } } return EX_NOERR; } template int Excn::Internals::put_non_define_data(const std::vector> &nodesets) { if (nodesets.empty()) { return EX_NOERR; } // Output nodeset ids... size_t num_nodesets = nodesets.size(); std::vector nodeset_id(num_nodesets); for (size_t i = 0; i < num_nodesets; i++) { nodeset_id[i] = nodesets[i].id; } if (put_id_array(exodusFilePtr, VAR_NS_IDS, nodeset_id) != NC_NOERR) { return EX_FATAL; } // Now, write the status array std::vector status(num_nodesets); for (size_t i = 0; i < num_nodesets; i++) { status[i] = nodesets[i].nodeCount > 0 ? 1 : 0; } if (put_array(exodusFilePtr, VAR_NS_STAT, status) != NC_NOERR) { return EX_FATAL; } return EX_NOERR; } // ======================================================================== template int Excn::Internals::put_metadata(const std::vector> &sidesets) { if (sidesets.empty()) { return EX_NOERR; } std::string errmsg; int dims[2]; int bulk_type = get_type(exodusFilePtr, EX_BULK_INT64_DB); int status = 0; // clear error code // Get number of side sets defined for this file int dimid; status = nc_inq_dimid(exodusFilePtr, DIM_NUM_SS, &dimid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_EBADDIM) { errmsg = fmt::format("Error: no side sets defined for file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to locate side sets defined in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } size_t num_side_sets = ex_inquire_int(exodusFilePtr, EX_INQ_SIDE_SETS); SMART_ASSERT(sidesets.size() == num_side_sets); for (size_t i = 0; i < num_side_sets; i++) { // NOTE: ex__inc_file_item is used to find the number of side sets // for a specific file and returns that value incremented. int cur_num_side_sets = (int)ex__inc_file_item(exodusFilePtr, ex__get_counter_list(EX_SIDE_SET)); if (sidesets[i].sideCount == 0) { continue; } status = nc_def_dim(exodusFilePtr, DIM_NUM_SIDE_SS(cur_num_side_sets + 1), sidesets[i].sideCount, &dimid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: side set {} already defined in file id {}", sidesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to define number of sides for set {} in file id {}", sidesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } dims[0] = dimid; int varid = 0; status = nc_def_var(exodusFilePtr, VAR_ELEM_SS(cur_num_side_sets + 1), bulk_type, 1, dims, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: side set {} element list already defined in file id {}", sidesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to create side set {} element list in file id {}", sidesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 1); // create side list variable for side set status = nc_def_var(exodusFilePtr, VAR_SIDE_SS(cur_num_side_sets + 1), bulk_type, 1, dims, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: side list already exists for side set {} in file id {}", sidesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to create side list for side set {} in file id {}", sidesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 1); // Create variable for distribution factors if required if (sidesets[i].dfCount > 0) { status = nc_def_dim(exodusFilePtr, DIM_NUM_DF_SS(cur_num_side_sets + 1), sidesets[i].dfCount, &dimid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: side set df count {} already defined in file id {}", sidesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to define side set df count for set {} in file id {}", sidesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } // create distribution factor list variable for side set dims[0] = dimid; status = nc_def_var(exodusFilePtr, VAR_FACT_SS(cur_num_side_sets + 1), nc_flt_code(exodusFilePtr), 1, dims, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: dist factor list already exists for side set {} in file id {}", sidesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to create dist factor list for side set {} in file id {}", sidesets[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 2); } } return EX_NOERR; } template int Excn::Internals::put_non_define_data(const std::vector> &sidesets) { if (sidesets.empty()) { return EX_NOERR; } // Output sideset ids... int num_sidesets = (int)sidesets.size(); std::vector sideset_id(num_sidesets); for (int i = 0; i < num_sidesets; i++) { sideset_id[i] = sidesets[i].id; } if (put_id_array(exodusFilePtr, VAR_SS_IDS, sideset_id) != NC_NOERR) { return EX_FATAL; } // Now, write the status array std::vector status(num_sidesets); for (int i = 0; i < num_sidesets; i++) { status[i] = sidesets[i].sideCount > 0 ? 1 : 0; } if (put_array(exodusFilePtr, VAR_SS_STAT, status) != NC_NOERR) { return EX_FATAL; } return EX_NOERR; } // ======================================================================== template int Excn::Internals::put_metadata(const std::vector> &edgeblocks) { if (edgeblocks.empty()) { return EX_NOERR; } std::string errmsg; int dims[2]; int bulk_type = get_type(exodusFilePtr, EX_BULK_INT64_DB); int status = 0; // clear error code // Get number of edge blocks defined for this file int dimid; status = nc_inq_dimid(exodusFilePtr, DIM_NUM_ED_BLK, &dimid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_EBADDIM) { errmsg = fmt::format("Error: no edge blocks defined for file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to locate edge blocks defined in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } size_t num_edge_blocks = ex_inquire_int(exodusFilePtr, EX_INQ_EDGE_BLK); SMART_ASSERT(edgeblocks.size() == num_edge_blocks); for (size_t i = 0; i < num_edge_blocks; i++) { // NOTE: ex__inc_file_item is used to find the number of edge blocks // for a specific file and returns that value incremented. int cur_num_edge_blocks = (int)ex__inc_file_item(exodusFilePtr, ex__get_counter_list(EX_EDGE_BLOCK)); if (edgeblocks[i].edgeCount == 0) { continue; } int num_edges_in_edgeblock_dim; status = nc_def_dim(exodusFilePtr, DIM_NUM_ED_IN_EBLK(cur_num_edge_blocks + 1), edgeblocks[i].edgeCount, &num_edges_in_edgeblock_dim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: edge block {} already defined in file id {}", edgeblocks[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to define number of edges for edge block {} in file id {}", edgeblocks[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } int num_nodes_per_edge_dim; status = nc_def_dim(exodusFilePtr, DIM_NUM_NOD_PER_ED(cur_num_edge_blocks + 1), edgeblocks[i].nodesPerEdge, &num_nodes_per_edge_dim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define number of nodes/edge for block {} in file id {}", edgeblocks[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } // element connectivity array dims[0] = num_edges_in_edgeblock_dim; dims[1] = num_nodes_per_edge_dim; int connid; status = nc_def_var(exodusFilePtr, VAR_EBCONN(cur_num_edge_blocks + 1), bulk_type, 2, dims, &connid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to create connectivity array for edge block {} in file id {}", edgeblocks[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } ex__compress_variable(exodusFilePtr, connid, 1); // store edge type as attribute of connectivity variable status = nc_put_att_text(exodusFilePtr, connid, ATT_NAME_ELB, static_cast(std::strlen(edgeblocks[i].elType)) + 1, edgeblocks[i].elType); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to store edge type name {} in file id {}", edgeblocks[i].elType, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } } return EX_NOERR; } template int Excn::Internals::put_non_define_data(const std::vector> &edgeblocks) { if (edgeblocks.empty()) { return EX_NOERR; } // Output edgeblock ids... int num_edgeblocks = (int)edgeblocks.size(); std::vector edgeblock_id(num_edgeblocks); for (int i = 0; i < num_edgeblocks; i++) { edgeblock_id[i] = edgeblocks[i].id; } if (put_id_array(exodusFilePtr, VAR_ID_ED_BLK, edgeblock_id) != NC_NOERR) { return EX_FATAL; } // Now, write the status array std::vector status(num_edgeblocks); for (int i = 0; i < num_edgeblocks; i++) { status[i] = edgeblocks[i].edgeCount > 0 ? 1 : 0; } if (put_array(exodusFilePtr, VAR_STAT_ED_BLK, status) != NC_NOERR) { return EX_FATAL; } return EX_NOERR; } // ======================================================================== template int Excn::Internals::put_metadata(const std::vector> &faceblocks) { if (faceblocks.empty()) { return EX_NOERR; } std::string errmsg; int dims[2]; int bulk_type = get_type(exodusFilePtr, EX_BULK_INT64_DB); int status = 0; // clear error code // Get number of face blocks defined for this file int dimid; status = nc_inq_dimid(exodusFilePtr, DIM_NUM_FA_BLK, &dimid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_EBADDIM) { errmsg = fmt::format("Error: no face blocks defined for file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to locate face blocks defined in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } size_t num_face_blocks = ex_inquire_int(exodusFilePtr, EX_INQ_FACE_BLK); SMART_ASSERT(faceblocks.size() == num_face_blocks); for (size_t i = 0; i < num_face_blocks; i++) { // NOTE: ex__inc_file_item is used to find the number of face blocks // for a specific file and returns that value incremented. int cur_num_face_blocks = (int)ex__inc_file_item(exodusFilePtr, ex__get_counter_list(EX_FACE_BLOCK)); if (faceblocks[i].faceCount == 0) { continue; } int num_faces_in_faceblock_dim; status = nc_def_dim(exodusFilePtr, DIM_NUM_FA_IN_FBLK(cur_num_face_blocks + 1), faceblocks[i].faceCount, &num_faces_in_faceblock_dim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); if (status == NC_ENAMEINUSE) { errmsg = fmt::format("Error: face block {} already defined in file id {}", faceblocks[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } else { errmsg = fmt::format("Error: failed to define number of faces for face block {} in file id {}", faceblocks[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); } return EX_FATAL; } int num_nodes_per_face_dim; status = nc_def_dim(exodusFilePtr, DIM_NUM_NOD_PER_FA(cur_num_face_blocks + 1), faceblocks[i].nodesPerFace, &num_nodes_per_face_dim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define number of nodes/face for block {} in file id {}", faceblocks[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } // element connectivity array dims[0] = num_faces_in_faceblock_dim; dims[1] = num_nodes_per_face_dim; int connid; status = nc_def_var(exodusFilePtr, VAR_FBCONN(cur_num_face_blocks + 1), bulk_type, 2, dims, &connid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to create connectivity array for face block {} in file id {}", faceblocks[i].id, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } ex__compress_variable(exodusFilePtr, connid, 1); // store face type as attribute of connectivity variable status = nc_put_att_text(exodusFilePtr, connid, ATT_NAME_ELB, static_cast(std::strlen(faceblocks[i].elType)) + 1, faceblocks[i].elType); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to store face type name {} in file id {}", faceblocks[i].elType, exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } } return EX_NOERR; } template int Excn::Internals::put_non_define_data(const std::vector> &faceblocks) { if (faceblocks.empty()) { return EX_NOERR; } // Output faceblock ids... int num_faceblocks = (int)faceblocks.size(); std::vector faceblock_id(num_faceblocks); for (int i = 0; i < num_faceblocks; i++) { faceblock_id[i] = faceblocks[i].id; } if (put_id_array(exodusFilePtr, VAR_ID_FA_BLK, faceblock_id) != NC_NOERR) { return EX_FATAL; } // Now, write the status array std::vector status(num_faceblocks); for (int i = 0; i < num_faceblocks; i++) { status[i] = faceblocks[i].faceCount > 0 ? 1 : 0; } if (put_array(exodusFilePtr, VAR_STAT_FA_BLK, status) != NC_NOERR) { return EX_FATAL; } return EX_NOERR; } namespace { template int put_array(int exoid, const char *var_type, const std::vector &array) { std::string errmsg; int var_id; int status; status = nc_inq_varid(exoid, var_type, &var_id); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to locate {} in file id {}", var_type, exoid); ex_err_fn(exoid, __func__, errmsg.c_str(), status); return EX_FATAL; } if (sizeof(INT) == sizeof(int64_t)) { status = nc_put_var_longlong(exoid, var_id, (long long int *)array.data()); } else { status = nc_put_var_int(exoid, var_id, array.data()); } if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to write {} array in file id {}", var_type, exoid); ex_err_fn(exoid, __func__, errmsg.c_str(), status); return EX_FATAL; } return EX_NOERR; } int put_id_array(int exoid, const char *var_type, const std::vector &ids) { std::string errmsg; int var_id; int status = nc_inq_varid(exoid, var_type, &var_id); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to locate {} in file id {}", var_type, exoid); ex_err_fn(exoid, __func__, errmsg.c_str(), status); return EX_FATAL; } int id_type = get_type(exoid, EX_IDS_INT64_API); if (id_type == NC_INT64) { status = nc_put_var_longlong(exoid, var_id, (long long int *)ids.data()); } else { // Have ex_entity_id (long long), need ints... std::vector int_ids(ids.size()); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) #endif int_ids.assign(ids.begin(), ids.end()); #ifdef _MSC_VER #pragma warning(pop) #endif status = nc_put_var_int(exoid, var_id, int_ids.data()); } if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to write {} array in file id {}", var_type, exoid); ex_err_fn(exoid, __func__, errmsg.c_str(), status); return EX_FATAL; } return EX_NOERR; } int define_coordinate_vars(int exodusFilePtr, int64_t nodes, int node_dim, int dimension, int dim_dim, int str_dim) { std::string errmsg; int status; int dim[2]; int varid; if (nodes > 0) { // node coordinate arrays -- separate storage... dim[0] = node_dim; if (dimension > 0) { status = nc_def_var(exodusFilePtr, VAR_COORD_X, nc_flt_code(exodusFilePtr), 1, dim, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define node x coordinate array in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 2); } if (dimension > 1) { status = nc_def_var(exodusFilePtr, VAR_COORD_Y, nc_flt_code(exodusFilePtr), 1, dim, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define node y coordinate array in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 2); } if (dimension > 2) { status = nc_def_var(exodusFilePtr, VAR_COORD_Z, nc_flt_code(exodusFilePtr), 1, dim, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define node z coordinate array in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } ex__compress_variable(exodusFilePtr, varid, 2); } } // coordinate names array dim[0] = dim_dim; dim[1] = str_dim; status = nc_def_var(exodusFilePtr, VAR_NAME_COOR, NC_CHAR, 2, dim, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define coordinate name array in file id {}", exodusFilePtr); ex_err_fn(exodusFilePtr, __func__, errmsg.c_str(), status); return EX_FATAL; } return EX_NOERR; } int define_netcdf_vars(int exoid, const char *type, size_t count, const char *dim_num, const char *stat_var, const char *id_var, const char *name_var) { int dimid = 0; int varid = 0; int dim[2]; int namestrdim = 0; std::string errmsg; int status = nc_inq_dimid(exoid, DIM_STR_NAME, &namestrdim); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to get string name dimension in file id {}", exoid); ex_err_fn(exoid, __func__, errmsg.c_str(), status); return EX_FATAL; } status = nc_def_dim(exoid, dim_num, count, &dimid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define number of {}s in file id {}", type, exoid); ex_err_fn(exoid, __func__, errmsg.c_str(), status); return EX_FATAL; } // id status array: dim[0] = dimid; status = nc_def_var(exoid, stat_var, NC_INT, 1, dim, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define side {} status in file id {}", type, exoid); ex_err_fn(exoid, __func__, errmsg.c_str(), status); return EX_FATAL; } // id array: int ids_type = get_type(exoid, EX_IDS_INT64_DB); status = nc_def_var(exoid, id_var, ids_type, 1, dim, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define {} property in file id {}", type, exoid); ex_err_fn(exoid, __func__, errmsg.c_str(), status); return EX_FATAL; } // store property name as attribute of property array variable status = nc_put_att_text(exoid, varid, ATT_PROP_NAME, 3, "ID"); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to store {} property name {} in file id {}", type, "ID", exoid); ex_err_fn(exoid, __func__, errmsg.c_str(), status); return EX_FATAL; } dim[0] = dimid; dim[1] = namestrdim; status = nc_def_var(exoid, name_var, NC_CHAR, 2, dim, &varid); if (status != NC_NOERR) { ex_opts(EX_VERBOSE); errmsg = fmt::format("Error: failed to define {} name array in file id {}", type, exoid); ex_err_fn(exoid, __func__, errmsg.c_str(), status); return EX_FATAL; } return EX_NOERR; } } // namespace