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.

472 lines
13 KiB

2 years ago
// Copyright(C) 1999-2021 National Technology & Engineering Solutions
// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with
// NTESS, the U.S. Government retains certain rights in this software.
//
// See packages/seacas/LICENSE for details
#include "ED_SystemInterface.h"
#include "exo_entity.h"
#include "exodusII.h" // for ex_get_var, EX_INVALID_ID, etc
#include "fmt/color.h"
#include "fmt/ostream.h"
#include "smart_assert.h" // for SMART_ASSERT
#include "stringx.h" // for to_lower
#include <cstdint> // for int64_t
#include <cstdlib> // for exit
#include <cstring> // for strlen
#include <string>
#include <vector>
namespace {
size_t get_index(int file_id, EXOTYPE exo_type, size_t id, const char *label);
size_t get_num_entities(int file_id, EXOTYPE exo_type);
size_t get_num_variables(int file_id, EXOTYPE type, const char *label);
size_t get_num_attributes(int file_id, EXOTYPE type, size_t id, const char *label);
#ifndef NDEBUG
size_t get_num_timesteps(int file_id);
#endif
} // namespace
Exo_Entity::Exo_Entity(int file_id, size_t id) : fileId(file_id), id_(id)
{
SMART_ASSERT(file_id > 0);
SMART_ASSERT((int)id > EX_INVALID_ID);
}
Exo_Entity::Exo_Entity(int file_id, size_t id, size_t nnodes)
: fileId(file_id), id_(id), numEntity(nnodes)
{
SMART_ASSERT(file_id > 0);
SMART_ASSERT((int)id > EX_INVALID_ID);
}
Exo_Entity::~Exo_Entity()
{
delete[] truth_;
if (numVars > 0) {
for (int i = 0; i < numVars; ++i) {
delete[] results_[i];
}
delete[] results_;
}
if (numAttr > 0) {
for (int i = 0; i < numAttr; ++i) {
delete[] attributes_[i];
}
}
}
int Exo_Entity::Check_State() const
{
SMART_ASSERT(id_ >= EX_INVALID_ID);
SMART_ASSERT(!(id_ == EX_INVALID_ID && numEntity > 0));
return 1;
}
void Exo_Entity::initialize(int file_id, size_t id)
{
fileId = file_id;
id_ = id;
index_ = get_index(fileId, exodus_type(), id_, label());
entity_load_params();
internal_load_params();
}
bool Exo_Entity::is_valid_var(size_t var_index) const
{
SMART_ASSERT((int)var_index < numVars);
if (truth_ == nullptr) {
get_truth_table();
SMART_ASSERT(truth_ != nullptr);
}
return (truth_[var_index] != 0);
}
std::string Exo_Entity::Load_Results(int time_step, int var_index)
{
SMART_ASSERT(Check_State());
if (fileId < 0) {
return "exodiff: ERROR: Invalid file id!";
}
if (id_ == EX_INVALID_ID) {
return "exodiff: ERROR: Must initialize block parameters first!";
}
if (var_index < 0 || var_index >= numVars) {
Error("Exo_Entity::Load_Results(): var_index is invalid. Aborting...\n");
}
SMART_ASSERT(time_step >= 1 && time_step <= (int)get_num_timesteps(fileId));
if (time_step != currentStep) {
Free_Results();
currentStep = time_step;
}
if (truth_ == nullptr) {
get_truth_table();
SMART_ASSERT(truth_ != nullptr);
}
if (truth_[var_index] != 0) {
if ((results_[var_index] == nullptr) && (numEntity != 0u)) {
results_[var_index] = new double[numEntity];
SMART_ASSERT(results_[var_index] != nullptr);
}
if (numEntity != 0u) {
int err = 0;
err = ex_get_var(fileId, time_step, exodus_type(), var_index + 1, id_, numEntity,
results_[var_index]);
if (err < 0) {
Error(fmt::format("Exo_Entity::Load_Results(): Call to exodus routine"
" returned error value! {} id = {}\n"
"Aborting...\n",
label(), id_));
}
else if (err > 0) {
return fmt::format("WARNING: Number {} returned from call to exodus get variable routine.",
err);
}
}
else {
return std::string("WARNING: No items in this ") + label();
}
}
else {
return std::string("WARNING: Variable not stored in this ") + label();
}
return "";
}
std::string Exo_Entity::Load_Results(int t1, int t2, double proportion, int var_index)
{
static std::vector<double> results2;
SMART_ASSERT(Check_State());
if (fileId < 0) {
return "exodiff: ERROR: Invalid file id!";
}
if (id_ == EX_INVALID_ID) {
return "exodiff: ERROR: Must initialize block parameters first!";
}
SMART_ASSERT(var_index >= 0 && var_index < numVars);
SMART_ASSERT(t1 >= 1 && t1 <= (int)get_num_timesteps(fileId));
SMART_ASSERT(t2 >= 1 && t2 <= (int)get_num_timesteps(fileId));
if (t1 != currentStep) {
Free_Results();
currentStep = t1;
}
if (truth_ == nullptr) {
get_truth_table();
SMART_ASSERT(truth_ != nullptr);
}
if (truth_[var_index] != 0) {
if ((results_[var_index] == nullptr) && (numEntity != 0u)) {
results_[var_index] = new double[numEntity];
SMART_ASSERT(results_[var_index] != nullptr);
}
if (numEntity != 0u) {
int err =
ex_get_var(fileId, t1, exodus_type(), var_index + 1, id_, numEntity, results_[var_index]);
if (err < 0) {
Error(fmt::format(
"Exo_Entity::Load_Results(): Call to exodus routine returned error value! {} id = {}\n"
"Aborting...\n",
label(), id_));
}
else if (err > 0) {
return fmt::format("WARNING: Number {} returned from call to exodus get variable routine.",
err);
}
if (t1 != t2) {
results2.resize(numEntity);
err = ex_get_var(fileId, t2, exodus_type(), var_index + 1, id_, numEntity, &results2[0]);
if (err < 0) {
Error(fmt::format("Exo_Entity::Load_Results(): Call to exodus routine"
" returned error value! {} id = {}\n"
"Aborting...\n",
label(), id_));
}
double *results1 = results_[var_index];
for (size_t i = 0; i < numEntity; i++) {
results1[i] = (1.0 - proportion) * results1[i] + proportion * results2[i];
}
}
}
else {
return std::string("WARNING: No items in this ") + label();
}
}
else {
return std::string("WARNING: Variable not stored in this ") + label();
}
return "";
}
const double *Exo_Entity::Get_Results(int var_index) const
{
SMART_ASSERT(Check_State());
if (currentStep == 0) {
return nullptr;
}
SMART_ASSERT(var_index >= 0 && var_index < numVars);
if (var_index >= 0 && var_index < numVars) {
return results_[var_index];
}
return nullptr;
}
void Exo_Entity::Free_Results()
{
SMART_ASSERT(Check_State());
currentStep = 0;
for (int v = 0; v < numVars; ++v) {
delete[] results_[v];
results_[v] = nullptr;
}
}
void Exo_Entity::get_truth_table() const
{
if (numVars > 0 && truth_ == nullptr) {
truth_ = new int[numVars];
SMART_ASSERT(truth_ != nullptr);
// initialize to true for the case of no objects in the block (some older
// versions of ex_get_object_truth_vector do not set the values at all)
for (int i = 0; i < numVars; ++i) {
truth_[i] = 1;
}
int err = ex_get_object_truth_vector(fileId, exodus_type(), id_, numVars, truth_);
if (err < 0) {
Error("Exo_Entity::get_truth_table(): ex_get_object_truth_vector returned error.\n");
}
}
}
std::string Exo_Entity::Load_Attributes(int attr_index)
{
SMART_ASSERT(Check_State());
if (fileId < 0) {
return "exodiff: ERROR: Invalid file id!";
}
if (id_ == EX_INVALID_ID) {
return "exodiff: ERROR: Must initialize block parameters first!";
}
SMART_ASSERT(attr_index >= 0 && attr_index < numAttr);
if ((attributes_[attr_index] == nullptr) && (numEntity != 0u)) {
attributes_[attr_index] = new double[numEntity];
SMART_ASSERT(attributes_[attr_index] != nullptr);
}
if (numEntity != 0u) {
int err = 0;
err = ex_get_one_attr(fileId, exodus_type(), id_, attr_index + 1, attributes_[attr_index]);
if (err < 0) {
Error(fmt::format("Exo_Entity::Load_Attributes(): Call to exodus routine"
" returned error value! {} id = {}\n"
"Aborting...\n",
label(), id_));
}
else if (err > 0) {
return fmt::format("WARNING: Number {} returned from call to exodus get variable routine.",
err);
}
}
else {
return std::string("WARNING: No items in this ") + label();
}
return "";
}
const double *Exo_Entity::Get_Attributes(int attr_index) const
{
SMART_ASSERT(Check_State());
SMART_ASSERT(attr_index >= 0 && attr_index < numAttr);
return attributes_[attr_index];
}
void Exo_Entity::Free_Attributes()
{
SMART_ASSERT(Check_State());
for (int v = 0; v < numAttr; ++v) {
delete[] attributes_[v];
attributes_[v] = nullptr;
}
}
const std::string &Exo_Entity::Get_Attribute_Name(int attr_index) const
{
SMART_ASSERT(attr_index >= 0 && attr_index < numAttr);
return attributeNames[attr_index];
}
int Exo_Entity::Find_Attribute_Index(const std::string &name) const
{
std::string lower_name = name;
to_lower(lower_name);
int indx = -1;
for (int i = 0; i < numAttr; i++) {
if (attributeNames[i] == lower_name) {
indx = i;
break;
}
}
return indx;
}
void Exo_Entity::internal_load_params()
{
int name_size = ex_inquire_int(fileId, EX_INQ_MAX_READ_NAME_LENGTH);
{
std::vector<char> name(name_size + 1);
ex_get_name(fileId, exodus_type(), id_, name.data());
if (name[0] != '\0') {
name_ = name.data();
to_lower(name_);
}
else {
name_ = short_label();
name_ += "_";
name_ += std::to_string(id_);
}
}
numVars = get_num_variables(fileId, exodus_type(), label());
if (numVars != 0) {
results_ = new double *[numVars];
SMART_ASSERT(results_ != nullptr);
for (int i = 0; i < numVars; ++i) {
results_[i] = nullptr;
}
}
numAttr = get_num_attributes(fileId, exodus_type(), id_, label());
if (numAttr != 0) {
attributes_.resize(numAttr);
char **names = get_name_array(numAttr, name_size);
int err = ex_get_attr_names(fileId, exodus_type(), id_, names);
if (err < 0) {
Error(fmt::format(
"ExoII_Read::Get_Init_Data(): Failed to get {} attribute names! Aborting...\n",
label()));
}
for (int vg = 0; vg < numAttr; ++vg) {
SMART_ASSERT(names[vg] != nullptr);
if (std::strlen(names[vg]) == 0) {
std::string name = "attribute_" + std::to_string(vg + 1);
attributeNames.push_back(name);
}
else if (static_cast<int>(std::strlen(names[vg])) > name_size) {
fmt::print(stderr, fmt::fg(fmt::color::red),
"exodiff: ERROR: {} attribute names appear corrupt\n"
" A length is 0 or greater than name_size({})\n"
" Here are the names that I received from"
" a call to ex_get_attr_names(...):\n",
label(), name_size);
for (int k = 1; k <= numAttr; ++k) {
fmt::print(stderr, fmt::fg(fmt::color::red), "\t\t{}) \"{}\"\n", k, names[k - 1]);
}
fmt::print(stderr, fmt::fg(fmt::color::red), " Aborting...\n");
exit(1);
}
else {
std::string n(names[vg]);
to_lower(n);
attributeNames.push_back(n);
}
}
free_name_array(names, numAttr);
}
}
namespace {
size_t get_index(int file_id, EXOTYPE exo_type, size_t id, const char *label)
{
// Get ids...
size_t count = get_num_entities(file_id, exo_type);
if ((ex_int64_status(file_id) & EX_IDS_INT64_API) != 0) {
std::vector<int64_t> ids(count);
ex_get_ids(file_id, exo_type, ids.data());
for (size_t i = 0; i < count; i++) {
if (static_cast<size_t>(ids[i]) == id) {
return i;
}
}
}
else {
std::vector<int> ids(count);
ex_get_ids(file_id, exo_type, ids.data());
for (size_t i = 0; i < count; i++) {
if (static_cast<size_t>(ids[i]) == id) {
return i;
}
}
}
Error(fmt::format("{} id {} does not exist!\n", label, id));
return 0;
}
size_t get_num_entities(int file_id, EXOTYPE exo_type)
{
ex_inquiry inquiry = EX_INQ_INVALID;
switch (exo_type) {
case EX_ELEM_BLOCK: inquiry = EX_INQ_ELEM_BLK; break;
case EX_NODE_SET: inquiry = EX_INQ_NODE_SETS; break;
case EX_SIDE_SET: inquiry = EX_INQ_SIDE_SETS; break;
case EX_EDGE_BLOCK: inquiry = EX_INQ_EDGE_BLK; break;
case EX_FACE_BLOCK: inquiry = EX_INQ_FACE_BLK; break;
default: Error("Invalid entity type in get_num_entities\n");
}
SMART_ASSERT(inquiry != EX_INQ_INVALID);
return ex_inquire_int(file_id, inquiry);
}
size_t get_num_variables(int file_id, EXOTYPE type, const char *label)
{
int num_vars = 0;
int err = ex_get_variable_param(file_id, type, &num_vars);
if (err < 0) {
Error(fmt::format("Failed to get number of '{}' variables! Aborting...\n", label));
}
return num_vars;
}
size_t get_num_attributes(int file_id, EXOTYPE type, size_t id, const char *label)
{
int num_attr = 0;
int err = ex_get_attr_param(file_id, type, id, &num_attr);
if (err < 0) {
Error(fmt::format("Failed to get number of '{}' attributes! Aborting...\n", label));
}
return num_attr;
}
#ifndef NDEBUG
size_t get_num_timesteps(int file_id) { return ex_inquire_int(file_id, EX_INQ_TIME); }
#endif
} // namespace