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
17 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 <exodusII.h> // for ex_close, ex_inquire, etc
#include <algorithm>
#include <cassert>
#include <copy_string_cpp.h>
#include <cstddef> // for size_t
#include <cstdio> // for nullptr
#include <cstdlib> // for malloc, free, calloc
#include <cstring> // for strlen
#include <fmt/ostream.h>
#include <string>
#include <vector>
#include "elb.h" // for Weight_Description<INT>, etc
#include "elb_elem.h" // for get_elem_type, E_Type, etc
#include "elb_err.h" // for Gen_Error, MAX_ERR_MSG
#include "elb_exo.h"
#include "elb_groups.h" // for parse_groups
#include "elb_util.h" // for in_list, roundfloat
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/* Function read_exo_weights() begins:
*----------------------------------------------------------------------------
* This function reads the nodal or elemental values from an ExodusII file
* which will be used by Chaco for weighting of the graph.
*****************************************************************************/
template int read_exo_weights(Problem_Description *prob, Weight_Description<int> *weight);
template int read_exo_weights(Problem_Description *prob, Weight_Description<int64_t> *weight);
template <typename INT>
int read_exo_weights(Problem_Description *prob, Weight_Description<INT> *weight)
{
int exoid;
/*---------------------------Execution Begins--------------------------------*/
/* Open the ExodusII file containing the weights */
int mode = EX_READ | prob->int64api;
int cpu_ws = 0;
int io_ws = 0;
float version;
if ((exoid = ex_open(weight->exo_filename.c_str(), mode, &cpu_ws, &io_ws, &version)) < 0) {
std::string ctemp = fmt::format("fatal: could not open ExodusII file {}", weight->exo_filename);
Gen_Error(0, ctemp);
return 0;
}
std::vector<float> values(weight->nvals);
if (prob->type == NODAL) {
size_t tmp_nodes = ex_inquire_int(exoid, EX_INQ_NODES);
/* check to make sure the sizes agree */
if ((size_t)weight->nvals != tmp_nodes) {
Gen_Error(0, "fatal: different number of nodes in mesh and weight files");
ex_close(exoid);
return 0;
}
weight->ow.resize(weight->nvals);
/* Read in the nodal values */
if (ex_get_var(exoid, weight->exo_tindx, EX_NODAL, weight->exo_vindx, 1, weight->nvals,
values.data()) < 0) {
Gen_Error(0, "fatal: unable to read nodal values");
ex_close(exoid);
return 0;
}
}
else {
size_t tmp_elem = ex_inquire_int(exoid, EX_INQ_ELEM);
/* check to make sure the sizes agree */
if ((size_t)weight->nvals != tmp_elem) {
Gen_Error(0, "fatal: different number of elems in mesh and weight files");
ex_close(exoid);
return 0;
}
/* Get the number of element blocks */
int neblks = ex_inquire_int(exoid, EX_INQ_ELEM_BLK);
std::vector<INT> eblk_ids(neblks);
std::vector<INT> eblk_ecnts(neblks);
if (ex_get_ids(exoid, EX_ELEM_BLOCK, eblk_ids.data()) < 0) {
Gen_Error(0, "fatal: unable to get element block IDs");
ex_close(exoid);
return 0;
}
/* Get the count of elements in each element block */
for (int cnt = 0; cnt < neblks; cnt++) {
INT dum1;
INT dum2;
char elem_type[MAX_STR_LENGTH + 1];
if (ex_get_block(exoid, EX_ELEM_BLOCK, eblk_ids[cnt], elem_type, &(eblk_ecnts[cnt]), &dum1,
nullptr, nullptr, &dum2) < 0) {
Gen_Error(0, "fatal: unable to get element block");
ex_close(exoid);
return 0;
}
}
/* Get the element variables */
size_t offset = 0;
for (int cnt = 0; cnt < neblks; cnt++) {
if (ex_get_var(exoid, weight->exo_tindx, EX_ELEM_BLOCK, weight->exo_vindx, eblk_ids[cnt],
eblk_ecnts[cnt], &(values[offset])) < 0) {
Gen_Error(0, "fatal: unable to get element variable");
ex_close(exoid);
return 0;
}
offset += eblk_ecnts[cnt];
}
}
/* Close the ExodusII weighting file */
if (ex_close(exoid) < 0) {
std::string ctemp =
fmt::format("warning: failed to close ExodusII file {}", weight->exo_filename);
Gen_Error(0, ctemp);
}
/* now I need to translate the values to positive integers */
/* first find the minimum value */
float minval = *std::min_element(values.begin(), values.end());
/* now translate the values to be greater than 1 and convert to ints */
for (int cnt = 0; cnt < weight->nvals; cnt++) {
values[cnt] += 1.0f - minval;
weight->vertices[cnt] = roundfloat(values[cnt]);
}
return 1;
} /*------------------------End read_exo_weights()----------------------*/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/* Function read_mesh_params() begins:
*----------------------------------------------------------------------------
* This function reads in information about the finite element mesh.
*****************************************************************************/
template int read_mesh_params(const std::string &exo_file, Problem_Description *problem,
Mesh_Description<int> *mesh, Sphere_Info *sphere);
template int read_mesh_params(const std::string &exo_file, Problem_Description *problem,
Mesh_Description<int64_t> *mesh, Sphere_Info *sphere);
template <typename INT>
int read_mesh_params(const std::string &exo_file, Problem_Description *problem,
Mesh_Description<INT> *mesh, Sphere_Info *sphere)
{
int exoid;
int cpu_ws = 0;
int io_ws = 0;
float version;
char elem_type[MAX_STR_LENGTH + 1];
/*---------------------------Execution Begins--------------------------------*/
/* Open the ExodusII geometry file */
int mode = EX_READ | problem->int64api;
if ((exoid = ex_open(exo_file.c_str(), mode, &cpu_ws, &io_ws, &version)) < 0) {
Gen_Error(0, "fatal: unable to open ExodusII file for mesh params");
return 0;
}
/* Get the init info */
ex_init_params exo{};
if (ex_get_init_ext(exoid, &exo)) {
Gen_Error(0, "fatal: unable to get init info from ExodusII file");
ex_close(exoid);
return 0;
}
copy_string(mesh->title, exo.title);
mesh->num_dims = exo.num_dim;
mesh->num_nodes = exo.num_nodes;
mesh->num_elems = exo.num_elem;
mesh->num_el_blks = exo.num_elem_blk;
mesh->num_node_sets = exo.num_node_sets;
mesh->num_side_sets = exo.num_side_sets;
/* Read the element block IDs */
mesh->eb_ids.resize(mesh->num_el_blks);
mesh->eb_cnts.resize(mesh->num_el_blks);
mesh->eb_npe.resize(mesh->num_el_blks);
mesh->eb_type.resize(mesh->num_el_blks);
if (ex_get_ids(exoid, EX_ELEM_BLOCK, mesh->eb_ids.data()) < 0) {
Gen_Error(0, "fatal: unable to get element block IDs");
ex_close(exoid);
return 0;
}
/* Get the length of the concatenated node set node list */
if (mesh->num_node_sets > 0) {
mesh->ns_list_len = ex_inquire_int(exoid, EX_INQ_NS_NODE_LEN);
}
else {
mesh->ns_list_len = 0;
}
/* Allocate and initialize memory for the sphere adjustment */
sphere->adjust.resize(mesh->num_el_blks);
sphere->begin.resize(mesh->num_el_blks);
sphere->end.resize(mesh->num_el_blks);
/* Determine the maximum number of nodes per element */
mesh->max_np_elem = 0;
for (size_t cnt = 0; cnt < mesh->num_el_blks; cnt++) {
INT nodes_in_elem;
if (ex_get_block(exoid, EX_ELEM_BLOCK, mesh->eb_ids[cnt], elem_type, &(mesh->eb_cnts[cnt]),
&nodes_in_elem, nullptr, nullptr, nullptr) < 0) {
Gen_Error(0, "fatal: unable to get element block");
ex_close(exoid);
return 0;
}
if (mesh->eb_cnts[cnt] == 0) {
continue;
}
mesh->eb_npe[cnt] = nodes_in_elem;
mesh->eb_type[cnt] = get_elem_type(elem_type, nodes_in_elem, mesh->num_dims);
if (cnt == 0) {
sphere->end[0] = mesh->eb_cnts[cnt];
}
if (mesh->eb_type[cnt] == SPHERE && problem->no_sph != 1) {
sphere->num += mesh->eb_cnts[cnt];
sphere->adjust[cnt] = 0;
}
else {
sphere->adjust[cnt] = sphere->num;
}
if (cnt != 0) {
sphere->begin[cnt] = sphere->end[cnt - 1];
sphere->end[cnt] = sphere->begin[cnt] + mesh->eb_cnts[cnt];
}
mesh->max_np_elem = MAX(mesh->max_np_elem, (size_t)nodes_in_elem);
}
/* Close the ExodusII file */
if (ex_close(exoid) < 0) {
Gen_Error(1, "warning: unable to close ExodusII file");
}
fmt::print("ExodusII mesh information\n");
if (strlen(mesh->title) > 0) {
fmt::print("\ttitle: {}\n", mesh->title);
}
fmt::print("\tgeometry dimension: {}\n", mesh->num_dims);
fmt::print("\tnumber of nodes: {}\tnumber of elements: {}\n", fmt::group_digits(mesh->num_nodes),
fmt::group_digits(mesh->num_elems));
fmt::print("\tnumber of element blocks: {}\n", mesh->num_el_blks);
fmt::print("\tnumber of node sets: {}\tnumber of side sets: {}\n", mesh->num_node_sets,
mesh->num_side_sets);
return 1;
} /*--------------------------End read_mesh_params()-------------------------*/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/* Function read_mesh_params() begins:
*----------------------------------------------------------------------------
* This function reads in the finite element mesh.
*****************************************************************************/
template int read_mesh(const std::string &exo_file, Problem_Description *problem,
Mesh_Description<int> *mesh, Weight_Description<int> *weight);
template int read_mesh(const std::string &exo_file, Problem_Description *problem,
Mesh_Description<int64_t> *mesh, Weight_Description<int64_t> *weight);
template <typename INT>
int read_mesh(const std::string &exo_file, Problem_Description *problem,
Mesh_Description<INT> *mesh, Weight_Description<INT> *weight)
{
float version;
float *xptr;
float *yptr;
float *zptr;
/*---------------------------Execution Begins--------------------------------*/
/* Open the ExodusII file */
int exoid;
int cpu_ws = 0;
int io_ws = 0;
int mode = EX_READ | problem->int64api;
if ((exoid = ex_open(exo_file.c_str(), mode, &cpu_ws, &io_ws, &version)) < 0) {
Gen_Error(0, "fatal: unable to open ExodusII mesh file");
return 0;
}
/* Read the coordinates, if desired */
xptr = yptr = zptr = nullptr;
if (problem->read_coords == ELB_TRUE) {
switch (mesh->num_dims) {
case 3: zptr = mesh->coords.data() + 2 * (mesh->num_nodes); FALL_THROUGH;
case 2: yptr = mesh->coords.data() + (mesh->num_nodes); FALL_THROUGH;
case 1: xptr = mesh->coords.data();
}
if (ex_get_coord(exoid, xptr, yptr, zptr) < 0) {
Gen_Error(0, "fatal: unable to read coordinate values for mesh");
return 0;
}
} /* End "if(problem->read_coords == ELB_TRUE)" */
/* Read the element connectivity */
size_t gelem_cnt = 0;
for (size_t cnt = 0; cnt < mesh->num_el_blks; cnt++) {
if (mesh->eb_cnts[cnt] == 0) {
continue;
}
std::vector<INT> blk_connect(mesh->eb_cnts[cnt] * mesh->eb_npe[cnt]);
/* Get the connectivity for this element block */
if (ex_get_conn(exoid, EX_ELEM_BLOCK, mesh->eb_ids[cnt], blk_connect.data(), nullptr, nullptr) <
0) {
Gen_Error(0, "fatal: failed to get element connectivity");
return 0;
}
/* find out if this element block is weighted */
int wgt = -1;
if (weight->type & EL_BLK) {
wgt = in_list(mesh->eb_ids[cnt], weight->elemblk);
}
/* Fill the 2D global connectivity array */
if (((problem->type == ELEMENTAL) && (weight->type & EL_BLK)) ||
((problem->type == NODAL) && (weight->type & EL_BLK))) {
for (int64_t cnt2 = 0; cnt2 < mesh->eb_cnts[cnt]; cnt2++) {
mesh->elem_type[gelem_cnt] = mesh->eb_type[cnt];
/* while going through the blocks, take care of the weighting */
if ((problem->type == ELEMENTAL) && (weight->type & EL_BLK)) {
/* is this block weighted */
if (wgt >= 0) {
/* check if there is a read value */
if (weight->vertices[gelem_cnt] >= 1) {
/* and if it should be overwritten */
if (weight->ow_read) {
weight->vertices[gelem_cnt] = weight->elemblk_wgt[wgt];
}
}
else {
weight->vertices[gelem_cnt] = weight->elemblk_wgt[wgt];
}
}
else {
/* now check if this weight has been initialized */
if (weight->vertices[gelem_cnt] < 1) {
weight->vertices[gelem_cnt] = 1;
}
}
}
for (int64_t cnt3 = 0; cnt3 < mesh->eb_npe[cnt]; cnt3++) {
INT node = blk_connect[cnt3 + cnt2 * mesh->eb_npe[cnt]] - 1;
assert(node >= 0);
mesh->connect[gelem_cnt][cnt3] = node;
/* deal with the weighting if necessary */
if ((problem->type == NODAL) && (weight->type & EL_BLK)) {
/* is this block weighted */
if (wgt >= 0) {
/* check if I read an exodus file */
if (weight->type & READ_EXO) {
/* check if it can be overwritten */
if (weight->ow_read) {
/* check if it has been overwritten already */
if (weight->ow[node]) {
weight->vertices[node] = MAX(weight->vertices[node], weight->elemblk_wgt[wgt]);
}
else {
weight->vertices[node] = weight->elemblk_wgt[wgt];
weight->ow[node] = 1; /* read value has been overwritten */
}
}
}
else {
weight->vertices[node] = MAX(weight->vertices[node], weight->elemblk_wgt[wgt]);
}
}
else {
/* now check if this weight has been initialized */
if (weight->vertices[node] < 1) {
weight->vertices[node] = 1;
}
}
}
}
gelem_cnt++;
}
}
else {
// No weights...
for (int64_t cnt2 = 0; cnt2 < mesh->eb_cnts[cnt]; cnt2++) {
mesh->elem_type[gelem_cnt] = mesh->eb_type[cnt];
for (int64_t cnt3 = 0; cnt3 < mesh->eb_npe[cnt]; cnt3++) {
INT node = blk_connect[cnt2 * mesh->eb_npe[cnt] + cnt3] - 1;
assert(node >= 0);
mesh->connect[gelem_cnt][cnt3] = node;
}
gelem_cnt++;
}
}
} /* End "for(cnt=0; cnt < mesh->num_el_blks; cnt++)" */
/* if there is a group designator, then parse it here */
if (problem->groups != nullptr) {
if (!parse_groups(mesh, problem)) {
Gen_Error(0, "fatal: unable to parse group designator");
ex_close(exoid);
return 0;
}
}
else {
problem->num_groups = 1; /* there is always one group */
}
/* Close the ExodusII file */
if (ex_close(exoid) < 0) {
Gen_Error(0, "warning: failed to close ExodusII mesh file");
}
return 1;
} /*---------------------------End read_mesh()-------------------------------*/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/* Function init_weight_struct() begins:
*----------------------------------------------------------------------------
* This function initializes the weight structure given the current mesh.
*****************************************************************************/
template int init_weight_struct(Problem_Description *problem, Mesh_Description<int> *mesh,
Weight_Description<int> *weight);
template int init_weight_struct(Problem_Description *problem, Mesh_Description<int64_t> *mesh,
Weight_Description<int64_t> *weight);
template <typename INT>
int init_weight_struct(Problem_Description *problem, Mesh_Description<INT> *mesh,
Weight_Description<INT> *weight)
{
if (problem->type == NODAL) {
weight->nvals = mesh->num_nodes;
}
else {
weight->nvals = mesh->num_elems;
}
/* Allocate memory */
weight->vertices.resize(weight->nvals);
return 1;
} /*-----------------------End init_weight_struct()--------------------------*/