Cloned SEACAS for EXODUS library with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1648 lines
56 KiB

/*
* 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 <EP_ExodusEntity.h> // for Block, Mesh
#include <EP_Internals.h> // for Internals, Redefine
#include <algorithm> // for sort
#include <copy_string_cpp.h>
#include <cstddef> // for size_t
#include <cstdint> // for int64_t
#include <cstdlib> // for exit, EXIT_FAILURE
#include <cstring> // for strlen, memset
#include <fmt/ostream.h>
#include <smart_assert.h> // for SMART_ASSERT
#include <string> // for string, basic_string
#include <vector> // for vector
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \
defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__)
#include <Shlwapi.h>
#endif
extern "C" {
#define NO_NETCDF_2
#include <exodusII.h>
#include <exodusII_int.h>
#include <netcdf.h>
}
// Explicit Initialization of the functions used...
namespace Excn {
template int Internals<int>::write_meta_data(const Mesh &mesh, const std::vector<Block> &blocks,
const std::vector<NodeSet<int>> &nodesets,
const std::vector<SideSet<int>> &sidesets,
const std::vector<EdgeBlock<int>> &edgeblock,
const std::vector<FaceBlock<int>> &faceblock,
const CommunicationMetaData &comm);
template bool Internals<int>::check_meta_data(const Mesh &mesh, const std::vector<Block> &blocks,
const std::vector<NodeSet<int>> &nodesets,
const std::vector<SideSet<int>> &sidesets,
const std::vector<EdgeBlock<int>> &edgeblock,
const std::vector<FaceBlock<int>> &faceblock,
const CommunicationMetaData &comm);
template int Internals<int64_t>::write_meta_data(const Mesh &mesh,
const std::vector<Block> &blocks,
const std::vector<NodeSet<int64_t>> &nodesets,
const std::vector<SideSet<int64_t>> &sidesets,
const std::vector<EdgeBlock<int64_t>> &edgeblock,
const std::vector<FaceBlock<int64_t>> &faceblock,
const CommunicationMetaData &comm);
template bool Internals<int64_t>::check_meta_data(
const Mesh &mesh, const std::vector<Block> &blocks,
const std::vector<NodeSet<int64_t>> &nodesets, const std::vector<SideSet<int64_t>> &sidesets,
const std::vector<EdgeBlock<int64_t>> &edgeblock,
const std::vector<FaceBlock<int64_t>> &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 <typename INT>
int put_array(int exoid, const char *var_type, const std::vector<INT> &array);
int put_id_array(int exoid, const char *var_type, const std::vector<ex_entity_id> &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 <typename INT>
int Excn::Internals<INT>::write_meta_data(const Mesh &mesh, const std::vector<Block> &blocks,
const std::vector<NodeSet<INT>> &nodesets,
const std::vector<SideSet<INT>> &sidesets,
const std::vector<EdgeBlock<INT>> &edgeblocks,
const std::vector<FaceBlock<INT>> &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<Excn::Block &>(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<Block> 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<Excn::Block &>(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 <typename INT>
bool Excn::Internals<INT>::check_meta_data(const Mesh &mesh, const std::vector<Block> & /*unused*/,
const std::vector<NodeSet<INT>> & /*unused*/,
const std::vector<SideSet<INT>> & /*unused*/,
const std::vector<EdgeBlock<INT>> & /*unused*/,
const std::vector<FaceBlock<INT>> & /*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 <typename INT>
int Excn::Internals<INT>::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, &current_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 <typename INT> int Excn::Internals<INT>::put_metadata(const std::vector<Block> &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<int>(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 <typename INT>
int Excn::Internals<INT>::put_non_define_data(const Mesh & /*unused*/,
const CommunicationMetaData & /*unused*/)
{
return EX_NOERR;
}
template <typename INT>
int Excn::Internals<INT>::put_non_define_data(const std::vector<Block> &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<ex_entity_id> 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<int> 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 <typename INT>
int Excn::Internals<INT>::put_metadata(const std::vector<NodeSet<INT>> &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<int>(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 <typename INT>
int Excn::Internals<INT>::put_non_define_data(const std::vector<NodeSet<INT>> &nodesets)
{
if (nodesets.empty()) {
return EX_NOERR;
}
// Output nodeset ids...
size_t num_nodesets = nodesets.size();
std::vector<ex_entity_id> 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<int> 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 <typename INT>
int Excn::Internals<INT>::put_metadata(const std::vector<SideSet<INT>> &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 <typename INT>
int Excn::Internals<INT>::put_non_define_data(const std::vector<SideSet<INT>> &sidesets)
{
if (sidesets.empty()) {
return EX_NOERR;
}
// Output sideset ids...
int num_sidesets = (int)sidesets.size();
std::vector<ex_entity_id> 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<int> 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 <typename INT>
int Excn::Internals<INT>::put_metadata(const std::vector<EdgeBlock<INT>> &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<int>(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 <typename INT>
int Excn::Internals<INT>::put_non_define_data(const std::vector<EdgeBlock<INT>> &edgeblocks)
{
if (edgeblocks.empty()) {
return EX_NOERR;
}
// Output edgeblock ids...
int num_edgeblocks = (int)edgeblocks.size();
std::vector<ex_entity_id> 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<int> 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 <typename INT>
int Excn::Internals<INT>::put_metadata(const std::vector<FaceBlock<INT>> &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<int>(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 <typename INT>
int Excn::Internals<INT>::put_non_define_data(const std::vector<FaceBlock<INT>> &faceblocks)
{
if (faceblocks.empty()) {
return EX_NOERR;
}
// Output faceblock ids...
int num_faceblocks = (int)faceblocks.size();
std::vector<ex_entity_id> 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<int> 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 <typename INT>
int put_array(int exoid, const char *var_type, const std::vector<INT> &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<ex_entity_id> &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> 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