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.
 
 
 
 
 
 

623 lines
16 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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "exodusII.h"
/*
// Read and EXODUSII database and return a TECPLOT file
*/
void tec(int exoid, const char *filename)
{
void teczone(int, int, int, char *, int, int, int *, int, double **, int, double **, FILE *);
/*
* FIRST, READ THE EXODUS DATA BASE
*/
/*
* Open the output file, if we can
*/
FILE *tecfile = fopen(filename, "w");
if (tecfile == NULL) {
printf("\nCannot open file %s for writing\n\n", filename);
exit(1);
}
/*
* Determine max name size used in database...
*/
int name_size = ex_inquire_int(exoid, EX_INQ_DB_MAX_USED_NAME_LENGTH);
ex_set_max_name_length(exoid, name_size);
/*
* Read database size, get coordinates and connectivity
*/
char title[MAX_LINE_LENGTH + 1];
memset(title, 0, MAX_LINE_LENGTH + 1);
int ndim, nnode, nelem, nblk, nnset, neset;
ex_get_init(exoid, title, &ndim, &nnode, &nelem, &nblk, &nnset, &neset);
double *x[3];
x[0] = x[1] = x[2] = NULL;
char *nameco[3];
for (int i = 0; i < ndim; i++) {
nameco[i] = (char *)malloc((name_size + 1) * sizeof(char));
x[i] = (double *)malloc(nnode * sizeof(double));
}
ex_get_coord_names(exoid, nameco);
if (strlen(nameco[0]) == 0)
strcpy(nameco[0], "X");
if (strlen(nameco[1]) == 0)
strcpy(nameco[1], "Y");
if (ndim > 2)
if (strlen(nameco[2]) == 0)
strcpy(nameco[2], "Z");
ex_get_coord(exoid, x[0], x[1], x[2]);
int *elem_id = (int *)malloc(nblk * sizeof(int));
int *node_per_elem = (int *)malloc(nblk * sizeof(int));
int *elem_per_blk = (int *)malloc(nblk * sizeof(int));
int *attr_per_blk = (int *)malloc(nblk * sizeof(int));
char **elem_type = (char **)malloc(nblk * sizeof(char *));
int **icon = (int **)malloc(nblk * sizeof(int *));
for (int i = 0; i < nblk; i++)
elem_type[i] = (char *)malloc((name_size + 1) * sizeof(char));
ex_get_ids(exoid, EX_ELEM_BLOCK, elem_id);
for (int i = 0; i < nblk; i++) {
ex_get_block(exoid, EX_ELEM_BLOCK, elem_id[i], elem_type[i], &elem_per_blk[i],
&node_per_elem[i], NULL, NULL, &attr_per_blk[i]);
icon[i] = (int *)malloc(elem_per_blk[i] * node_per_elem[i] * sizeof(int));
ex_get_conn(exoid, EX_ELEM_BLOCK, elem_id[i], icon[i], NULL, NULL);
}
/*
* Read time step information
*/
double *time = NULL;
int ntime = ex_inquire_int(exoid, EX_INQ_TIME);
if (ntime > 0) {
time = (double *)malloc(ntime * sizeof(double));
ex_get_all_times(exoid, time);
}
/*
* Read number of nodal variables and save space
*/
int nvar = 0;
ex_get_variable_param(exoid, EX_NODAL, &nvar);
char **varnames = NULL;
double **q = NULL;
if (nvar > 0) {
varnames = (char **)malloc(nvar * sizeof(char *));
q = (double **)malloc(nvar * sizeof(double *));
for (int i = 0; i < nvar; i++) {
varnames[i] = (char *)malloc((name_size + 1) * sizeof(char));
q[i] = (double *)malloc(nnode * sizeof(double));
}
ex_get_variable_names(exoid, EX_NODAL, nvar, varnames);
}
/* /////////////////////////////////////////////////////////////////////
// PROMPT USER FOR INFO AND WRITE TECPLOT FILE
/////////////////////////////////////////////////////////////////////
*/
/*
* Write the TECPLOT header information
*/
assert(strlen(title) < (MAX_LINE_LENGTH + 1));
fprintf(tecfile, "TITLE = \"%s\"\n", title);
fprintf(tecfile, "VARIABLES = ");
for (int i = 0; i < ndim; i++) {
fprintf(tecfile, "\"%s\"", nameco[i]);
if (i < (ndim - 1))
fprintf(tecfile, ", ");
}
if (nvar == 0)
fprintf(tecfile, "\n");
else
fprintf(tecfile, ",\n ");
int idum = 0;
for (int i = 0; i < nvar; i++) {
idum += strlen(varnames[i]);
assert(idum < 1022);
fprintf(tecfile, "\"%s\"", varnames[i]);
if (i < (nvar - 1)) {
if ((i + 1) % 4 == 0) {
idum = 0;
fprintf(tecfile, ",\n ");
}
else
fprintf(tecfile, ", ");
}
}
fprintf(tecfile, "\n");
/*
* Select a time step
*/
int izone = 0;
int itime = 0;
if (ntime == 0) {
printf("\nNo solution variables available, saving mesh only\n\n");
izone = 1;
}
else {
printf("\nTime step information:\n\n");
for (int i = 0; i < ntime; i++)
printf(" Time step %5d, time = %e\n", i + 1, time[i]);
do {
printf("\nSelect time step number to save,\n");
printf(" or 0 for zone animation of all time steps: ");
scanf("%d", &itime);
printf("\n");
} while (itime < 0 || itime > ntime);
printf("\n");
if (itime == 0)
izone = 0;
else
izone = 1;
}
/*
* Write time steps
*/
if (izone == 0) {
/*
* Collapse the zones into one
*/
/*
* Make sure we are using all the same element types
* Create one master connectivity array
*/
for (int i = 1; i < nblk; i++)
if (strcmp(elem_type[0], elem_type[i]) != 0) {
printf("\nCannot create zone animation because\n");
;
printf("\n there are multiple element types.");
exit(1);
}
int *ic = (int *)malloc(nelem * node_per_elem[0] * sizeof(int));
int k = 0;
for (int j = 0; j < nblk; j++)
for (int i = 0; i < node_per_elem[j] * elem_per_blk[j]; i++)
ic[k++] = icon[j][i];
assert(k == nelem * node_per_elem[0]);
if (itime == 0) {
for (int j = 0; j < ntime; j++) {
for (int i = 0; i < nvar; i++) {
ex_get_var(exoid, j + 1, EX_NODAL, i + 1, 1, nnode, q[i]);
}
int i = 0;
teczone(1, nnode, j + 1, elem_type[i], node_per_elem[i], nelem, ic, ndim, x, nvar, q,
tecfile);
}
printf("\n");
}
free(ic);
}
else if (izone == 1) {
/*
|| Write out each zone individually
*/
for (int i = 0; i < nvar; i++)
ex_get_var(exoid, itime, EX_NODAL, i + 1, 1, nnode, q[i]);
for (int i = 0; i < nblk; i++)
teczone(nblk, nnode, elem_id[i], elem_type[i], node_per_elem[i], elem_per_blk[i], icon[i],
ndim, x, nvar, q, tecfile);
printf("\n");
}
/* /////////////////////////////////////////////////////////////////////
// CLEAN UP
/////////////////////////////////////////////////////////////////////
*/
fclose(tecfile);
/*
* Free up allocated memory
*/
for (int i = 0; i < ndim; i++) {
free(nameco[i]);
free(x[i]);
}
free(elem_id);
free(node_per_elem);
free(elem_per_blk);
free(attr_per_blk);
if (elem_type != NULL) {
for (int i = 0; i < nblk; i++) {
free(elem_type[i]);
}
free(elem_type);
}
if (icon != NULL) {
for (int i = 0; i < nblk; i++) {
free(icon[i]);
}
free(icon);
}
if (nvar > 0) {
if (varnames != NULL) {
for (int i = 0; i < nvar; i++) {
free(varnames[i]);
}
free(varnames);
}
if (q != NULL) {
for (int i = 0; i < nvar; i++) {
free(q[i]);
}
free(q);
}
}
}
/*
* Write TECPLOT zonal information
*/
void teczone(int nblk, int nnode, int elem_id, char *elem_type, int node_per_elem, int elem_per_blk,
int *icon, int ndim, double **x, int nvar, double **q, FILE *tecfile)
{
int *ic = NULL;
double *xx[3];
double **qq = NULL;
int *isort = NULL;
int inode;
void internal_heapsort(int *, int);
int hunt(int, int, int *, int *);
int ifac = 1;
if (strcmp(elem_type, "SHELL") == 0) {
ifac = 2;
}
if (strcmp(elem_type, "BAR") == 0) {
ifac = 2;
}
if (strcmp(elem_type, "TRUSS") == 0) {
ifac = 4;
}
#ifdef DEBUG
printf("...in teczone\n");
printf("......elem_type %s\n", elem_type);
printf("......elem_per_blk %d\n", elem_per_blk);
#endif
if (nblk > 1) {
/*
* Create local block connectivity
*/
ic = (int *)malloc(ifac * node_per_elem * elem_per_blk * sizeof(int));
isort = (int *)malloc(node_per_elem * elem_per_blk * sizeof(int));
for (int j = 0; j < node_per_elem * elem_per_blk; j++)
isort[j] = icon[j];
#ifdef DEBUG
printf("...sorting global connectivity\n");
printf("......total nodes %d\n", elem_per_blk * node_per_elem);
#endif
/*
* Sort nodes in this element block
*/
internal_heapsort(isort, node_per_elem * elem_per_blk);
#ifdef DEBUG
printf("...compressing global connectivity\n");
#endif
/*
* Compress node list
*/
inode = 0;
for (int j = 0; j < node_per_elem * elem_per_blk - 1; j++)
if (isort[j] != isort[j + 1])
isort[++inode] = isort[j + 1];
inode++;
#ifdef DEBUG
printf("......found %d unique nodes\n", inode);
printf("...sorting local connectivity\n");
#endif
/*
* Sort local connectivity
*/
int i = (inode + 1) / 2;
for (int k = 0; k < elem_per_blk; k++) {
for (int j = 0; j < node_per_elem; j++) {
int n = k * node_per_elem + j;
int nn = k * ifac * node_per_elem + j;
ic[nn] = hunt(icon[n], inode, isort, &i);
}
if (ifac == 2)
for (int j = 0; j < node_per_elem; j++) {
int nn = k * ifac * node_per_elem + j;
ic[nn + node_per_elem] = ic[nn];
}
else if (ifac == 4)
for (int j = 0; j < node_per_elem; j++) {
int nn = k * ifac * node_per_elem + j;
ic[nn + node_per_elem] = ic[nn + node_per_elem - 1 - j];
ic[nn + 2 * node_per_elem] = ic[nn];
ic[nn + 3 * node_per_elem] = ic[nn + node_per_elem - 1 - j];
}
}
#ifdef DEBUG
printf("...copy local data\n");
#endif
/*
* Copy local data
*/
for (int ii = 0; ii < ndim; ii++)
xx[ii] = (double *)malloc(inode * sizeof(double));
for (int j = 0; j < ndim; j++)
for (int ii = 0; ii < inode; ii++)
xx[j][ii] = x[j][isort[ii] - 1];
if (nvar > 0)
qq = (double **)malloc(nvar * sizeof(double *));
for (int ii = 0; ii < nvar; ii++)
qq[ii] = (double *)malloc(inode * sizeof(double));
for (int j = 0; j < nvar; j++)
for (int ii = 0; ii < inode; ii++)
qq[j][ii] = q[j][isort[ii] - 1];
}
else {
/*
* Copy local block connectivity
*/
if (ifac > 1) {
printf("\nCannot perform zone animation for degenerate elements\n\n");
exit(1);
}
inode = nnode;
ic = icon;
for (int i = 0; i < ndim; i++)
xx[i] = x[i];
if (nvar > 0)
qq = (double **)malloc(nvar * sizeof(double *));
for (int i = 0; i < nvar; i++)
qq[i] = q[i];
}
#ifdef DEBUG
printf("...writing zone data\n");
#endif
/*
* Write zone data
*/
printf(" Writing Zone %4d, %8s, %6d elements, %6d nodes\n", elem_id, elem_type, elem_per_blk,
inode);
char zname[80];
char eltype[16];
snprintf(zname, 80, "Zone %s_%d", elem_type, elem_id);
if (ndim == 3 && (node_per_elem == 8 || (node_per_elem == 4 && ifac == 2) ||
(node_per_elem == 2 && ifac == 4)))
snprintf(eltype, 16, "BRICK");
else if (ndim == 3 && node_per_elem == 4)
snprintf(eltype, 16, "TETRAHEDRON");
else if (ndim == 2 && (node_per_elem == 4 || (node_per_elem == 2 && ifac == 2)))
snprintf(eltype, 16, "QUADRILATERAL");
else if (ndim == 2 && node_per_elem == 3)
snprintf(eltype, 16, "TRIANGLE");
else {
printf("\nBad element type found in teczone\n");
printf(" Dimensions = %d\n", ndim);
printf(" Nodes = %d\n", node_per_elem);
exit(1);
}
fprintf(tecfile, "ZONE T=\"%s\", F=FEBLOCK, ET=%s,\n", zname, eltype);
fprintf(tecfile, " N=%d, E=%d\n", inode, elem_per_blk);
#define CHUNK 8
for (int j = 0; j < ndim; j++) {
for (int i = 0; i < inode / CHUNK; i++) {
for (int k = 0; k < CHUNK; k++)
fprintf(tecfile, "%.16f ", xx[j][i * CHUNK + k]);
fprintf(tecfile, "\n");
}
if (inode % CHUNK != 0) {
for (int i = CHUNK * (inode / CHUNK); i < inode; i++)
fprintf(tecfile, "%.16f ", xx[j][i]);
fprintf(tecfile, "\n");
}
}
for (int j = 0; j < nvar; j++) {
for (int i = 0; i < inode / CHUNK; i++) {
for (int k = 0; k < CHUNK; k++)
fprintf(tecfile, "%.16f ", qq[j][i * CHUNK + k]);
fprintf(tecfile, "\n");
}
if (inode % CHUNK != 0) {
for (int i = CHUNK * (inode / CHUNK); i < inode; i++)
fprintf(tecfile, "%.16f ", qq[j][i]);
fprintf(tecfile, "\n");
}
}
for (int i = 0; i < elem_per_blk; i++) {
for (int j = 0; j < ifac * node_per_elem; j++) {
int k = ic[i * ifac * node_per_elem + j];
fprintf(tecfile, "%d ", k);
}
fprintf(tecfile, "\n");
}
#ifdef DEBUG
printf("...freeing allocated space\n");
#endif
if (nblk > 1) {
free(ic);
free(isort);
for (int i = 0; i < ndim; i++)
free(xx[i]);
if (qq != NULL) {
for (int i = 0; i < nvar; i++)
free(qq[i]);
if (nvar > 0)
free(qq);
}
}
else {
if (nvar > 0)
free(qq);
}
}
void siftDown(int *a, int start, int count);
#define SWAP(r, s) \
do { \
int t = r; \
r = s; \
s = t; \
} while (0)
void internal_heapsort(int *a, int count)
{
/* heapify */
for (int start = (count - 2) / 2; start >= 0; start--) {
siftDown(a, start, count);
}
for (int end = count - 1; end > 0; end--) {
SWAP(a[end], a[0]);
siftDown(a, 0, end);
}
}
void siftDown(int *a, int start, int end)
{
int root = start;
while (root * 2 + 1 < end) {
int child = 2 * root + 1;
if ((child + 1 < end) && (a[child] < a[child + 1])) {
child += 1;
}
if (a[root] < a[child]) {
SWAP(a[child], a[root]);
root = child;
}
else
return;
}
}
/*
* Bisection search with binary hunt,
* from Numerical Recipes
*/
int hunt(int node, int n, int *key, int *iguess)
{
if (node == key[*iguess - 1])
return *iguess;
int i = *iguess;
int inc = 1;
int j = 0;
if (node > key[i - 1]) { /* hunt up */
if (i == n) {
printf("\nError in HUNT: node is outside range of table\n");
printf(" requested node = %d\n", node);
printf(" last in table = %d\n", key[n - 1]);
exit(1);
}
j = i + 1;
while (node > key[j - 1]) {
i = j;
inc += inc;
j = i + inc;
if (j > n) {
j = n;
break;
}
}
if (node == key[j - 1]) {
*iguess = j;
return j;
}
}
else if (node < key[i - 1]) { /* hunt down */
if (i == 1) {
printf("\nError in HUNT: node is outside range of table\n");
printf(" requested node = %d\n", node);
printf(" first in table = %d\n", key[0]);
exit(1);
}
j = i;
i -= 1;
while (node < key[i - 1]) {
j = i;
inc += inc;
i = j - inc;
if (i < 1) {
i = 1;
break;
}
}
if (node == key[i - 1]) {
*iguess = i;
return i;
}
}
int k = (i + j) / 2;
while (node != key[k - 1]) {
if (key[k - 1] > node) {
j = k;
k = (i + j) / 2;
}
else {
i = k;
k = (i + j + 1) / 2;
}
}
*iguess = k;
return k;
}