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.
 
 
 
 
 
 

1323 lines
41 KiB

/*
* Copyright(C) 1999-2021, 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
*/
/* exodus II to matlab m file, copy of
exo2mat.
exo2mat was written by mrtabba
exo2m modifications by gmreese to permit usage on machines without
the matlab libraries.
modified by D. Todd Griffith, 01/12/2006
to include changes made in versions 1.4 through 1.6 on the
SEACAS tools repository as the previous modifications dated
12/08 and 12/15/2005 were made starting with Version 1.3.
In particular, the only changes are those made here are those
made in Version 1.6 which include a special provision
for exodus files which contain no distribution factors
modified by D. Todd Griffith, 12/15/2005
to write distribution factors as double precision type
modified by D. Todd Griffith 12/08/2005
to include complete writing of side set and node set information
so it will be available for the mat2exo conversion stage
*/
#include <algorithm>
#include <array>
#include <cstring> // for strlen, etc
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
#include "add_to_log.h" // for add_to_log
#include "exodusII.h" // for ex_get_variable_param, etc
#include "fmt/chrono.h"
#include "fmt/ostream.h"
#include "fmt/printf.h"
#include "matio.h" // for Mat_VarCreate, Mat_VarFree, etc
#include "time_stamp.h"
#include <cassert> // for assert
#include <cstddef> // for size_t
#include <cstdlib> // for free, calloc, exit
#include <ctime>
#if MATIO_VERSION < 151
#error "MatIO Version 1.5.1 or greater is required"
#endif
#define EXT ".mat"
static int textfile = 0;
static FILE *m_file = nullptr; /* file for m file output */
static mat_t *mat_file = nullptr; /* file for binary .mat output */
static bool debug = false;
static std::array<std::string, 3> qainfo{"exo2mat", "2021/09/27", "4.08"};
void logger(const char *message)
{
const std::string tsFormat = "[%H:%M:%S] ";
fmt::print(std::clog, "{}: {}\n", time_stamp(tsFormat), message);
}
void usage()
{
auto v5default = MAT_FT_DEFAULT == MAT_FT_MAT5 ? "[default]" : "";
auto v7default = MAT_FT_DEFAULT == MAT_FT_MAT73 ? "[default]" : "";
fmt::print("exo2mat [options] exodus_file_name.\n"
" the exodus_file_name is required (exodus only).\n"
" Options:\n"
" -t write a text (.m) file rather than a binary .mat\n"
" -o output file name (rather than auto generate)\n"
" -c use cell arrays for transient variables.\n"
" -v5 output version 5 mat file {}\n"
" -v73 output version 7.3 mat file (hdf5-based) {}\n"
" -v7.3 output version 7.3 mat file (hdf5-based)\n"
" ** note **\n"
"Binary files are written by default on all platforms.\n", v5default, v7default);
}
/* put a string into an m file. If the string has
line feeds, we put it as ints, and use 'char()' to convert it */
void mPutStr(const std::string &name, const char *str)
{
assert(m_file != nullptr);
if (strchr(str, '\n') == nullptr) {
fmt::fprintf(m_file, "%s='%s';\n", name, str);
}
else {
fmt::fprintf(m_file, "%s=[", name);
size_t i;
size_t j;
for (j = i = 0; i < std::strlen(str); i++, j++) {
if (j >= 20) {
j = 0;
fmt::fprintf(m_file, "...\n");
}
fmt::fprintf(m_file, "%d ", str[i]);
}
fmt::fprintf(m_file, "];\n");
fmt::fprintf(m_file, "%s=char(%s);\n", name, name);
}
}
/* put double array in m file */
void mPutDbl(const std::string &name, int n1, int n2, double *pd)
{
assert(m_file != nullptr);
if (n1 == 1 && n2 == 1) {
fmt::fprintf(m_file, "%s=%15.8e;\n", name, *pd);
return;
}
fmt::fprintf(m_file, "%s=zeros(%d,%d);\n", name, n1, n2);
for (int i = 0; i < n1; i++) {
for (int j = 0; j < n2; j++) {
fmt::fprintf(m_file, "%s(%d,%d)=%15.8e;\n", name, i + 1, j + 1, pd[i * n2 + j]);
}
}
}
/* put integer array in m file */
void mPutInt(const std::string &name, int pd)
{
assert(m_file != nullptr);
fmt::fprintf(m_file, "%s=%d;\n", name, pd);
}
/* put integer array in m file */
void mPutInt(const std::string &name, int n1, int n2, int *pd)
{
assert(m_file != nullptr);
if (n1 == 1 && n2 == 1) {
fmt::fprintf(m_file, "%s=%d;\n", name, *pd);
return;
}
fmt::fprintf(m_file, "%s=zeros(%d,%d);\n", name, n1, n2);
for (int i = 0; i < n1; i++) {
for (int j = 0; j < n2; j++) {
fmt::fprintf(m_file, "%s(%d,%d)=%d;\n", name, i + 1, j + 1, pd[i * n2 + j]);
}
}
}
/* put string in mat file*/
int matPutStr(const std::string &name, char *str)
{
int error = 0;
matvar_t *matvar = nullptr;
size_t dims[2];
dims[0] = 1;
dims[1] = std::strlen(str);
matvar = Mat_VarCreate(name.c_str(), MAT_C_CHAR, MAT_T_UINT8, 2, dims, str, MAT_F_DONT_COPY_DATA);
if (matvar != nullptr) {
error = Mat_VarWrite(mat_file, matvar, MAT_COMPRESSION_NONE);
Mat_VarFree(matvar);
}
else {
error = 1;
}
return error;
}
/* put double in mat file*/
int matPutDbl(const std::string &name, int n1, int n2, double *pd)
{
int error = 0;
matvar_t *matvar = nullptr;
size_t dims[2];
dims[0] = n1;
dims[1] = n2;
matvar =
Mat_VarCreate(name.c_str(), MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, pd, MAT_F_DONT_COPY_DATA);
if (matvar != nullptr) {
error = Mat_VarWrite(mat_file, matvar, MAT_COMPRESSION_ZLIB);
Mat_VarFree(matvar);
}
else {
error = 1;
}
return error;
}
/* put integer in mat file*/
int matPutInt(const std::string &name, int n1, int n2, int *pd)
{
int error = 0;
matvar_t *matvar = nullptr;
size_t dims[2];
dims[0] = n1;
dims[1] = n2;
matvar = Mat_VarCreate(name.c_str(), MAT_C_INT32, MAT_T_INT32, 2, dims, pd, MAT_F_DONT_COPY_DATA);
if (matvar != nullptr) {
error = Mat_VarWrite(mat_file, matvar, MAT_COMPRESSION_ZLIB);
Mat_VarFree(matvar);
}
else {
error = 1;
}
return error;
}
/* wrappers for the output routine types */
void PutStr(const std::string &name, const std::string &str)
{
if (textfile != 0) {
mPutStr(name, str.c_str());
}
else {
matPutStr(name, const_cast<char *>(str.c_str()));
}
}
int PutInt(const std::string &name, int pd)
{
int error = 0;
if (textfile != 0) {
mPutInt(name, pd);
}
else {
error = matPutInt(name, 1, 1, &pd);
}
return error;
}
int PutInt(const std::string &name, int n1, int n2, int *pd)
{
int error = 0;
if (textfile != 0) {
mPutInt(name, n1, n2, pd);
}
else {
error = matPutInt(name, n1, n2, pd);
}
return error;
}
int PutDbl(const std::string &name, int n1, int n2, double *pd)
{
int error = 0;
if (textfile != 0) {
mPutDbl(name, n1, n2, pd);
}
else {
error = matPutDbl(name, n1, n2, pd);
}
return error;
}
char **get_exodus_names(size_t count, int size)
{
auto names = new char *[count];
for (size_t i = 0; i < count; i++) {
names[i] = new char[size + 1];
std::memset(names[i], '\0', size + 1);
}
return names;
}
void delete_exodus_names(char **names, int count)
{
for (int i = 0; i < count; i++) {
delete[] names[i];
}
delete[] names;
}
void get_put_user_names(int exo_file, ex_entity_type type, int num_blocks, const std::string &mname)
{
int max_name_length = ex_inquire_int(exo_file, EX_INQ_DB_MAX_USED_NAME_LENGTH);
max_name_length = max_name_length < 32 ? 32 : max_name_length;
ex_set_max_name_length(exo_file, max_name_length);
char **names = get_exodus_names(num_blocks, max_name_length + 1);
ex_get_names(exo_file, type, names);
std::string user_names;
for (int j = 0; j < num_blocks; j++) {
user_names += names[j];
user_names += "\n";
}
PutStr(mname, user_names);
delete_exodus_names(names, num_blocks);
}
void get_put_names(int exo_file, ex_entity_type type, int num_vars, const std::string &mname)
{
int max_name_length = ex_inquire_int(exo_file, EX_INQ_DB_MAX_USED_NAME_LENGTH);
max_name_length = max_name_length < 32 ? 32 : max_name_length;
char **names = get_exodus_names(num_vars, max_name_length + 1);
if (debug) {
logger("\tReading variable names");
}
ex_get_variable_names(exo_file, type, num_vars, names);
std::string mat;
for (int i = 0; i < num_vars; i++) {
mat += names[i];
mat += "\n";
}
if (debug) {
logger("\tWriting variable names");
}
PutStr(mname, mat);
delete_exodus_names(names, num_vars);
}
std::vector<std::string> get_names(int exo_file, ex_entity_type type, int num_vars)
{
int max_name_length = ex_inquire_int(exo_file, EX_INQ_DB_MAX_USED_NAME_LENGTH);
max_name_length = max_name_length < 32 ? 32 : max_name_length;
char **names = get_exodus_names(num_vars, max_name_length + 1);
if (debug) {
logger("\tReading variable names");
}
ex_get_variable_names(exo_file, type, num_vars, names);
std::vector<std::string> mat(num_vars);
for (int i = 0; i < num_vars; i++) {
mat[i] = names[i];
}
delete_exodus_names(names, num_vars);
return mat;
}
void get_put_vars(int exo_file, ex_entity_type type, int num_blocks, int num_vars,
int num_time_steps, const std::vector<int> &num_per_block,
const std::string &prefix, bool use_cell_arrays)
{
/* truth table */
if (debug) {
logger("\tTruth Table");
}
std::vector<int> truth_table(num_vars * num_blocks);
ex_get_truth_table(exo_file, type, num_blocks, num_vars, truth_table.data());
std::vector<int> ids(num_blocks);
ex_get_ids(exo_file, type, ids.data());
size_t num_entity = std::accumulate(num_per_block.begin(), num_per_block.end(), 0);
if (use_cell_arrays) {
std::string var_name = prefix + "var";
size_t dims[2];
dims[0] = 2;
dims[1] = num_vars;
matvar_t *cell_array =
Mat_VarCreate(var_name.c_str(), MAT_C_CELL, MAT_T_CELL, 2, dims, nullptr, 0);
assert(cell_array);
std::vector<double> scr(num_vars * num_time_steps * num_entity);
dims[0] = num_entity;
dims[1] = num_time_steps;
size_t offset = 0;
// Get vector of variable names...
auto names = get_names(exo_file, type, num_vars);
std::vector<matvar_t *> cell_element(num_vars * 2);
int j = 0;
for (int i = 0; i < num_vars; i++) {
size_t sdims[2];
sdims[0] = 1;
sdims[1] = names[i].length();
cell_element[j] = Mat_VarCreate(nullptr, MAT_C_CHAR, MAT_T_UINT8, 2, sdims,
(void *)names[i].c_str(), MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, j, cell_element[j]);
j++;
cell_element[j] = Mat_VarCreate(nullptr, MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &scr[offset],
MAT_F_DONT_COPY_DATA);
assert(cell_element[j]);
Mat_VarSetCell(cell_array, j, cell_element[j]);
size_t n = 0;
for (int jj = 0; jj < num_time_steps; jj++) {
for (int k = 0; k < num_blocks; k++) {
if (truth_table[num_vars * k + i] == 1) {
ex_get_var(exo_file, jj + 1, type, i + 1, ids[k], num_per_block[k], &scr[n + offset]);
}
n += num_per_block[k];
}
}
offset += num_time_steps * num_entity;
j++;
}
Mat_VarWrite(mat_file, cell_array, MAT_COMPRESSION_NONE);
Mat_VarFree(cell_array);
}
else {
std::string var_name = prefix + "names";
get_put_names(exo_file, type, num_vars, var_name);
std::vector<double> scr(num_entity * num_time_steps);
std::string format = prefix + "var%02d";
for (int i = 0; i < num_vars; i++) {
if (debug) {
logger("\tReading");
}
std::fill(scr.begin(), scr.end(), 0.0);
size_t n = 0;
std::string str = fmt::sprintf(format.c_str(), i + 1);
for (int j = 0; j < num_time_steps; j++) {
for (int k = 0; k < num_blocks; k++) {
if (truth_table[num_vars * k + i] == 1) {
ex_get_var(exo_file, j + 1, type, i + 1, ids[k], num_per_block[k], &scr[n]);
}
n = n + num_per_block[k];
}
}
if (debug) {
logger("\tWriting");
}
PutDbl(str, num_entity, num_time_steps, scr.data());
}
}
}
std::vector<int> handle_element_blocks(int exo_file, int num_blocks, bool use_cell_arrays)
{
std::vector<int> ids(num_blocks);
ex_get_ids(exo_file, EX_ELEM_BLOCK, ids.data());
std::vector<int> num_elem_in_block(num_blocks);
// Storing:
// 1) name
// 2) id
// 3) block topology type
// 4) connectivity
int max_name_length = ex_inquire_int(exo_file, EX_INQ_DB_MAX_USED_NAME_LENGTH);
max_name_length = max_name_length < 32 ? 32 : max_name_length;
if (use_cell_arrays) {
int num_field = 4;
size_t dims[2];
dims[0] = num_field;
dims[1] = num_blocks;
matvar_t *cell_array =
Mat_VarCreate("element_blocks", MAT_C_CELL, MAT_T_CELL, 2, dims, nullptr, 0);
assert(cell_array);
std::vector<matvar_t *> cell_element(num_blocks * num_field);
std::vector<int> num_node_per_elem(num_blocks);
size_t conn_size = 0;
std::vector<std::string> types(num_blocks);
for (int i = 0; i < num_blocks; i++) {
char type[33];
int num_elem = 0;
int num_node = 0;
int num_attr = 0;
ex_get_block(exo_file, EX_ELEM_BLOCK, ids[i], type, &num_elem, &num_node, nullptr, nullptr,
&num_attr);
types[i] = std::string(type);
num_elem_in_block[i] = num_elem;
num_node_per_elem[i] = num_node;
conn_size += num_elem * num_node;
}
std::vector<int> connect(conn_size);
size_t conn_off = 0;
for (int i = 0; i < num_blocks; i++) {
std::vector<char> name(max_name_length + 1);
ex_get_name(exo_file, EX_ELEM_BLOCK, ids[i], name.data());
dims[0] = 1;
dims[1] = std::strlen(name.data());
size_t index = num_field * i + 0;
cell_element[index] =
Mat_VarCreate(nullptr, MAT_C_CHAR, MAT_T_UINT8, 2, dims, (void *)name.data(), 0);
Mat_VarSetCell(cell_array, index, cell_element[index]);
dims[0] = 1;
dims[1] = 1;
index = num_field * i + 1;
cell_element[index] =
Mat_VarCreate(nullptr, MAT_C_INT32, MAT_T_INT32, 2, dims, &ids[i], MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, index, cell_element[index]);
dims[0] = 1;
dims[1] = types[i].length();
index = num_field * i + 2;
cell_element[index] =
Mat_VarCreate(nullptr, MAT_C_CHAR, MAT_T_UINT8, 2, dims, (void *)types[i].c_str(), 0);
Mat_VarSetCell(cell_array, index, cell_element[index]);
dims[0] = num_node_per_elem[i];
dims[1] = num_elem_in_block[i];
index = num_field * i + 3;
ex_get_conn(exo_file, EX_ELEM_BLOCK, ids[i], &connect[conn_off], nullptr, nullptr);
cell_element[index] = Mat_VarCreate(nullptr, MAT_C_INT32, MAT_T_INT32, 2, dims,
&connect[conn_off], MAT_F_DONT_COPY_DATA);
assert(cell_element[index]);
Mat_VarSetCell(cell_array, index, cell_element[index]);
conn_off += num_node_per_elem[i] * num_elem_in_block[i];
}
Mat_VarWrite(mat_file, cell_array, MAT_COMPRESSION_NONE);
Mat_VarFree(cell_array);
}
else {
std::vector<int> connect;
std::vector<double> attr;
PutInt("blkids", num_blocks, 1, ids.data());
std::vector<char> type(max_name_length + 1);
std::string types;
for (int i = 0; i < num_blocks; i++) {
int num_elem = 0;
int num_node = 0;
int num_attr = 0;
ex_get_block(exo_file, EX_ELEM_BLOCK, ids[i], type.data(), &num_elem, &num_node, nullptr,
nullptr, &num_attr);
types += type.data();
types += "\n";
num_elem_in_block[i] = num_elem;
connect.resize(num_elem * num_node);
ex_get_conn(exo_file, EX_ELEM_BLOCK, ids[i], connect.data(), nullptr, nullptr);
std::string str = fmt::sprintf("blk%02d", i + 1);
PutInt(str, num_node, num_elem, connect.data());
// Handle block attributes (if any...)
attr.resize(num_elem);
str = fmt::sprintf("blk%02d_nattr", i + 1);
PutInt(str, num_attr);
if (num_attr > 0) {
std::string attr_names;
char **names = get_exodus_names(num_attr, max_name_length + 1);
ex_get_attr_names(exo_file, EX_ELEM_BLOCK, ids[i], names);
for (int j = 0; j < num_attr; j++) {
attr_names += names[j];
attr_names += "\n";
}
str = fmt::sprintf("blk%02d_attrnames", i + 1);
PutStr(str, attr_names);
delete_exodus_names(names, num_attr);
for (int j = 0; j < num_attr; j++) {
str = fmt::sprintf("blk%02d_attr%02d", i + 1, j + 1);
ex_get_one_attr(exo_file, EX_ELEM_BLOCK, ids[i], j + 1, attr.data());
PutDbl(str, num_elem, 1, attr.data());
}
}
}
get_put_user_names(exo_file, EX_ELEM_BLOCK, num_blocks, "blkusernames");
PutStr("blknames", types);
}
return num_elem_in_block;
}
std::vector<int> handle_node_sets(int exo_file, int num_sets, bool use_cell_arrays)
{
std::vector<int> num_nodes(num_sets);
if (num_sets > 0) {
if (debug) {
logger("Node Sets");
}
std::vector<int> ids(num_sets);
ex_get_ids(exo_file, EX_NODE_SET, ids.data());
size_t tot_nodes = 0;
size_t tot_dfac = 0;
std::vector<int> num_df(num_sets);
for (int i = 0; i < num_sets; i++) {
int n1;
int n2;
ex_get_set_param(exo_file, EX_NODE_SET, ids[i], &n1, &n2);
num_nodes[i] = n1;
num_df[i] = n2;
tot_nodes += n1;
tot_dfac += n2;
}
// Storing:
// 1) name
// 2) id
// 3) node list
// 4) distribution factors
if (use_cell_arrays) {
size_t dims[2];
dims[0] = 4;
dims[1] = num_sets;
matvar_t *cell_array =
Mat_VarCreate("node_sets", MAT_C_CELL, MAT_T_CELL, 2, dims, nullptr, 0);
assert(cell_array);
std::vector<matvar_t *> cell_element(num_sets * 4);
std::vector<int> node_list(tot_nodes);
std::vector<double> dist_fac(tot_dfac);
size_t nl_off = 0;
size_t df_off = 0;
int max_name_length = ex_inquire_int(exo_file, EX_INQ_DB_MAX_USED_NAME_LENGTH);
max_name_length = max_name_length < 32 ? 32 : max_name_length;
for (int i = 0; i < num_sets; i++) {
std::vector<char> name(max_name_length + 1);
ex_get_name(exo_file, EX_NODE_SET, ids[i], name.data());
dims[0] = 1;
dims[1] = std::strlen(name.data());
size_t index = 4 * i + 0;
cell_element[index] =
Mat_VarCreate(nullptr, MAT_C_CHAR, MAT_T_UINT8, 2, dims, (void *)name.data(), 0);
Mat_VarSetCell(cell_array, index, cell_element[index]);
dims[0] = 1;
dims[1] = 1;
index = 4 * i + 1;
cell_element[index] = Mat_VarCreate(nullptr, MAT_C_INT32, MAT_T_INT32, 2, dims, &ids[i],
MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, index, cell_element[index]);
dims[0] = num_nodes[i];
dims[1] = 1;
index = 4 * i + 2;
ex_get_set(exo_file, EX_NODE_SET, ids[i], &node_list[nl_off], nullptr);
/* nodes list */
cell_element[index] = Mat_VarCreate(nullptr, MAT_C_INT32, MAT_T_INT32, 2, dims,
&node_list[nl_off], MAT_F_DONT_COPY_DATA);
assert(cell_element[index]);
Mat_VarSetCell(cell_array, index, cell_element[index]);
/* distribution-factors list */
ex_get_set_dist_fact(exo_file, EX_NODE_SET, ids[i], &dist_fac[df_off]);
index = 4 * i + 3;
cell_element[index] = Mat_VarCreate(nullptr, MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims,
&dist_fac[df_off], MAT_F_DONT_COPY_DATA);
assert(cell_element[index]);
Mat_VarSetCell(cell_array, index, cell_element[index]);
nl_off += num_nodes[i];
df_off += num_df[i];
}
Mat_VarWrite(mat_file, cell_array, MAT_COMPRESSION_NONE);
Mat_VarFree(cell_array);
}
else {
PutInt("nsids", num_sets, 1, ids.data());
for (int i = 0; i < num_sets; i++) {
std::vector<int> node_list(num_nodes[i]);
ex_get_set(exo_file, EX_NODE_SET, ids[i], node_list.data(), nullptr);
/* nodes list */
std::string str;
str = fmt::sprintf("nsnod%02d", i + 1);
PutInt(str, node_list.size(), 1, node_list.data());
/* distribution-factors list */
if (num_df[i] > 0) {
std::vector<double> dist_fac(num_df[i]);
ex_get_set_dist_fact(exo_file, EX_NODE_SET, ids[i], dist_fac.data());
str = fmt::sprintf("nsfac%02d", i + 1);
PutDbl(str, dist_fac.size(), 1, dist_fac.data());
}
}
}
get_put_user_names(exo_file, EX_NODE_SET, num_sets, "nsusernames");
/* Store # nodes and # dis. factors per node set */
PutInt("nnsnodes", num_sets, 1, num_nodes.data());
PutInt("nnsdfac", num_sets, 1, num_df.data());
}
return num_nodes;
}
std::vector<int> handle_side_sets(int exo_file, int num_sets, bool use_cell_arrays)
{
std::vector<int> num_sideset_sides(num_sets);
std::vector<int> num_sideset_dfac(num_sets);
std::vector<int> num_sideset_nodes(num_sets);
if (num_sets > 0) {
std::vector<int> ids(num_sets);
ex_get_ids(exo_file, EX_SIDE_SET, ids.data());
// Storing:
// 1) name
// 2) id
// 3) element list
// 4) side list
// 5) node count per face
// 6) face node list
// 7) distribution factors
if (use_cell_arrays) {
size_t dims[2];
dims[0] = 7;
dims[1] = num_sets;
matvar_t *cell_array =
Mat_VarCreate("side_sets", MAT_C_CELL, MAT_T_CELL, 2, dims, nullptr, 0);
assert(cell_array);
std::vector<matvar_t *> cell_element(num_sets * 7);
size_t num_sides = ex_inquire_int(exo_file, EX_INQ_SS_ELEM_LEN);
size_t num_nodes = ex_inquire_int(exo_file, EX_INQ_SS_NODE_LEN);
std::vector<int> elem_list(num_sides);
std::vector<int> side_list(num_sides);
std::vector<int> num_nodes_per_side(num_sides);
std::vector<int> side_nodes(num_nodes);
// size_t num_df = ex_inquire_int(exo_file, EX_INQ_SS_DF_LEN);
// If `num_df == 0` or if it isn't equal to `num_nodes`, then
// all df will be set to 1.0, but in any case, the size of
// `ssdfac` should be num_nodes and not num_df.
std::vector<double> ssdfac(num_nodes);
size_t side_off = 0;
size_t node_off = 0;
size_t df_off = 0;
int max_name_length = ex_inquire_int(exo_file, EX_INQ_DB_MAX_USED_NAME_LENGTH);
max_name_length = max_name_length < 32 ? 32 : max_name_length;
for (int i = 0; i < num_sets; i++) {
std::vector<char> name(max_name_length + 1);
ex_get_name(exo_file, EX_SIDE_SET, ids[i], name.data());
dims[0] = 1;
dims[1] = std::strlen(name.data());
size_t index = 7 * i + 0;
cell_element[index] =
Mat_VarCreate(nullptr, MAT_C_CHAR, MAT_T_UINT8, 2, dims, (void *)name.data(), 0);
Mat_VarSetCell(cell_array, index, cell_element[index]);
dims[0] = 1;
dims[1] = 1;
index = 7 * i + 1;
cell_element[index] = Mat_VarCreate(nullptr, MAT_C_INT32, MAT_T_INT32, 2, dims, &ids[i],
MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, index, cell_element[index]);
int n1;
int n2;
ex_get_set_param(exo_file, EX_SIDE_SET, ids[i], &n1, &n2);
num_sideset_sides[i] = n1;
num_sideset_dfac[i] = n2;
bool has_ss_dfac = !(n2 == 0 || n1 == n2);
if (!has_ss_dfac) {
num_sideset_dfac[i] = num_sideset_nodes[i];
}
ex_get_side_set_node_list_len(exo_file, ids[i], &num_sideset_nodes[i]);
/* element and side list for side sets (dgriffi) */
ex_get_set(exo_file, EX_SIDE_SET, ids[i], &elem_list[side_off], &side_list[side_off]);
dims[0] = num_sideset_sides[i];
dims[1] = 1;
index = 7 * i + 2;
cell_element[index] = Mat_VarCreate(nullptr, MAT_C_INT32, MAT_T_INT32, 2, dims,
&elem_list[side_off], MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, index, cell_element[index]);
index = 7 * i + 3;
cell_element[index] = Mat_VarCreate(nullptr, MAT_C_INT32, MAT_T_INT32, 2, dims,
&side_list[side_off], MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, index, cell_element[index]);
ex_get_side_set_node_list(exo_file, ids[i], &num_nodes_per_side[side_off],
&side_nodes[node_off]);
/* number-of-nodes-per-side list */
index = 7 * i + 4;
cell_element[index] = Mat_VarCreate(nullptr, MAT_C_INT32, MAT_T_INT32, 2, dims,
&num_nodes_per_side[side_off], MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, index, cell_element[index]);
dims[0] = num_sideset_nodes[i];
dims[1] = 1;
index = 7 * i + 5;
cell_element[index] = Mat_VarCreate(nullptr, MAT_C_INT32, MAT_T_INT32, 2, dims,
&side_nodes[node_off], MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, index, cell_element[index]);
/* distribution-factors list */
if (has_ss_dfac) {
ex_get_set_dist_fact(exo_file, EX_SIDE_SET, ids[i], &ssdfac[df_off]);
}
else {
n2 = num_sideset_dfac[i];
for (int j = 0; j < n2; j++) {
ssdfac[j] = 1.0;
}
}
dims[0] = num_sideset_dfac[i];
dims[1] = 1;
index = 7 * i + 6;
cell_element[index] = Mat_VarCreate(nullptr, MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims,
&ssdfac[df_off], MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, index, cell_element[index]);
side_off += num_sideset_sides[i];
node_off += num_sideset_nodes[i];
df_off += num_sideset_dfac[i];
}
Mat_VarWrite(mat_file, cell_array, MAT_COMPRESSION_NONE);
Mat_VarFree(cell_array);
}
else {
PutInt("ssids", num_sets, 1, ids.data());
std::vector<int> elem_list;
std::vector<int> side_list;
std::vector<int> num_nodes_per_side;
std::vector<int> side_nodes;
std::vector<double> ssdfac;
for (int i = 0; i < num_sets; i++) {
int n1;
int n2;
ex_get_set_param(exo_file, EX_SIDE_SET, ids[i], &n1, &n2);
num_sideset_sides[i] = n1;
num_sideset_dfac[i] = n2;
bool has_ss_dfac = (n2 != 0);
if (n2 == 0 || n1 == n2) {
ex_get_side_set_node_list_len(exo_file, ids[i], &n2);
}
num_nodes_per_side.resize(n1);
side_nodes.resize(n2);
ex_get_side_set_node_list(exo_file, ids[i], num_nodes_per_side.data(), side_nodes.data());
/* number-of-nodes-per-side list */
std::string str;
str = fmt::sprintf("ssnum%02d", i + 1);
PutInt(str, n1, 1, num_nodes_per_side.data());
/* nodes list */
str = fmt::sprintf("ssnod%02d", i + 1);
PutInt(str, n2, 1, side_nodes.data());
/* distribution-factors list */
if (has_ss_dfac) {
ssdfac.resize(n2);
ex_get_set_dist_fact(exo_file, EX_SIDE_SET, ids[i], ssdfac.data());
str = fmt::sprintf("ssfac%02d", i + 1);
PutDbl(str, n2, 1, ssdfac.data());
}
/* element and side list for side sets (dgriffi) */
elem_list.resize(n1);
side_list.resize(n1);
ex_get_set(exo_file, EX_SIDE_SET, ids[i], elem_list.data(), side_list.data());
str = fmt::sprintf("ssside%02d", i + 1);
PutInt(str, n1, 1, side_list.data());
str = fmt::sprintf("sselem%02d", i + 1);
PutInt(str, n1, 1, elem_list.data());
}
}
get_put_user_names(exo_file, EX_SIDE_SET, num_sets, "ssusernames");
/* Store # sides and # dis. factors per side set (dgriffi) */
PutInt("nsssides", num_sets, 1, num_sideset_sides.data());
PutInt("nssdfac", num_sets, 1, num_sideset_dfac.data());
}
return num_sideset_sides;
}
void handle_coordinates(int exo_file, size_t num_nodes, int num_axes)
{
if (debug) {
logger("Coordinates");
}
std::vector<double> x, y, z;
x.resize(num_nodes);
if (num_axes >= 2) {
y.resize(num_nodes);
}
if (num_axes == 3) {
z.resize(num_nodes);
}
ex_get_coord(exo_file, x.data(), y.data(), z.data());
PutDbl("x0", num_nodes, 1, x.data());
if (num_axes >= 2) {
PutDbl("y0", num_nodes, 1, y.data());
}
if (num_axes == 3) {
PutDbl("z0", num_nodes, 1, z.data());
}
}
/**********************************************************************/
/* remove an argument from the list */
void del_arg(int *argc, char *argv[], int j)
{
for (int jj = j + 1; jj < *argc; jj++) {
argv[jj - 1] = argv[jj];
}
(*argc)--;
argv[*argc] = nullptr;
}
/**********************************************************************/
int main(int argc, char *argv[])
{
std::string oname{};
std::string filename{};
std::string str;
const char *ext = EXT;
int err;
int num_axes;
int num_blocks;
int num_side_sets;
int num_node_sets;
int num_time_steps;
int num_info_lines;
int num_global_vars;
int num_nodal_vars;
int num_element_vars;
int num_nodeset_vars;
int num_sideset_vars;
size_t num_nodes = 0;
size_t num_elements = 0;
enum mat_ft mat_version = MAT_FT_DEFAULT;
bool use_cell_arrays = false;
/* process arguments */
for (int j = 1; j < argc && argv[j][0] == '-'; j++) {
if (strcmp(argv[j], "-t") == 0) { /* write text file (*.m) */
del_arg(&argc, argv, j);
textfile = 1;
j--;
continue;
}
if (strcmp(argv[j], "-h") == 0 || strcmp(argv[j], "--help") == 0) { /* write help info */
del_arg(&argc, argv, j);
usage();
exit(1);
}
if (strcmp(argv[j], "-d") == 0) { /* write help info */
del_arg(&argc, argv, j);
j--;
debug = true;
continue;
}
if (strcmp(argv[j], "-c") == 0) { /* use cell arrays */
del_arg(&argc, argv, j);
j--;
use_cell_arrays = true;
continue;
}
if (strcmp(argv[j], "-v73") == 0) { /* Version 7.3 */
del_arg(&argc, argv, j);
mat_version = MAT_FT_MAT73;
j--;
continue;
}
// This matches the option used in matlab
if ((strcmp(argv[j], "-v7.3") == 0) || (strcmp(argv[j], "-V7.3") == 0)) { /* Version 7.3 */
del_arg(&argc, argv, j);
mat_version = MAT_FT_MAT73;
j--;
continue;
}
if (strcmp(argv[j], "-v5") == 0) { /* Version 5 (default) */
del_arg(&argc, argv, j);
mat_version = MAT_FT_MAT5;
j--;
continue;
}
if (strcmp(argv[j], "-o") == 0) { /* specify output file name */
del_arg(&argc, argv, j);
if (argv[j] != nullptr) {
oname = argv[j];
del_arg(&argc, argv, j);
fmt::print("output file: {}\n", oname);
}
else {
fmt::print(stderr, "ERROR: Invalid output file specification.\n");
return 2;
}
j--;
continue;
}
// Unrecognized option...
fmt::print(stderr, "ERROR: Unrecognized option: '{}'\n", argv[j]);
usage();
exit(1);
}
/* QA Info */
fmt::print("{}: {}, {}\n", qainfo[0], qainfo[2], qainfo[1]);
/* usage message*/
if (argc != 2) {
usage();
exit(1);
}
/* open output file */
if (textfile != 0) {
ext = ".m";
}
if (oname.empty()) {
filename = argv[1];
size_t pos = filename.find_last_of('.');
if (pos != std::string::npos) {
filename = filename.substr(0, pos);
}
filename += std::string(ext);
}
else {
filename = oname;
}
if (textfile != 0) {
m_file = fopen(filename.c_str(), "w");
if (m_file == nullptr) {
fmt::print(stderr, "ERROR: Unable to open '{}'\n", filename);
exit(1);
}
}
else {
mat_file = Mat_CreateVer(filename.c_str(), nullptr, mat_version);
if (mat_file == nullptr) {
fmt::print(stderr, "ERROR: Unable to create matlab file '{}'\n", filename);
exit(1);
}
}
ex_opts(EX_VERBOSE);
/* word sizes */
int cpu_word_size = sizeof(double);
int io_word_size = 0;
/* open exodus file */
float exo_version;
int exo_file = ex_open(argv[1], EX_READ, &cpu_word_size, &io_word_size, &exo_version);
if (exo_file < 0) {
fmt::print(stderr, "ERROR: Cannot open '{}'\n", argv[1]);
exit(1);
}
/* print */
fmt::print("\ttranslating {} to {}...\n", argv[1], filename);
/* read database parameters */
char *line = reinterpret_cast<char *>(calloc((MAX_LINE_LENGTH + 1), sizeof(char)));
ex_get_init(exo_file, line, &num_axes, &num_nodes, &num_elements, &num_blocks, &num_node_sets,
&num_side_sets);
num_info_lines = ex_inquire_int(exo_file, EX_INQ_INFO);
num_time_steps = ex_inquire_int(exo_file, EX_INQ_TIME);
ex_get_variable_param(exo_file, EX_GLOBAL, &num_global_vars);
ex_get_variable_param(exo_file, EX_NODAL, &num_nodal_vars);
ex_get_variable_param(exo_file, EX_ELEM_BLOCK, &num_element_vars);
ex_get_variable_param(exo_file, EX_NODE_SET, &num_nodeset_vars);
ex_get_variable_param(exo_file, EX_SIDE_SET, &num_sideset_vars);
/* export parameters */
PutInt("naxes", num_axes);
PutInt("nnodes", num_nodes);
PutInt("nelems", num_elements);
PutInt("nblks", num_blocks);
PutInt("nnsets", num_node_sets);
PutInt("nssets", num_side_sets);
PutInt("nsteps", num_time_steps);
PutInt("ngvars", num_global_vars);
PutInt("nnvars", num_nodal_vars);
PutInt("nevars", num_element_vars);
PutInt("nnsvars", num_nodeset_vars);
PutInt("nssvars", num_sideset_vars);
/* allocate -char- scratch space*/
int nstr2 = num_info_lines;
nstr2 = std::max(nstr2, num_blocks);
nstr2 = std::max(nstr2, num_node_sets);
nstr2 = std::max(nstr2, num_side_sets);
char **str2 = get_exodus_names(nstr2, 512);
/* title */
PutStr("Title", line);
/* information records */
if (num_info_lines > 0) {
ex_get_info(exo_file, str2);
std::string ostr;
for (int i = 0; i < num_info_lines; i++) {
if (std::strlen(str2[i]) > 0) {
ostr += str2[i];
ostr += "\n";
}
}
PutStr("info", ostr);
ostr = "";
for (int i = 0; i < num_info_lines; i++) {
if (std::strlen(str2[i]) > 0 && strncmp(str2[i], "cavi", 4) == 0) {
ostr += str2[i];
ostr += "\n";
}
}
PutStr("cvxp", ostr);
}
/* nodal coordinates */
handle_coordinates(exo_file, num_nodes, num_axes);
/* side sets */
if (debug) {
logger("Side Sets");
}
auto num_sideset_sides = handle_side_sets(exo_file, num_side_sets, use_cell_arrays);
/* node sets (section by dgriffi) */
auto num_nodeset_nodes = handle_node_sets(exo_file, num_node_sets, use_cell_arrays);
/* element blocks */
if (debug) {
logger("Element Blocks");
}
auto num_elem_in_block = handle_element_blocks(exo_file, num_blocks, use_cell_arrays);
/* time values */
if (num_time_steps > 0) {
if (debug) {
logger("Time Steps");
}
std::vector<double> scr(num_time_steps);
ex_get_all_times(exo_file, scr.data());
PutDbl("time", num_time_steps, 1, scr.data());
}
/* global variables */
if (num_global_vars > 0) {
if (debug) {
logger("Global Variables");
}
if (use_cell_arrays) {
size_t dims[2];
dims[0] = 2;
dims[1] = num_global_vars;
matvar_t *cell_array = Mat_VarCreate("gvar", MAT_C_CELL, MAT_T_CELL, 2, dims, nullptr, 0);
assert(cell_array);
std::vector<double> scr(num_time_steps * num_global_vars);
dims[0] = num_time_steps;
dims[1] = 1;
size_t offset = 0;
// Get vector of variable names...
auto gnames = get_names(exo_file, EX_GLOBAL, num_global_vars);
std::vector<matvar_t *> cell_element(num_global_vars * 2);
int j = 0;
for (int i = 0; i < num_global_vars; i++) {
size_t sdims[2];
sdims[0] = 1;
sdims[1] = gnames[i].length();
cell_element[j] = Mat_VarCreate(nullptr, MAT_C_CHAR, MAT_T_UINT8, 2, sdims,
(void *)gnames[i].c_str(), MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, j, cell_element[j]);
j++;
ex_get_var_time(exo_file, EX_GLOBAL, i + 1, 1, 1, num_time_steps, &scr[offset]);
cell_element[j] = Mat_VarCreate(nullptr, MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &scr[offset],
MAT_F_DONT_COPY_DATA);
assert(cell_element[j]);
Mat_VarSetCell(cell_array, j, cell_element[j]);
offset += num_time_steps;
j++;
}
Mat_VarWrite(mat_file, cell_array, MAT_COMPRESSION_NONE);
Mat_VarFree(cell_array);
}
else {
get_put_names(exo_file, EX_GLOBAL, num_global_vars, "gnames");
std::vector<double> scr(num_time_steps);
for (int i = 0; i < num_global_vars; i++) {
str = fmt::sprintf("gvar%02d", i + 1);
ex_get_var_time(exo_file, EX_GLOBAL, i + 1, 1, 1, num_time_steps, scr.data());
PutDbl(str, num_time_steps, 1, scr.data());
}
}
}
/* nodal variables */
if (num_nodal_vars > 0) {
if (debug) {
logger("Nodal Variables");
}
if (debug) {
logger("\tNames");
}
if (use_cell_arrays) {
size_t dims[2];
dims[0] = 2;
dims[1] = num_nodal_vars;
matvar_t *cell_array = Mat_VarCreate("nvar", MAT_C_CELL, MAT_T_CELL, 2, dims, nullptr, 0);
assert(cell_array);
std::vector<double> scr(num_nodal_vars * num_time_steps * num_nodes);
dims[0] = num_nodes;
dims[1] = num_time_steps;
size_t offset = 0;
// Get vector of variable names...
auto nnames = get_names(exo_file, EX_NODAL, num_nodal_vars);
std::vector<matvar_t *> cell_element(num_nodal_vars * 2);
int j = 0;
for (int i = 0; i < num_nodal_vars; i++) {
size_t sdims[2];
sdims[0] = 1;
sdims[1] = nnames[i].length();
cell_element[j] = Mat_VarCreate(nullptr, MAT_C_CHAR, MAT_T_UINT8, 2, sdims,
(void *)nnames[i].c_str(), MAT_F_DONT_COPY_DATA);
Mat_VarSetCell(cell_array, j, cell_element[j]);
j++;
cell_element[j] = Mat_VarCreate(nullptr, MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &scr[offset],
MAT_F_DONT_COPY_DATA);
assert(cell_element[j]);
Mat_VarSetCell(cell_array, j, cell_element[j]);
for (int k = 0; k < num_time_steps; k++) {
ex_get_var(exo_file, k + 1, EX_NODAL, i + 1, 1, num_nodes, &scr[num_nodes * k + offset]);
}
offset += num_time_steps * num_nodes;
j++;
}
Mat_VarWrite(mat_file, cell_array, MAT_COMPRESSION_NONE);
Mat_VarFree(cell_array);
}
else {
get_put_names(exo_file, EX_NODAL, num_nodal_vars, "nnames");
std::vector<double> scr(num_nodes * num_time_steps);
for (int i = 0; i < num_nodal_vars; i++) {
str = fmt::sprintf("nvar%02d", i + 1);
if (debug) {
logger("\tReading");
}
for (int j = 0; j < num_time_steps; j++) {
ex_get_var(exo_file, j + 1, EX_NODAL, i + 1, 1, num_nodes, &scr[num_nodes * j]);
}
if (debug) {
logger("\tWriting");
}
PutDbl(str, num_nodes, num_time_steps, scr.data());
}
}
}
/* element variables */
if (num_element_vars > 0) {
if (debug) {
logger("Element Variables");
}
get_put_vars(exo_file, EX_ELEM_BLOCK, num_blocks, num_element_vars, num_time_steps,
num_elem_in_block, "e", use_cell_arrays);
}
/* nodeset variables */
if (num_nodeset_vars > 0) {
if (debug) {
logger("Nodeset Variables");
}
get_put_vars(exo_file, EX_NODE_SET, num_node_sets, num_nodeset_vars, num_time_steps,
num_nodeset_nodes, "ns", use_cell_arrays);
}
/* sideset variables */
if (num_sideset_vars > 0) {
if (debug) {
logger("Sideset Variables");
}
get_put_vars(exo_file, EX_SIDE_SET, num_side_sets, num_sideset_vars, num_time_steps,
num_sideset_sides, "ss", use_cell_arrays);
}
/* node and element number maps */
if (debug) {
logger("Node and Element Number Maps");
}
ex_opts(0); /* turn off error reporting. It is not an error to have no map*/
std::vector<int> ids(num_nodes);
err = ex_get_id_map(exo_file, EX_NODE_MAP, ids.data());
if (err == 0) {
PutInt("node_num_map", num_nodes, 1, ids.data());
}
ids.resize(num_elements);
err = ex_get_id_map(exo_file, EX_ELEM_MAP, ids.data());
if (err == 0) {
PutInt("elem_num_map", num_elements, 1, ids.data());
}
if (debug) {
logger("Closing file");
}
ex_close(exo_file);
if (textfile != 0) {
fclose(m_file);
}
else {
Mat_Close(mat_file);
}
free(line);
delete_exodus_names(str2, nstr2);
fmt::print("done...\n");
/* exit status */
add_to_log("exo2mat", 0);
return (0);
}