/*! $Id: elio.c,v 1.60 2012/02/07 19:19:01 pturner Exp $
*
* I/O routines for new file format - pturner 11-2002
*
*/
/*! \mainpage ELIO - Interface to ELCIRC data files.
**
** \section intro Introduction
**
** The ELIO library provides a C-programming language interface to output files generated by ELCIRC. The CVS repository is 'ace/elio' - use:
cvs checkout ace/elio
to get the elio source code as well as the sources for other utilities using the elio library. These codes are documented at the URL:
http://amb1019.ccalmr.ogi.edu/doc/codes
**
** \section use Building your programs.
**
** Makefile
#
# Sample Makefile for use of libelio.a.
#
# \$Revision\$
# \$Log\$
#
#
INSTALLDIR = /usr/local/ace
OBJS = testel.o
# -miee for alphas
# CFLAGS = -mieee
# for intel
CFLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
LIB = /usr/local/ace/lib
CC = gcc -g
testel: testel.o
\$(CC) \$(CFLAGS) -g testel.c -L\$(LIB) -lelio -lm -o testel
**
** \section examp Example of use.
**
** The following code reads the header from a data file and prints out a
** summary of what is seen using the ElioPrintHeader() function.
**
// ginfo.c example program - pturner.
//
// \$Revision\$
//
// \$Log\$
//
\#include
\#include
\#include
\#include "elio.h"
int main(int argc, char **argv)
{
char iname[1024];
FILE *fp;
ElcircHeader h;
int err;
if (argc != 2) {
fprintf(stderr, "Usage: \%s \\n", argv[0]);
exit(1);
}
strcpy(iname, argv[1]);
// check that file type is correct
if ((fp = fopen(iname, "rb")) == NULL) {
fprintf(stderr, "\%s: Unable to open file \%s.\\n", argv[0], iname);
exit(1);
}
if (ElioGetFileType(fp) < 2) {
fprintf(stderr, "\%s: Incorrect file type for file \%s.\\n", argv[0], iname);
exit(1);
}
fclose(fp);
// Get the header
if ((err = ElioGetHeader(iname, &h)) != ELIO_OK) {
fprintf(stderr, "\%s: Error in call to GetElcircHeader(), error # \%d.\\n", argv[0], err);
exit(1);
}
ElioPrintHeader(&h);
printf("Number of steps in file: \%d\\n", ElioGetNStepsInFile(iname, &h));
ElioFreeHeader(&h);
}
Makefile for ginfo.c
#
# Sample Makefile for use of libelio.a.
#
# \$Revision\$
# \$Log\$
#
# -miee for alphas
# CFLAGS = -mieee
# for intel
CFLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
LIB = /usr/local/ace/lib
CC = gcc -g
ginfo: ginfo.o
\$(CC) \$(CFLAGS) -g ginfo.c -L\$(LIB) -lelio -lm -o ginfo
**
**/
#include
#include
#include
#include
#include
#include
#include "elio.h"
/*!
* @def WIN32
*
* Windows differences, if true, fix things up for cygwin and Visual C++.
*
*/
#ifdef WIN32
#include
#define off_t long
#define fseeko fseek
#define ftello ftell
#endif
/*!
* Error codes, line numbers, not used right now.
*/
int ElioErr = 0;
int ElioSysErr = 0;
int ElioLineErr = 0;
/*!
* Free memory allocated by a previous call to ElioGetHeader()
* Calling this on an unallocated Header will likely result
* in a seg fault.
*/
void ElioFreeHeader(ElcircHeader * h)
{
free(h->zcor);
free(h->x);
free(h->y);
free(h->d);
free(h->etype);
free(h->icon[0]);
free(h->icon[1]);
free(h->icon[2]);
if (h->v == 3) {
free(h->icon[3]);
}
if (h->v != 4) {
free(h->bi);
free(h->bisave);
}
free(h->no);
}
/*!
* Free a previously allocated time step.
*/
void ElioFreeTimeStep(ElcircTimeStep * t)
{
if (t->e != NULL) {
free(t->e);
}
if (t->surfind != NULL) {
free(t->surfind);
}
free(t->d);
}
/*!
* Allocate memory for a time step given information in a valid
* ElcircHeader.
*
* Returns ELIO_ERR on failure after cleaning up any current allocations.
* Returns ELIO_OK on success.
*/
int ElioAllocateTimeStep(ElcircHeader * h, ElcircTimeStep * t)
{
switch (h->v) {
case 2:
case 3:
t->surfind = (int *) malloc(h->np * sizeof(int));
t->d = (float *) malloc(h->nitems * sizeof(float));
t->e = (float *) NULL;
if (t->surfind == NULL || t->d == NULL) {
return ELIO_ERR;
}
break;
case 4:
case 5:
t->surfind = (int *) malloc(h->np * sizeof(int));
t->e = (float *) malloc(h->np * sizeof(float));
t->d = (float *) malloc(h->nitems * sizeof(float));
if (t->e == NULL || t->d == NULL) {
return ELIO_ERR;
}
break;
}
return ELIO_OK;
}
/*!
* Print header information from a valid ElcircHeader struct.
*
* \param h = Previously filled in ElcircHeader.
*
*/
void ElioPrintHeader(ElcircHeader * h)
{
int i;
printf("Magic: %s\n", h->magic);
printf("Version: %s\n", h->version);
printf("Start Time: %s\n", h->start_time);
printf("Variable Name: %s\n", h->variable_nm);
printf("Variable Dim: %s\n", h->variable_dim);
printf("Number of Steps: %d\n", h->nsteps);
printf("Time Step: %f\n", h->timestep);
printf("Skip Steps: %d\n", h->skip);
printf("Variable Type: %d\n", h->ivs);
printf("Variable Dimension: %d\n", h->i23d);
switch (h->v) {
case 2:
case 3:
printf("Data is Z Level\n");
printf("Vertical position: %f\n", h->vpos);
printf("Z of MSL: %f\n", h->zmsl);
printf("Number of Vertical Levels: %d\n", h->nvrt);
printf("Levels:\n");
for (i = 0; i < h->nvrt; i++) {
printf(" %02d: %f\n", i, h->zcor[i]);
}
break;
case 4:
printf("Data is Sigma Level\n");
printf("ivcor: %d\n", h->ivcor);
printf("h0: %f\n", h->h0);
printf("hc: %f\n", h->hc);
printf("Theta b: %f\n", h->thetab);
printf("Theta f: %f\n", h->thetaf);
printf("Number of Sigma Levels: %d\n", h->nvrt);
printf("Levels:\n");
for (i = 0; i < h->nvrt; i++) {
printf(" %02d: %f\n", i, h->zcor[i]);
}
break;
case 5:
printf("Data is Sigma+Z\n");
printf("Total number of Levels: %d\n", h->nvrt);
printf("Sigma levels ks: %d\n", h->ks);
printf("Z levels kz: %d\n", h->kz);
printf("h0: %f\n", h->h0);
printf("hs: %f\n", h->hs);
printf("hc: %f\n", h->hc);
printf("Theta b: %f\n", h->thetab);
printf("Theta f: %f\n", h->thetaf);
printf("Levels:\n");
for (i = 0; i < h->nvrt; i++) {
printf(" %02d: %f\n", i, h->zcor[i]);
}
break;
default:
printf("Vertical position: %f\n", h->vpos);
printf("Z of MSL: %f\n", h->zmsl);
printf("Number of Vertical Levels: %d\n", h->nvrt);
printf("Levels:\n");
for (i = 0; i < h->nvrt; i++) {
printf(" %02d: %f\n", i, h->zcor[i]);
}
break;
}
printf("Number of Floats/Step: %d\n", h->nitems);
printf("Header Size (bytes): %d\n", h->hsize);
printf("Time Step Size (bytes): %d\n", h->ssize);
printf("Number of Nodes: %d\n", h->np);
printf("Number of Elements: %d\n", h->ne);
printf("Internal version number: %d\n", h->v);
printf("First Node: 1 -> %f, %f, %f\n", h->x[0], h->y[0], h->d[0]);
printf("First Element: 1 -> %d, %d, %d\n", h->icon[0][0], h->icon[1][0], h->icon[2][0]);
printf("Last Node: %d -> %f, %f, %f\n", h->np, h->x[h->np - 1], h->y[h->np - 1], h->d[h->np - 1]);
printf("Last Element: %d -> %d, %d, %d\n", h->ne, h->icon[0][h->ne - 1], h->icon[1][h->ne - 1], h->icon[2][h->ne - 1]);
}
/*!
* ElioGetTimeStep: Read data for a single time step.
*
* Input variables:
*
* \param fp = Open file handle.
* \param step = Time step to read starting from 0 to nsteps - 1.
* \param h = Valid ElcircHeader struct.
*
* Output Variables:
*
* \param t = Valid ElcircTimeStep.
*
* On success returns ELIO_OK.
*
* On failure, returns ELIO_FSEEK_ERR or ELIO_FREAD_ERR depending
* on the nature of the error.
*/
int ElioGetTimeStep(FILE * fp, int step, ElcircHeader * h, ElcircTimeStep * t)
{
off_t skip;
int i, n;
short *b;
skip = (off_t) h->hsize + (off_t) step *(off_t) h->ssize;
if (fseeko(fp, skip, SEEK_SET)) {
return ELIO_FSEEK_ERR;
}
if (fread(&t->t, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&t->it, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (h->v == 4 || h->v == 5) {
if (fread(t->e, sizeof(float), h->np, fp) != h->np)
return ELIO_FREAD_ERR;
for (i = 0; i < h->np; i++) {
t->surfind[i] = h->nvrt;
}
} else {
if (fread(t->surfind, sizeof(int), h->np, fp) != h->np)
return ELIO_FREAD_ERR;
t->e = (float *) NULL;
}
if ((n = fread(t->d, sizeof(float), h->nitems, fp)) != h->nitems) {
return ELIO_FREAD_ERR;
}
/*
printf("Completed Read of Time Step (%d): Time, Step = %f, %d\n", step, t->t, t->it);
*/
return ELIO_OK;
}
/*!
* Returns the Z positions of the vertical given the elevation, e. Also
* the bottom and surface indexes in i1 and i2. Array Zpos1 is returned
* with the valid z values. Only values from zpos1[i1] through zpos[i2]
* contain valid data.
*/
int ElioGetZPos(ElcircHeader * h, double d, double e, int *i1, int *i2, double *zpos1)
{
int i, ilev1 = 0, ilev2 = 0;
for (i = 0; i < h->nvrt; i++) {
zpos1[i] = -h->zmsl + h->zcor[i];
}
ilev1 = 0;
while (-d >= zpos1[ilev1] && ilev1 < h->nvrt) {
ilev1++;
}
zpos1[ilev1] = (-d);
ilev2 = h->nvrt - 1;
while (e <= zpos1[ilev2] && ilev2 > 0) {
ilev2--;
}
ilev2++;
zpos1[ilev2] = e;
*i1 = ilev1;
*i2 = ilev2;
return ELIO_OK;
}
/*!
* Return the surface index for a node.
*
* Input variables:
*
* \param fp = Open file handle
* \param node = node number starting from 0.
* \param step = Time step index starting from 0.
* \param h = Valid ElcircHeader struct.
*/
int ElioGetNodeSurfaceIndex(FILE * fp, int node, int step, ElcircHeader * h)
{
off_t skip;
int retval = -1;
int ti;
if (node >= h->np || node < 0) {
return retval;
}
skip = (off_t) h->hsize + (off_t) step *(off_t) h->ssize + (off_t) 8 + (off_t) (node * 4);
if (fseeko(fp, skip, SEEK_SET)) {
return ELIO_FSEEK_ERR;
}
if (fread(&ti, sizeof(int), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
return ti;
}
/*!
* Return data for a single node from one time step.
*
* Input variables:
*
* \param fp = Open file handle.
* \param step = Time step to read starting from 0.
* \param node = Node to read starting from 0.
* \param h = Valid ElcircHeader struct.
*
* Output Variables:
*
* \param t = Pointer to the time for this time step, float.
* \param it = Pointer to the current computational time step, integer.
* \param bind = Pointer to the bottom index starting from 0.
* \param sind = Pointer to the surface index starting from 0.
* \param d = Pointer to an array of float values, with valid data from
* d[bind] through d[sind].
*
* Returns ELIO_OK on success.
* Returns ELIO_FSEEK_ERR or ELIO_FREAD_ERR on error.
*
*/
int ElioGetNode(FILE * fp, int step, int node, ElcircHeader * h, float *t, int *it, int *bind, int *sind, float *d)
{
int i, npts, itmp;
float e;
off_t skip;
*bind = h->bi[node];
if (h->i23d == 3) { /* 3d data */
skip = (off_t) h->hsize + (off_t) step *(off_t) h->ssize;
if (fseeko(fp, skip, SEEK_SET)) { /* Read time, it, and sind */
return ELIO_FSEEK_ERR;
}
if (fread(t, sizeof(float), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
if (fread(it, sizeof(int), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
if (h->v == 4) {
itmp = h->nvrt;
*bind = 0;
if (fseeko(fp, node * 4L, SEEK_CUR)) { /* elevation */
return ELIO_FSEEK_ERR;
}
if (fread(&e, sizeof(float), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
} else if (h->v == 5) {
itmp = h->nvrt;
if (fseeko(fp, node * 4L, SEEK_CUR)) { /* elevation */
return ELIO_FSEEK_ERR;
}
if (fread(&e, sizeof(float), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
} else {
if (fseeko(fp, node * 4L, SEEK_CUR)) { /* sind */
return ELIO_FSEEK_ERR;
}
if (fread(&itmp, sizeof(int), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
}
*sind = itmp - 1;
npts = (h->nvrt - h->bi[node]) * h->ivs; /* number of points to read for this node */
if (fseeko(fp, skip + (off_t) ((2 + h->np + h->no[node]) * 4), SEEK_SET)) { /* skip time, it, and the surf indexes */
return ELIO_FSEEK_ERR;
}
if (fread(d, sizeof(float), npts, fp) != npts) {
return ELIO_FREAD_ERR;
}
} else if (h->i23d == 2) { /* 2d data - just one or 2 values to read */
skip = (off_t) h->hsize + (off_t) step *(off_t) h->ssize;
if (fseeko(fp, skip, SEEK_SET)) { /* Read time, it, and sind */
return ELIO_FSEEK_ERR;
}
if (fread(t, sizeof(float), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
if (fread(it, sizeof(int), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
if (h->v == 4) {
itmp = h->nvrt;
*bind = 0;
if (fseeko(fp, node * 4L, SEEK_CUR)) { /* elevation */
return ELIO_FSEEK_ERR;
}
if (fread(&e, sizeof(float), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
} else if (h->v == 5) {
itmp = h->nvrt;
if (fseeko(fp, node * 4L, SEEK_CUR)) { /* elevation */
return ELIO_FSEEK_ERR;
}
if (fread(&e, sizeof(float), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
} else {
if (fseeko(fp, node * 4L, SEEK_CUR)) { /* Read time, it, and sind */
return ELIO_FSEEK_ERR;
}
if (fread(&itmp, sizeof(int), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
}
*sind = itmp - 1;
npts = h->ivs; /* number of points to read for this node */
if (fseeko(fp, skip + (off_t) (2L + h->np) * 4L + (off_t) (npts * node * 4L), SEEK_SET)) { /* skip time, it, and the surf indexes */
return ELIO_FSEEK_ERR;
}
if (fread(d, sizeof(float), npts, fp) != npts) {
return ELIO_FREAD_ERR;
}
} else {
return ELIO_ERR;
}
return ELIO_OK;
}
/*!
* Extract data for a single node from one previously time step.
* Works for 2d and 3d data, vector and scalar.
*
* Input variables:
*
* \param t = Pointer to previously read time step.
* \param h = Pointer to valid ElcircHeader struct.
* \param node = Node number starting from 0.
* \param bind = Bottom index starting from 0.
* \param sind = Surface index starting from 0.
*
* Output Variables:
*
* \param d = Pointer to array extracted from timestep struct.
*
* Returns ELIO_OK on success.
*
*/
int ElioExtractNode(ElcircTimeStep * t, ElcircHeader * h, int node, int bind, int sind, float *d)
{
int i;
if (h->i23d == 2) {
if (h->ivs == 2) {
d[0] = t->d[h->no[node]];
d[1] = t->d[h->no[node] + 1];
} else {
d[0] = t->d[h->no[node]];
}
} else {
for (i = bind; i <= sind; i++) {
if (h->ivs == 2) {
d[2 * i] = t->d[h->no[node] + 2 * i - 2 * bind];
d[2 * i + 1] = t->d[h->no[node] + 2 * i + 1 - 2 * bind];
} else {
d[i] = t->d[h->no[node] + i - bind];
}
}
}
return ELIO_OK;
}
/*!
* Get data for a single node from one time step - fills in missing data
* values to match the old format.
*
* Input variables:
*
* \param fp = Pointer to open file handle.
* \param step = Time step starting from 0.
* \param node = Node number starting from 0.
* \param h = Pointer to valid ElcircHeader struct.
*
* Output Variables:
*
* \param t = Pointer to time, float.
* \param it = Pointer to computational time step, integer.
* \param d = Pointer to array of return values, h.nvrt long.
*
* Returns ELIO_OK on success.
* Returns ELIO_FSEEK_ERR and ELIO_FREAD_ERR on error.
*/
int ElioGetNodeOld(FILE * fp, int step, int node, ElcircHeader * h, float *t, int *it, float *d)
{
int i, npts, bind, sind, rval = 0;
off_t skip;
float *tmp;
tmp = (float *) malloc(h->nvrt * h->ivs * sizeof(float));
bind = h->bi[node];
if (h->i23d == 3) { /* 3d data */
skip = (off_t) h->hsize + (off_t) step *(off_t) h->ssize;
if (fseeko(fp, skip, SEEK_SET)) { /* Read time, it, and sind */
rval = ELIO_FSEEK_ERR;
goto out;
}
if (fread(t, sizeof(float), 1, fp) != 1) {
rval = ELIO_FREAD_ERR;
goto out;
}
if (fread(it, sizeof(int), 1, fp) != 1) {
rval = ELIO_FREAD_ERR;
goto out;
}
if (fseeko(fp, (off_t) (node * 4L), SEEK_CUR)) {
rval = ELIO_FSEEK_ERR;
goto out;
} /* sind */
if (fread(&sind, sizeof(int), 1, fp) != 1) {
rval = ELIO_FREAD_ERR;
goto out;
}
npts = (h->nvrt - h->bi[node]) * h->ivs; /* number of points to read for this node */
if (fseeko(fp, skip + (off_t) ((2 + h->np + h->no[node]) * 4), SEEK_SET)) { /* skip time, it, and the surf indexes */
rval = ELIO_FSEEK_ERR;
goto out;
}
if (fread(tmp, sizeof(float), npts, fp) != npts) {
rval = ELIO_FREAD_ERR;
goto out;
}
} else if (h->i23d == 2) { /* 2d data - just one or 2 values to read */
skip = (off_t) h->hsize + (off_t) step *(off_t) h->ssize;
if (fseeko(fp, skip, SEEK_SET)) { /* Read time, it, and sind */
rval = ELIO_FSEEK_ERR;
goto out;
}
if (fread(&t, sizeof(float), 1, fp) != 1) {
rval = ELIO_FREAD_ERR;
goto out;
}
if (fread(&it, sizeof(int), 1, fp) != 1) {
rval = ELIO_FREAD_ERR;
goto out;
}
if (fseeko(fp, (off_t) (node * 4L), SEEK_CUR)) { /* Read time, it, and sind */
rval = ELIO_FSEEK_ERR;
goto out;
}
if (fread(&sind, sizeof(int), 1, fp) != 1) {
rval = ELIO_FREAD_ERR;
goto out;
}
npts = h->ivs; /* number of points to read for this node */
if (fseeko(fp, skip + (off_t) ((2 + h->np) * 4), SEEK_SET)) { /* skip time, it, and the surf indexes */
rval = ELIO_FSEEK_ERR;
goto out;
}
if (fread(tmp, sizeof(float), npts, fp) != npts) {
rval = ELIO_FREAD_ERR;
goto out;
}
} else {
rval = 9;
goto out;
}
for (i = 0; i < (sind - bind) * h->ivs; i++) {
d[i + bind * h->ivs] = tmp[i];
}
out:;
free(tmp);
return rval;
}
/*!
* Get data for a single node from one time step should work for both
* sigma and z-level grids.
*
* Input variables:
*
* \param fp = Pointer to open file handle.
* \param step = Time step starting from 0.
* \param elem = Element number.
* \param h = Pointer to valid ElcircHeader struct.
* \param hh = Pointer to shape function coefficients.
*
* Output Variables:
*
* \param t = Pointer to time, float.
* \param it = Pointer to computational time step, integer.
* \param bind = Pointer to bottom index, integer.
* \param sind = Pointer to surface index, integer.
* \param d = Pointer to array of return values, h.nvrt long.
*
* Returns ELIO_OK on success.
* Returns ELIO_FSEEK_ERR and ELIO_FREAD_ERR on error.
*/
int ElioGetXYData2(FILE * fp, int step, int elem, ElcircHeader * h, double *hh, float *t, int *it, int *bind, int *sind, float *d)
{
int i, j, nn[4], tcnt, cnt[4];
double uret, vret;
double *u[4], *v[4], dd[4], vv[4];
float dtmp[4][400];
float dt[400];
/* get the nodes for the element */
for (i = 0; i < h->nvrt * h->ivs; i++) {
dt[i] = d[i] = 0.0;
}
for (i = 0; i < h->etype[elem]; i++) {
nn[i] = h->icon[i][elem];
ElioGetNode(fp, step, nn[i], h, t, it, &bind[i], &sind[i], dt);
//printf("Node %d element %d %d %d\n", nn[i], elem, bind[i], sind[i]);
for (j = 0; j < h->nvrt; j++) {
if (h->ivs == 2) {
// printf("%d %f %f\n", i, dt[2 * j], dt[2 * j + 1]);
if (bind[i] <= j && sind[i] >= j) {
dtmp[i][2 * j] = dt[2 * (j - bind[i])];
dtmp[i][2 * j + 1] = dt[2 * (j - bind[i]) + 1];
} else {
dtmp[i][2 * j] = 0.0;
dtmp[i][2 * j + 1] = 0.0;
}
} else if (h->ivs == 1) {
//printf("ElioGetXYData2 = %d, %d: %f\n", i, j, dt[j]);
if (bind[i] <= j && sind[i] >= j) {
dtmp[i][j] = dt[j - bind[i]];
} else {
dtmp[i][j] = 0.0;
}
}
}
}
for (j = 0; j < h->nvrt; j++) {
uret = -99.0;
vret = 0.0;
tcnt = 0;
for (i = 0; i < h->etype[elem]; i++) {
cnt[i] = 0;
if (h->ivs == 2) {
if (bind[i] <= j && sind[i] >= j) {
dd[i] = dtmp[i][2 * j];
vv[i] = dtmp[i][2 * j + 1];
cnt[i]++;
tcnt++;
} else {
dd[i] = 0.0;
vv[i] = 0.0;
}
} else if (h->ivs == 1) {
if (bind[i] <= j && sind[i] >= j) {
dd[i] = dtmp[i][j];
cnt[i]++;
tcnt++;
} else {
dd[i] = 0.0;
}
}
}
if (h->ivs == 2) {
if (tcnt && tcnt != h->etype[elem]) {
uret = 0.0;
vret = 0.0;
for (i = 0; i < h->etype[elem]; i++) {
uret = uret + cnt[i] * dd[i];
vret = vret + cnt[i] * vv[i];
}
uret = uret / tcnt;
vret = vret / tcnt;
} else if (tcnt == h->etype[elem]) {
ElioEval(h->etype[elem], hh, dd, &uret);
ElioEval(h->etype[elem], hh, vv, &vret);
}
d[2 * j] = uret;
d[2 * j + 1] = vret;
} else if (h->ivs == 1) {
if (tcnt && tcnt != h->etype[elem]) {
uret = 0.0;
for (i = 0; i < h->etype[elem]; i++) {
uret = uret + cnt[i] * dd[i];
}
uret = uret / tcnt;
} else if (tcnt == h->etype[elem]) {
ElioEval(h->etype[elem], hh, dd, &uret);
}
d[j] = uret;
}
}
return ELIO_OK;
}
/*!
* Get data for a single node from one time step for sigma grids
*
* Input variables:
*
* \param h = Pointer to valid ElcircHeader struct.
* \param elem = Element number.
* \param x = x of location to interpolate to.
* \param y = y of location to interpolate to.
* \param hh = Pointer to shape function coefficients.
* \param t = Pointer to valid ElcircTimeStep struct.
*
* Output Variables:
*
* \param d = Pointer to array of return values, h.nvrt long.
*
* Returns ELIO_OK on success.
* Returns ELIO_FSEEK_ERR and ELIO_FREAD_ERR on error.
*/
int ElioInterpTimeStepSigma(ElcircHeader * h, int elem, double x, double y, double *hh, ElcircTimeStep * t, float *d)
{
int i, j, nn[4], tcnt, cnt[4];
double uret, vret;
double *u[4], *v[4], dd[4], vv[4];
float dtmp[4][400];
float dt[400];
/* get the nodes for the element */
for (i = 0; i < h->nvrt * h->ivs; i++) {
dt[i] = d[i] = 0.0;
}
for (i = 0; i < h->etype[elem]; i++) {
nn[i] = h->icon[i][elem];
ElioExtractNode(t, h, nn[i], 0, h->nvrt - 1, dt);
for (j = 0; j < h->nvrt; j++) {
//printf("%d, %d: %f\n", i, j, dt[j]);
if (h->ivs == 2) {
dtmp[i][2 * j] = dt[2 * j];
dtmp[i][2 * j + 1] = dt[2 * j + 1];
} else if (h->ivs == 1) {
dtmp[i][j] = dt[j];
}
}
}
for (j = 0; j < h->nvrt; j++) {
for (i = 0; i < h->etype[elem]; i++) {
if (h->ivs == 2) {
dd[i] = dtmp[i][2 * j];
vv[i] = dtmp[i][2 * j + 1];
} else if (h->ivs == 1) {
dd[i] = dtmp[i][j];
}
}
if (h->ivs == 2) {
ElioEval(h->etype[elem], hh, dd, &uret);
ElioEval(h->etype[elem], hh, vv, &vret);
d[2 * j] = uret;
d[2 * j + 1] = vret;
} else {
ElioEval(h->etype[elem], hh, dd, &uret);
d[j] = uret;
}
//printf("uret = %d, %d: %f\n", i, j, d[j]);
}
return ELIO_OK;
}
int ElioInterpTimeStep(ElcircHeader * h, int elem, double x, double y, double *hh, ElcircTimeStep * t, int *bind, int *sind, float *d)
{
int i, j, nn[4], tcnt, cnt[4];
double uret, vret;
double *u[4], *v[4], dd[4], vv[4];
float dtmp[4][400];
float dt[400];
/* get the nodes for the element */
for (i = 0; i < h->nvrt * h->ivs; i++) {
dt[i] = d[i] = 0.0;
}
for (i = 0; i < h->etype[elem]; i++) {
nn[i] = h->icon[i][elem];
bind[i] = h->bi[nn[i]];
sind[i] = t->surfind[nn[i]] - 1;
ElioExtractNode(t, h, nn[i], bind[i], sind[i], dt);
for (j = 0; j < h->nvrt; j++) {
if (h->ivs == 2) {
if (bind[i] <= j && sind[i] >= j) {
dtmp[i][2 * j] = dt[2 * j];
dtmp[i][2 * j + 1] = dt[2 * j + 1];
//printf("values = %d, %d: %f %f\n", i, j, dt[2 * j], dt[2 * j + 1]);
} else {
dtmp[i][2 * j] = 0.0;
dtmp[i][2 * j + 1] = 0.0;
}
} else if (h->ivs == 1) {
//if (h->nvrt == 1) printf("InterpTimeStep = %d, %d: %f %d %d\n", i, j, dt[j], bind[i], sind[i]);
if (bind[i] <= j && sind[i] >= j) {
//if (tdebug && dt[j] < 0.0) {
// printf("InterpTimeStep = %d, %d: %f %d %d\n", i, j, dt[j], bind[i], sind[i]);
//}
dtmp[i][j] = dt[j];
} else {
dtmp[i][j] = 0.0;
}
}
}
}
for (j = 0; j < h->nvrt; j++) {
uret = -99.0;
vret = 0.0;
tcnt = 0;
for (i = 0; i < h->etype[elem]; i++) {
cnt[i] = 0;
if (h->ivs == 2) {
if (bind[i] <= j && sind[i] >= j) {
dd[i] = dtmp[i][2 * j];
vv[i] = dtmp[i][2 * j + 1];
cnt[i]++;
tcnt++;
} else {
dd[i] = 0.0;
vv[i] = 0.0;
}
} else if (h->ivs == 1) {
if (bind[i] <= j && sind[i] >= j) {
dd[i] = dtmp[i][j];
cnt[i]++;
tcnt++;
} else {
dd[i] = 0.0;
}
}
}
if (h->ivs == 2) {
if (tcnt && tcnt != h->etype[elem]) {
uret = 0.0;
vret = 0.0;
for (i = 0; i < h->etype[elem]; i++) {
uret = uret + cnt[i] * dd[i];
vret = vret + cnt[i] * vv[i];
//printf("ElioInterpTimeStep: %d %d %d %lf %lf\n", tcnt, i, cnt[i], dd[i], vv[i]);
}
uret = uret / tcnt;
vret = vret / tcnt;
} else if (tcnt == h->etype[elem]) {
ElioEval(h->etype[elem], hh, dd, &uret);
ElioEval(h->etype[elem], hh, vv, &vret);
//printf("ElioInterpTimeStep OK: %lf %lf\n", uret, vret);
}
d[2 * j] = uret;
d[2 * j + 1] = vret;
} else if (h->ivs == 1) {
if (tcnt && tcnt != h->etype[elem]) {
uret = 0.0;
for (i = 0; i < h->etype[elem]; i++) {
uret = uret + cnt[i] * dd[i];
}
uret = uret / tcnt;
} else if (tcnt == h->etype[elem]) {
ElioEval(h->etype[elem], hh, dd, &uret);
}
d[j] = uret;
}
}
return ELIO_OK;
}
/*!
* int ElioGetXYData(FILE * fp, int step, double x, double y, ElcircHeader * h, float *t, int *it, int *bind, int *sind, float *d)
*
* Get data at (x, y) by interpolation.
*
* \param fp - Open file handle for the file to read.
* \param step - Step to read starting from 0 - the first step.
* \param x - X.
* \param y - Y.
* \param h - Elcirc header information previously read.
* \param t - Return time from the file.
* \param it - Return time step from file.
* \param bind - Integer array of 4 values for returning bottom indexes for the element (x, y) is in.
* \param sind - Integer array of 4 values for returning surface indexes for the element (x, y) is in.
* \param d - Return data values.
*
* Returns ELIO_OK on success.
* Returns ELIO_ERR on unknown failures.
* Returns ELIO_FSEEK_ERR on seek failures.
* Returns ELIO_FREAD_ERR on read failures.
*/
int ElioGetXYData(FILE * fp, int step, double x, double y, ElcircHeader * h, float *t, int *it, int *bind, int *sind, float *d)
{
int i, j, elem, nn[4];
double hh[4], uret;
double *u[4], *v[4], dd[4];
float dtmp[4][400];
/* find the element that contains the point */
if ((elem = ElioFindElementXY(h, x, y)) < 0) {
printf("elio.GetXY(): Unable to locate element.\n");
return 1;
}
/* get the nodes for the element */
for (i = 0; i < h->etype[elem]; i++) {
nn[i] = h->icon[i][elem];
ElioGetNode(fp, step, nn[i], h, t, it, &bind[i], &sind[i], &dtmp[i][0]);
}
ElioGetCoefficients(h, elem, x, y, hh);
for (i = 0; i < h->nvrt * h->ivs; i++) {
d[i] = 0.0;
}
for (j = 0; j < h->nvrt; j++) {
for (i = 0; i < h->etype[elem]; i++) {
if (bind[i] >= j && sind[i] < h->nvrt) {
dd[i] = dtmp[i][j - bind[i]];
} else {
dd[i] = -99.0;
}
}
ElioEval(h->etype[elem], hh, dd, &uret);
d[j] = uret;
}
return ELIO_OK;
}
/*!
* int ElioGetPoint(FILE * fp, int step, int node, int level, ElcircHeader * h, float *t, int *it, float *d)
* Get data for a single node from one time step at a particular level (numbered from 0)
*
* \param fp - Open file handle for the file to read.
* \param step - Step to read starting from 0 - the first step.
* \param node - Node to read starting from 0.
* \param level - Level to read starting from 0.
* \param h - Elcirc header information previously read.
* \param t - Return time value from data file.
* \param it, - Return time step from data file.
* \param d - Reurn data value.
*
* Returns ELIO_OK on success.
* Returns ELIO_ERR on unknown failures.
* Returns ELIO_FSEEK_ERR on seek failures.
* Returns ELIO_FREAD_ERR on read failures.
*/
int ElioGetPoint(FILE * fp, int step, int node, int level, ElcircHeader * h, float *t, int *it, float *d)
{
int i, npts, sind;
off_t skip;
if (h->i23d == 3) { /* 3d data */
skip = (off_t) h->hsize + (off_t) step *(off_t) h->ssize;
if (fseeko(fp, skip, SEEK_SET)) { /* Read time, it, and sind */
return ELIO_FSEEK_ERR;
}
if (fread(t, sizeof(float), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
if (fread(it, sizeof(int), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
if (fseeko(fp, node * 4L, SEEK_CUR)) { /* sind */
return ELIO_FSEEK_ERR;
}
if (fread(&sind, sizeof(int), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
npts = h->ivs; /* number of points to read for this node */
if (fseeko(fp, skip + (off_t) ((2 + h->np + h->no[node] + level) * 4), SEEK_SET)) { /* skip time, it, and the surf indexes and go to the particular level of interest */
return ELIO_FSEEK_ERR;
}
if (fread(d, sizeof(float), npts, fp) != npts) {
return ELIO_FREAD_ERR;
}
//printf("Starting level %d ending level %d\n", h->bi[node], sind);
//for (i = 0; i < npts; i++) {
// printf("Data %d = %f\n", i + h->bi[node], d[i]);
//}
//printf("Completed Read of Time Step (%d): Time, Step = %f, %d\n", step, *t, *it);
} else if (h->i23d == 2) { /* 2d data - just one or 2 values to read */
skip = (off_t) h->hsize + (off_t) step *(off_t) h->ssize;
if (fseeko(fp, skip, SEEK_SET)) { /* Read time, it, and sind */
return ELIO_FSEEK_ERR;
}
if (fread(&t, sizeof(float), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
if (fread(&it, sizeof(int), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
if (fseeko(fp, node * 4L, SEEK_CUR)) { /* Read time, it, and sind */
return ELIO_FSEEK_ERR;
}
if (fread(&sind, sizeof(int), 1, fp) != 1) {
return ELIO_FREAD_ERR;
}
npts = h->ivs; /* number of points to read for this node */
if (fseeko(fp, skip + (off_t) ((2 + h->np) * 4), SEEK_SET)) { /* skip time, it, and the surf indexes */
return ELIO_FSEEK_ERR;
}
if (fread(d, sizeof(float), npts, fp) != npts) {
return ELIO_FREAD_ERR;
}
/*
printf("Starting level %d ending level %d\n", h->bi[node], sind);
for (i = 0; i < npts; i++) {
printf("Data %d = %f\n", i, d[i]);
}
*/
printf("Completed Read of Time Step (%d): Time, Step = %f, %d\n", step, *t, *it);
} else {
return ELIO_ERR;
}
return ELIO_OK;
}
/*!
* Read the ElcircHeader from a data file
*
* Input variables:
*
* \param fname = Pointer to a character array with the file name to read.
*
* Output variables:
*
* \param h = Pointer to ElcircHeader header. Memory will be allocated
* to accomodate the internal variables.
*
* Returns ELIO_OK on success.
* Returns non-zero on failure.
*
* Notes: There are some transformations of header variables performed for
* convenience. For 2d variables such as elevations and winds, nvrt (the
* number of levels) is set to one, the bottom index for each node is set
* to 0 for all nodes. In the case of 3d variables the bottom indices
* ('bi') are decremented by one.
*
*/
int ElioGetHeader(char *fname, ElcircHeader * h)
{
FILE *fp;
int *itmp, i, j, ss;
if (sizeof(int) != 4 || sizeof(char) != 1 || sizeof(float) != 4) {
fprintf(stderr, "Sizeof problems, please investigate: sizeof(char,int,float) = (%d,%d,%d)\n", sizeof(int), sizeof(char), sizeof(float));
exit(1);
}
fp = fopen(fname, "rb");
if (fp == NULL) {
fprintf(stderr, "GetElioHeader(): Unable to open file %s\n", fname);
return 1;
}
if (fread(h->magic, sizeof(char), 48, fp) != 48)
return ELIO_FREAD_ERR;
h->magic[48] = 0;
/* DataFormat v3.0 */
if (strncmp(h->magic, "DataFormat v5.0", 15) == 0) {
h->v = 5;
h->sigma = 2; /* Sigma + Z-level grid */
} else if (strncmp(h->magic, "DataFormat v4.0", 15) == 0) {
h->v = 4;
h->sigma = 1; /* sigma-level grid */
} else if (strncmp(h->magic, "DataFormat v3.0", 15) == 0) {
h->v = 3;
h->sigma = 0; /* Z-level grid */
} else if (strncmp(h->magic, "DataFormat v2.0", 15) == 0) {
h->v = 2;
h->sigma = 0; /* Z-level grid */
} else {
fprintf(stderr, "GetElioHeader(): Unknown version identifier %s\n", h->magic);
return (3);
}
if (fread(h->version, sizeof(char), 48, fp) != 48)
return ELIO_FREAD_ERR;
h->version[48] = 0;
if (fread(h->start_time, sizeof(char), 48, fp) != 48)
return ELIO_FREAD_ERR;
h->start_time[48] = 0;
if (fread(h->variable_nm, sizeof(char), 48, fp) != 48)
return ELIO_FREAD_ERR;
h->variable_nm[48] = 0;
if (fread(h->variable_dim, sizeof(char), 48, fp) != 48)
return ELIO_FREAD_ERR;
h->variable_dim[48] = 0;
if (fread(&h->nsteps, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->timestep, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->skip, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->ivs, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->i23d, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (h->v == 2 || h->v == 3) {
if (fread(&h->vpos, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->zmsl, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->nvrt, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
} else if (h->v == 4) {
if (fread(&h->ivcor, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->h0, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->hc, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->thetab, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->thetaf, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->nvrt, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
} else if (h->v == 5) {
if (fread(&h->nvrt, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->kz, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
h->ks = h->nvrt - h->kz;
if (fread(&h->h0, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->hs, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->hc, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->thetab, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->thetaf, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
}
h->zcor = (float *) malloc(h->nvrt * sizeof(float));
if (fread(h->zcor, sizeof(float), h->nvrt, fp) != h->nvrt)
return ELIO_FREAD_ERR;
if (fread(&h->np, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(&h->ne, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
h->x = (float *) malloc(h->np * sizeof(float));
h->y = (float *) malloc(h->np * sizeof(float));
h->d = (float *) malloc(h->np * sizeof(float));
h->bi = (int *) malloc(h->np * sizeof(int));
h->bisave = (int *) malloc(h->np * sizeof(int));
h->no = (int *) malloc(h->np * sizeof(int)); /* offset into data for each node */
for (i = 0; i < h->np; i++) {
if (fread(h->x + i, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(h->y + i, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (fread(h->d + i, sizeof(float), 1, fp) != 1)
return ELIO_FREAD_ERR;
if (h->v != 4) {
if (fread(h->bi + i, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
} else {
h->bi[i] = 1;
}
}
h->icon[0] = (int *) malloc(h->ne * sizeof(int));
h->icon[1] = (int *) malloc(h->ne * sizeof(int));
h->icon[2] = (int *) malloc(h->ne * sizeof(int));
h->etype = (int *) malloc(h->ne * sizeof(int));
if (h->v == 2) { /* format version 2 */
itmp = (int *) malloc(h->ne * 3 * sizeof(int));
if (fread(itmp, sizeof(int), h->ne * 3, fp) != h->ne * 3)
return ELIO_FREAD_ERR;
for (i = 0; i < h->ne; i++) {
h->etype[i] = 3;
h->icon[0][i] = itmp[i * 3] - 1;
h->icon[1][i] = itmp[i * 3 + 1] - 1;
h->icon[2][i] = itmp[i * 3 + 2] - 1;
}
free(itmp);
} else if (h->v == 3) { /* format version 3 support for quads */
h->icon[3] = (int *) malloc(h->ne * sizeof(int));
for (i = 0; i < h->ne; i++) {
if (fread(&h->etype[i], sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
for (j = 0; j < h->etype[i]; j++) {
if (fread(&h->icon[j][i], sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
h->icon[j][i]--;
}
}
} else if (h->v == 4 || h->v == 5) { /* format version 4 no support for quads */
for (i = 0; i < h->ne; i++) {
if (fread(&h->etype[i], sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
for (j = 0; j < h->etype[i]; j++) {
if (fread(&h->icon[j][i], sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
h->icon[j][i]--;
}
}
}
/* compute size of data in time step and offsets to each node */
if (h->i23d == 3) {
if (h->v != 4) {
h->nitems = 0;
for (i = 0; i < h->np; i++) {
h->bisave[i] = h->bi[i];
if (h->bi[i] > 0) {
h->bi[i]--;
} else {
}
h->no[i] = h->nitems;
h->nitems += (h->nvrt - h->bi[i]) * h->ivs;
//printf("%d: %d %d %d %d %d\n", i, h->nvrt, h->ivs, h->bi[i], h->no[i], h->nitems);
}
} else {
h->nitems = h->ivs * h->nvrt * h->np;
for (i = 0; i < h->np; i++) {
h->bisave[i] = h->bi[i];
h->bi[i] = 0;
h->no[i] = i * h->ivs * h->nvrt;
}
}
} else {
h->nvrt = 1; /* only 1 level */
if (h->v != 4) {
h->nitems = 0;
for (i = 0; i < h->np; i++) {
h->bisave[i] = h->bi[i];
h->bi[i] = 0; /* bottom index is always 0 */
h->no[i] = h->nitems;
h->nitems += h->ivs;
}
} else {
h->nitems = h->ivs * h->np;
for (i = 0; i < h->np; i++) {
h->bisave[i] = h->bi[i];
h->bi[i] = 0; /* bottom index is always 0 */
h->no[i] = i * h->ivs;
}
}
}
/* get the header size in bytes */
h->hsize = ftello(fp);
/* get time step size in bytes */
if (h->v == 3 || h->v == 4 || h->v == 5) { /* version 4 has elevation so size is the same */
h->ssize = 8 + h->np * 4 + h->nitems * 4;
} else if (h->v == 2) {
h->ssize = 8 + h->np * 4 + h->nitems * 4;
}
if (fclose(fp)) {
return ELIO_FCLOSE_ERR;
}
return ELIO_OK;
}
/*!
* Allocate memory for an ElcircHeader
*
* Input/Output variable:
*
* \param h = Pointer to ElcircHeader header. Memory will be allocated
* to accomodate the internal variables. Assumes suitable defaults
* have been set for np, ne, and nvrt. Also that other variables
* have proper defaults set.
*
* Returns ELIO_OK on success.
* Returns non-zero on failure.
*
*/
int ElioAllocateHeader(ElcircHeader * h)
{
h->zcor = (float *) malloc(h->nvrt * sizeof(float));
h->x = (float *) malloc(h->np * sizeof(float));
h->y = (float *) malloc(h->np * sizeof(float));
h->d = (float *) malloc(h->np * sizeof(float));
h->bi = (int *) malloc(h->np * sizeof(int));
h->bisave = (int *) malloc(h->np * sizeof(int)); /* save the original bi values */
h->no = (int *) malloc(h->np * sizeof(int)); /* offset into data for each node */
h->icon[0] = (int *) malloc(h->ne * sizeof(int));
h->icon[1] = (int *) malloc(h->ne * sizeof(int));
h->icon[2] = (int *) malloc(h->ne * sizeof(int));
h->icon[3] = (int *) malloc(h->ne * sizeof(int));
h->etype = (int *) malloc(h->ne * sizeof(int));
return ELIO_OK;
}
int ElioMakeScalarsOld(ElcircHeader * h, float *d, float *dd)
{
int i, j, k;
for (i = 0; i < h->np * h->nvrt; i++) {
dd[i] = -99.0;
}
for (j = 0; j < h->np; j++) {
for (k = h->bi[j]; k < h->nvrt; k++) {
dd[j * h->nvrt + k] = d[h->no[j] + k - h->bi[j]];
}
}
return ELIO_OK;
}
int ElioMakeVectorsOld(ElcircHeader * h, float *d, float *dd)
{
int i, j, k;
float tmp;
for (i = 0; i < 2 * h->np * h->nvrt; i++) {
dd[i] = 0.0;
}
for (j = 0; j < h->np; j++) {
for (k = h->bi[j]; k < h->nvrt; k++) {
tmp = d[h->no[j] + (k - h->bi[j]) * 2];
dd[2 * (j * h->nvrt + k)] = tmp;
tmp = d[h->no[j] + (k - h->bi[j]) * 2 + 1];
dd[2 * (j * h->nvrt + k) + 1] = tmp;
/*
dd[2 * (j * h->nvrt + k)] = d[h->no[j] + (k - h->bi[j]) * 2];
dd[2 * (j * h->nvrt + k) + 1] = d[h->no[j] + (k - h->bi[j]) * 2 + 1];
*/
}
}
return ELIO_OK;
}
/*!
* Return the actual number of time steps in a data file regardless of
* what the ElcircHeader says.
*/
int ElioGetNStepsInFile(char *fname, ElcircHeader * h)
{
char id[5];
int n;
off_t fsize = 0;
FILE *fp = fopen(fname, "rb");
if (fp == NULL) {
fprintf(stderr, "GetNStepsInFile(): Unable to open file %s\n", fname);
return ELIO_OK;
}
if (fseeko(fp, 0L, SEEK_END)) {
return ELIO_FSEEK_ERR;
}
fsize = ftello(fp);
if (fclose(fp)) {
return ELIO_FCLOSE_ERR;
}
fsize = fsize - (off_t) h->hsize;
if (h->ssize > 0) {
n = fsize / h->ssize;
} else {
n = -1;
}
return n;
}
/*!
* Extract a Header for the extracted grid
* x, y, isin need to be allocated in advance.
* invert = 1 to select outside the region
* most == 1 to include an element if a single node is in the region
* NOTE: most does not work, if a node is in then every node of every element that uses that node is also in
* Need to add some additional logic for most to work.
*/
int ElioExtractGrid(ElcircHeader * h1, int nb, double *xb, double *yb, int *isin, int invert, int most, ElcircHeader * h2)
{
int i, j;
int n;
int np, ne;
int n1, n2, n3, n4;
double x, y;
*h2 = *h1; /* copy the easy stuff */
/*
* Find the 'in' nodes and assign the new node numbers for the reduced grid.
*/
for (i = 0; i < h1->np; i++) {
isin[i] = 0;
}
n = 1; /* start from 1 for truth testing (0 is not in) */
for (i = 0; i < h1->np; i++) {
x = (double) h1->x[i];
y = (double) h1->y[i];
if (!isin[i]) { // if most == 1 the test for already in
if (invert) {
if (!ElioInPolygon(x, y, nb, xb, yb)) {
isin[i] = n;
n++;
} else {
isin[i] = 0;
}
} else {
if (ElioInPolygon(x, y, nb, xb, yb)) {
isin[i] = n;
n++;
} else {
isin[i] = 0;
}
}
}
if (isin[i] && most) {
// TODO need to add logic to mark all associated nodes as in also.
// crude version - loop over all elements and find elements using this node then
// mark all other nodes of the element as in.
// Better version uses an edgelist.
for (j = 0; j < h1->ne; j++) {
n1 = h1->icon[0][j];
n2 = h1->icon[1][j];
n3 = h1->icon[2][j];
if (n1 == i) {
if (!isin[n2]) {
isin[n2] = n;
n++;
}
if (!isin[n3]) {
isin[n3] = n;
n++;
}
} else if (n2 == i) {
if (!isin[n1]) {
isin[n1] = n;
n++;
}
if (!isin[n3]) {
isin[n3] = n;
n++;
}
} else if (n3 == i) {
if (!isin[n1]) {
isin[n1] = n;
n++;
}
if (!isin[n2]) {
isin[n2] = n;
n++;
}
}
}
}
}
h2->np = n - 1; /* one extra */
h2->x = (float *) malloc(h2->np * sizeof(float));
h2->y = (float *) malloc(h2->np * sizeof(float));
h2->d = (float *) malloc(h2->np * sizeof(float));
h2->bi = (int *) malloc(h2->np * sizeof(int));
h2->bisave = (int *) malloc(h2->np * sizeof(int));
h2->no = (int *) malloc(h2->np * sizeof(int));
/*
* count the number of elements in the new grid
*/
n = 0;
for (i = 0; i < h1->ne; i++) {
n1 = h1->icon[0][i];
n2 = h1->icon[1][i];
n3 = h1->icon[2][i];
if (h1->etype[i] == 3) {
if (isin[n1] && isin[n2] && isin[n3]) {
++n;
}
} else if (h1->etype[i] == 4) {
n4 = h1->icon[3][i];
if (isin[n1] && isin[n2] && isin[n3] && isin[n4]) {
++n;
}
}
}
h2->ne = n;
h2->icon[0] = (int *) malloc(h2->ne * sizeof(int));
h2->icon[1] = (int *) malloc(h2->ne * sizeof(int));
h2->icon[2] = (int *) malloc(h2->ne * sizeof(int));
h2->icon[3] = (int *) malloc(h2->ne * sizeof(int));
h2->etype = (int *) malloc(h2->ne * sizeof(int));
/*
* Build new header
*/
n = 0;
for (i = 0; i < h1->np; i++) {
if (isin[i]) {
h2->x[n] = h1->x[i];
h2->y[n] = h1->y[i];
h2->d[n] = h1->d[i];
h2->bi[n] = h1->bi[i];
h2->bisave[n] = h1->bisave[i];
n++;
}
}
/*
* use the old node numbers to hash into the list containing the new
* node numbers when writing out the table of elements.
*/
n = 0;
for (i = 0; i < h1->ne; i++) {
n1 = h1->icon[0][i];
n2 = h1->icon[1][i];
n3 = h1->icon[2][i];
h2->etype[n] = h1->etype[i];
if (h1->etype[i] == 4) {
n4 = h1->icon[3][i];
if (isin[n1] && isin[n2] && isin[n3] && isin[n4]) {
h2->icon[0][n] = isin[n1] - 1; /* isin starts from 1 */
h2->icon[1][n] = isin[n2] - 1;
h2->icon[2][n] = isin[n3] - 1;
h2->icon[3][n] = isin[n4] - 1;
n++;
}
} else {
if (isin[n1] && isin[n2] && isin[n3]) {
h2->icon[0][n] = isin[n1] - 1; /* isin starts from 1 */
h2->icon[1][n] = isin[n2] - 1;
h2->icon[2][n] = isin[n3] - 1;
n++;
}
}
}
/* get the computed elements of the header */
if (h2->i23d == 3) {
h2->nitems = 0;
for (i = 0; i < h2->np; i++) {
h2->no[i] = h2->nitems;
h2->nitems += (h2->nvrt - h2->bi[i]) * h2->ivs;
}
} else {
h2->nvrt = 1; /* only 1 level */
h2->nitems = 0;
for (i = 0; i < h2->np; i++) {
h2->bi[i] = 0; /* bottom index is always 0 */
h2->no[i] = h2->nitems;
h2->nitems += h2->ivs;
}
}
/* get the header size in bytes TODO */
/*h2->hsize = ftello(fp); */
/* get time step size in bytes */
h2->ssize = 8 + h2->np * 4 + h2->nitems * 4;
return ELIO_OK;
}
/*!
* Extract data from a sampled grid
* The header must be created before this function is called
*/
int ElioExtractData(ElcircHeader * h1, ElcircHeader * h2, int *isin, ElcircTimeStep t1, ElcircTimeStep * t2)
{
int i, j, n, *si, npts;
float *d;
*t2 = t1;
si = (int *) malloc(h2->np * sizeof(int));
n = 0;
for (i = 0; i < h1->np; i++) {
if (isin[i]) {
si[n] = t1.surfind[i];
n++;
}
}
t2->surfind = si;
t2->d = (float *) malloc(h2->nitems * sizeof(float));
n = 0;
for (i = 0; i < h1->np; i++) {
if (isin[i]) {
for (j = 0; j < h1->nvrt - h1->bi[i]; j++) {
t2->d[n] = t1.d[h1->no[i] + j];
n++;
}
}
}
return ELIO_OK;
}
/*!
* Routines to determine if a point lies in a polygon
*/
int ElioIntersectToLeft(double x, double y, double x1, double y1, double x2, double y2)
{
double xtmp, m, b;
/* ignore horizontal lines */
if (y1 == y2) {
return 0;
}
/* not contained vertically */
if (((y < y1) && (y < y2)) || ((y > y1) && (y > y2))) {
return 0;
}
/* none of the above, compute the intersection */
if ((xtmp = x2 - x1) != 0.0) {
m = (y2 - y1) / xtmp;
b = y1 - m * x1;
xtmp = (y - b) / m;
} else {
xtmp = x1;
}
if (xtmp <= x) {
/* check for intersections at a vertex */
/* if this is the max ordinate then accept */
if (y == y1) {
if (y1 > y2) {
return 1;
} else {
return 0;
}
}
/* check for intersections at a vertex */
if (y == y2) {
if (y2 > y1) {
return 1;
} else {
return 0;
}
}
/* no vertices intersected */
return 1;
}
return 0;
}
/*!
* Determine if (x,y) is in the polygon xlist[], ylist[].
*/
int ElioInPolygon(double x, double y, int n, double *xlist, double *ylist)
{
int i, l = 0, ll = 0;
for (i = 0; i < n; i++) {
if ((y < ylist[i] && y < ylist[(i + 1) % n])
|| (y > ylist[i] && y > ylist[(i + 1) % n])) {
continue;
}
if ((x < xlist[i] && x < xlist[(i + 1) % n])) {
continue;
}
l += ElioIntersectToLeft(x, y, xlist[i], ylist[i], xlist[(i + 1) % n], ylist[(i + 1) % n]);
}
return l % 2;
}
/*!
* Locate the element in which x, y is located.
* Returns -1 if the element cannot be located, the element number
* starting from zero otherwise.
*
*/
int ElioFindElementXY(ElcircHeader * h, double xp, double yp)
{
int i, j;
int n0, n1, n2, n3;
double x[4], y[4];
for (i = 0; i < h->ne; i++) {
for (j = 0; j < h->etype[i]; j++) {
x[j] = h->x[h->icon[j][i]];
y[j] = h->y[h->icon[j][i]];
}
if (h->etype[i] == 3) {
if (ElioInsideElement(xp, yp, x[0], y[0], x[1], y[1], x[2], y[2])) {
return i;
}
} else {
if (ElioInsideElement4(xp, yp, x[0], y[0], x[1], y[1], x[2], y[2], x[3], y[3])) {
return i;
}
}
}
return -1;
}
/*!
* Tolerance for locating point in elements.
*/
static double ElioInsideElementTol = -1e-05;
/*!
* Set the tolerance for locating points in elements.
*/
void ElioSetInsideElementTol(double tol)
{
ElioInsideElementTol = -tol;
}
/*!
* Determine if (x, y) is inside the triangle given by (x1, y1), (x2, y2), (x3, y3).
*/
int ElioInsideElement(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3)
{
if ((x - x1) * (y1 - y2) + (y - y1) * (x2 - x1) < ElioInsideElementTol)
return 0;
if ((x - x2) * (y2 - y3) + (y - y2) * (x3 - x2) < ElioInsideElementTol)
return 0;
if ((x - x3) * (y3 - y1) + (y - y3) * (x1 - x3) < ElioInsideElementTol)
return 0;
return 1;
}
/*!
* Determine if (x, y) is inside the convex quadrangle given by (x1, y1), (x2, y2), (x3, y3), (x4, y4).
*/
int ElioInsideElement4(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
{
if ((x - x1) * (y1 - y2) + (y - y1) * (x2 - x1) < ElioInsideElementTol)
return 0;
if ((x - x2) * (y2 - y3) + (y - y2) * (x3 - x2) < ElioInsideElementTol)
return 0;
if ((x - x3) * (y3 - y4) + (y - y3) * (x4 - x3) < ElioInsideElementTol)
return 0;
if ((x - x4) * (y4 - y1) + (y - y4) * (x1 - x4) < ElioInsideElementTol)
return 0;
return 1;
}
/*!
* Given previously computed nodal coefficients in h, and flow (u, v) at each node compute the flow and return in (uret, vret).
*
* \param n Integer number of nodes.
* \param h Pointer to nodal coefficients.
* \param u Pointer to nodal values for u at the nodes.
* \param v Pointer to nodal values for u at the nodes.
* \param uret Pointer to return value.
* \param vret Pointer to return value.
*/
int ElioEvalFlowXY(int n, double *h, double *u, double *v, double *uret, double *vret)
{
int i;
*uret = 0.0;
*vret = 0.0;
if (n != 3 && n != 4) {
return 1;
} else {
for (i = 0; i < n; i++) {
*uret += h[i] * u[i];
*vret += h[i] * v[i];
}
}
return ELIO_OK;
}
int ElioEval(int n, double *h, double *c, double *uret)
{
int i;
*uret = 0.0;
if (n != 3 && n != 4) {
return 1;
} else {
for (i = 0; i < n; i++) {
*uret += h[i] * c[i];
}
}
return ELIO_OK;
}
int ElioEvalScalarXY(int n, double *h, double *c, double *uret)
{
int i;
*uret = 0.0;
if (n != 3 && n != 4) {
return 1;
} else {
for (i = 0; i < n; i++) {
*uret += h[i] * c[i];
}
}
return ELIO_OK;
}
/*! Compute coefficients for interpolation for both triangles and quads using
* information from the element number.
*
* \param h Header struct to write.
* \param elem Number of the element from 0.
* \param xp X-coordinate of point for interpolation.
* \param yp Y-coordinate of point for interpolation.
* \param w Coefficients of interpolator.
*
* Returns ELIO_OK on success and ELIO_ERR on failure.
*/
int ElioGetCoefficients(ElcircHeader * h, int elem, double xp, double yp, double *w)
{
double aum, ado, atr, bum, bdo, btr, cum, cdo, ctr;
double x1, y1, x2, y2, x3, y3, x4, y4, c1, c2, c3, arei;
double xi, eta;
int nn[4];
nn[0] = h->icon[0][elem];
nn[1] = h->icon[1][elem];
nn[2] = h->icon[2][elem];
x1 = h->x[nn[0]];
y1 = h->y[nn[0]];
x2 = h->x[nn[1]];
y2 = h->y[nn[1]];
x3 = h->x[nn[2]];
y3 = h->y[nn[2]];
if (h->etype[elem] == 3) {
aum = x2 * y3 - x3 * y2;
bum = y2 - y3;
cum = x3 - x2;
ado = x3 * y1 - x1 * y3;
bdo = y3 - y1;
cdo = x1 - x3;
atr = x1 * y2 - x2 * y1;
btr = y1 - y2;
ctr = x2 - x1;
arei = 1.0 / (aum + ado + atr);
w[2] = (atr + btr * xp + ctr * yp) * arei;
w[1] = (ado + bdo * xp + cdo * yp) * arei;
w[0] = 1.0 - w[1] - w[2];
return ELIO_OK;
} else {
nn[3] = h->icon[3][elem];
x4 = h->x[nn[3]];
y4 = h->y[nn[3]];
ibilinear(x1, x2, x3, x4, y1, y2, y3, y4, xp, yp, &xi, &eta, w);
return ELIO_OK;
}
return ELIO_ERR;
}
/*! Compute coefficients for interpolation for both triangles and quads using
* information from the element number.
*
* \param h Header struct to write.
* \param elem Number of the element from 0.
* \param xp X-coordinate of point for interpolation.
* \param yp Y-coordinate of point for interpolation.
* \param w Coefficients of interpolator.
*
* Returns ELIO_OK on success and ELIO_ERR on failure.
*/
int ElioGetCoefficientsGrid(ElioGrid * g, int elem, double xp, double yp, double *w)
{
double aum, ado, atr, bum, bdo, btr, cum, cdo, ctr;
double x1, y1, x2, y2, x3, y3, x4, y4, c1, c2, c3, arei;
double xi, eta;
int nn[4];
if (g == NULL || elem < 0 || elem >= g->ne) {
return ELIO_ERR;
}
nn[0] = g->icon[0][elem];
nn[1] = g->icon[1][elem];
nn[2] = g->icon[2][elem];
x1 = g->x[nn[0]];
y1 = g->y[nn[0]];
x2 = g->x[nn[1]];
y2 = g->y[nn[1]];
x3 = g->x[nn[2]];
y3 = g->y[nn[2]];
if (g->etype[elem] == 3) {
aum = x2 * y3 - x3 * y2;
bum = y2 - y3;
cum = x3 - x2;
ado = x3 * y1 - x1 * y3;
bdo = y3 - y1;
cdo = x1 - x3;
atr = x1 * y2 - x2 * y1;
btr = y1 - y2;
ctr = x2 - x1;
arei = 1.0 / (aum + ado + atr);
w[2] = (atr + btr * xp + ctr * yp) * arei;
w[1] = (ado + bdo * xp + cdo * yp) * arei;
w[0] = 1.0 - w[1] - w[2];
return ELIO_OK;
} else {
nn[3] = g->icon[3][elem];
x4 = g->x[nn[3]];
y4 = g->y[nn[3]];
ibilinear(x1, x2, x3, x4, y1, y2, y3, y4, xp, yp, &xi, &eta, w);
return ELIO_OK;
}
return ELIO_ERR;
}
/*! Compute coefficients for interpolation for both triangles and quads using
* coordinates of the nodes rather than information from the element number.
*
* \param n Number of nodes in the element.
* \param x Pointer to array with x-coordinate of nodes.
* \param y Pointer to array with y-coordinate of nodes.
* \param xp X-coordinate of point for interpolation.
* \param yp Y-coordinate of point for interpolation.
* \param w Coefficients of interpolator.
*
* Returns ELIO_OK on success and ELIO_ERR on failure.
*/
int ElioGetCoefficientsXY(int n, double *x, double *y, double xp, double yp, double *w)
{
double aum, ado, atr, bum, bdo, btr, cum, cdo, ctr;
double x1, y1, x2, y2, x3, y3, x4, y4, c1, c2, c3, arei;
double xi, eta;
x1 = x[0];
y1 = y[0];
x2 = x[1];
y2 = y[1];
x3 = x[2];
y3 = y[2];
if (n == 3) {
aum = x2 * y3 - x3 * y2;
bum = y2 - y3;
cum = x3 - x2;
ado = x3 * y1 - x1 * y3;
bdo = y3 - y1;
cdo = x1 - x3;
atr = x1 * y2 - x2 * y1;
btr = y1 - y2;
ctr = x2 - x1;
arei = 1.0 / (aum + ado + atr);
w[2] = (atr + btr * xp + ctr * yp) * arei;
w[1] = (ado + bdo * xp + cdo * yp) * arei;
w[0] = 1.0 - w[1] - w[2];
return ELIO_OK;
}
if (n == 4) {
x4 = x[3];
y4 = y[3];
ibilinear(x1, x2, x3, x4, y1, y2, y3, y4, xp, yp, &xi, &eta, w);
return ELIO_OK;
} else {
return ELIO_ERR;
}
return ELIO_ERR;
}
/*!
* Define a header for the surface.
*/
int ElioGetSurfaceHeader(ElcircHeader * h1, ElcircHeader * h2)
{
int i, j;
strncpy(h2->magic, h1->magic, 48);
strncpy(h2->version, h1->version, 48);
strncpy(h2->start_time, h1->start_time, 48);
strncpy(h2->variable_nm, h1->variable_nm, 48);
strncpy(h2->variable_dim, h1->variable_dim, 48);
h2->nsteps = h1->nsteps;
h2->timestep = h1->timestep;
h2->skip = h1->skip;
h2->ivs = h1->ivs;
h2->i23d = h1->i23d;
h2->vpos = h1->vpos;
h2->zmsl = h1->zmsl;
h2->nvrt = h1->nvrt;
h2->zcor = (float *) malloc(h1->nvrt * sizeof(float));
for (i = 0; i < h1->nvrt; i++) {
h2->zcor = h1->zcor;
}
h2->np = h1->np;
h2->ne = h1->ne;
h2->x = (float *) malloc(h1->np * sizeof(float));
h2->y = (float *) malloc(h1->np * sizeof(float));
h2->d = (float *) malloc(h1->np * sizeof(float));
h2->bi = (int *) malloc(h1->np * sizeof(int));
h2->bisave = (int *) malloc(h1->np * sizeof(int));
h2->no = (int *) malloc(h1->np * sizeof(int)); /* offset into data for each node */
for (i = 0; i < h1->np; i++) {
h2->x[i] = h1->x[i];
h2->y[i] = h1->y[i];
h2->d[i] = h1->d[i];
h2->bisave[i] = h1->bisave[i];
h2->bi[i] = h1->bi[i];
}
h2->icon[0] = (int *) malloc(h1->ne * sizeof(int));
h2->icon[1] = (int *) malloc(h1->ne * sizeof(int));
h2->icon[2] = (int *) malloc(h1->ne * sizeof(int));
for (i = 0; i < h1->ne; i++) {
h2->icon[0][i] = h1->icon[0][i];
h2->icon[1][i] = h1->icon[0][i];
h2->icon[2][i] = h1->icon[0][i];
}
/* compute size of data in time step and offsets to each node */
h2->nitems = 0;
for (i = 0; i < h1->np; i++) {
h2->bi[i] = 1;
h2->no[i] = h2->nitems;
h2->nitems += 1;
}
/* get the header size in bytes */
/*h2->hsize = ftello(fp); */
/* get time step size in bytes */
h2->ssize = 8 + h2->np * 4 + h2->nitems * 4;
return ELIO_OK;
}
/*!
* Get a time step for the surface. Not implemented.
*/
int ElioGetSurfaceStep(ElcircHeader * h1, ElcircHeader * h2, ElcircTimeStep t1, ElcircTimeStep * t2)
{
return ELIO_OK;
}
/*!
* Define a header for the bottom. Not implemented.
*/
int ElioGetBottomHeader(ElcircHeader * h1, ElcircHeader * h2)
{
return ELIO_OK;
}
/*! Not implemented.
*/
int ElioGetBottomStep(ElcircHeader * h1, ElcircHeader * h2, ElcircTimeStep t1, ElcircTimeStep * t2)
{
return ELIO_OK;
}
/*! Not implemented.
*/
int ElioGetTransectHeader(ElcircHeader * h1, int n, double *x, double *y, ElcircHeader * h2)
{
return ELIO_OK;
}
/*! Not implemented.
*/
int ElioGetTransectStep(ElcircHeader * h1, ElcircHeader * h2, int step, int n, double *x, double *y, ElcircTimeStep t1, ElcircTimeStep * t2)
{
return ELIO_OK;
}
/*! Not implemented.
*/
int ElioGetLevelHeader(ElcircHeader * h1, ElcircHeader * h2)
{
return ELIO_OK;
}
/*! Not implemented.
*/
int ElioGetLevelStep(ElcircHeader * h1, ElcircHeader * h2, ElcircTimeStep t1, int level, ElcircTimeStep * t2)
{
return ELIO_OK;
}
/*! Not implemented.
*/
int ElioGetZLevelHeader(ElcircHeader * h1, ElcircHeader * h2)
{
return ELIO_OK;
}
/*! Not implemented.
*/
int ElioGetZLevelStep(ElcircHeader * h1, ElcircHeader * h2, ElcircTimeStep t1, float z, ElcircTimeStep * t2)
{
return ELIO_OK;
}
/*! Write the ELCIRC header.
* \param fp Pointer to open file handle.
* \param h Header struct to write.
*
* The structure to write should be prepared in advance with an allocated
* grid and all members filled in with appropriate values.
*/
int ElioPutHeader(FILE * fp, ElcircHeader * h)
{
int *itmp, i, j, bitmp, etmp;
if (fp == NULL) {
fprintf(stderr, "Bad file pointer\n");
return ELIO_ERR;
}
/*if (!(strncmp(h->magic, "DataFormat v3.0", 15) == 0)) {
fprintf(stderr, "ElioPutHeader(): Version identifier %s, must be 'DataFormat v3.0'\n", h->magic);
return (ELIO_ERR);
} */
if (fwrite(h->magic, sizeof(char), 48, fp) != 48)
return ELIO_FWRITE_ERR;
h->magic[48] = 0;
if (fseeko(fp, 48L, SEEK_SET)) {
return ELIO_FSEEK_ERR;
}
if (fwrite(h->version, sizeof(char), 48, fp) != 48)
return ELIO_FWRITE_ERR;
h->version[48] = 0;
if (fwrite(h->start_time, sizeof(char), 48, fp) != 48)
return ELIO_FWRITE_ERR;
h->start_time[48] = 0;
if (fwrite(h->variable_nm, sizeof(char), 48, fp) != 48)
return ELIO_FWRITE_ERR;
h->variable_nm[48] = 0;
if (fwrite(h->variable_dim, sizeof(char), 48, fp) != 48)
return ELIO_FWRITE_ERR;
h->variable_dim[48] = 0;
if (fwrite(&h->nsteps, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->timestep, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->skip, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->ivs, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->i23d, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (h->v == 3) {
if (fwrite(&h->vpos, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->zmsl, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->nvrt, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
} else if (h->v == 4) {
if (fwrite(&h->ivcor, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->h0, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->hc, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->thetab, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->thetaf, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->nvrt, sizeof(int), 1, fp) != 1)
return ELIO_FREAD_ERR;
} else if (h->v == 5) {
if (fwrite(&h->nvrt, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->kz, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->h0, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->hs, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->hc, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->thetab, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->thetaf, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
}
if (fwrite(h->zcor, sizeof(float), h->nvrt, fp) != h->nvrt)
return ELIO_FWRITE_ERR;
if (fwrite(&h->np, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&h->ne, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
for (i = 0; i < h->np; i++) {
if (fwrite(h->x + i, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(h->y + i, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(h->d + i, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (h->v != 4) {
bitmp = h->bisave[i]; /* subtracted 1 previously, have to add it back */
if (fwrite(&bitmp, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
}
}
/* for hybrid grids */
for (i = 0; i < h->ne; i++) {
if (fwrite(&h->etype[i], sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
for (j = 0; j < h->etype[i]; j++) {
etmp = h->icon[j][i] + 1; /* node number start from 0 internally, need to add 1 */
if (fwrite(&etmp, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
}
}
return ELIO_OK;
}
/*!
* Write a time step.
*
* \param fp Open filehandle.
* \param h Pointer to ELCIRC header.
* \param t Value parameter containing time step information to write.
*/
int ElioPutTimeStep(FILE * fp, ElcircHeader * h, ElcircTimeStep t)
{
if (fwrite(&t.t, sizeof(float), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (fwrite(&t.it, sizeof(int), 1, fp) != 1)
return ELIO_FWRITE_ERR;
if (h->v != 4) {
if (fwrite(t.surfind, sizeof(int), h->np, fp) != h->np)
return ELIO_FWRITE_ERR;
} else {
if (fwrite(t.e, sizeof(float), h->np, fp) != h->np)
return ELIO_FWRITE_ERR;
}
if (fwrite(t.d, sizeof(float), h->nitems, fp) != h->nitems)
return ELIO_FWRITE_ERR;
//printf("Completed Write of Time Step: Time, Step = %f, %d\n", t.t, t.it);
return ELIO_OK;
}
/*! Not implemented
*
*/
int ElioPutHeaderOld(FILE * fp, ElcircHeader * h)
{
return ELIO_OK;
}
/*! Not implemented
*
*/
int ElioPutTimeStepOld(FILE * fp, ElcircHeader * h, ElcircTimeStep t)
{
return ELIO_OK;
}
/*! Return the file type.
*
* Returns -1 on error.
*/
int ElioGetFileType(FILE * fp)
{
char id[100];
int retval = -1;
if (fread(id, sizeof(char), 15, fp) != 15) {
return retval;
}
id[15] = 0;
if (fseeko(fp, 0L, SEEK_SET)) {
return retval;
}
if (strcmp(id, "DataFormat v2.0") == 0) {
retval = 2;
} else if (strcmp(id, "DataFormat v3.0") == 0) {
retval = 3;
} else if (strcmp(id, "DataFormat v4.0") == 0) {
retval = 4;
} else if (strcmp(id, "DataFormat v5.0") == 0) {
retval = 5;
}
return retval;
}
/*!
* Copy header h1 to h2
*/
int ElioCopyHeader(ElcircHeader * h1, ElcircHeader * h2)
{
FILE *fp;
int *itmp, i, j, ss;
*h2 = *h1;
memcpy(h2->magic, h1->magic, 48);
memcpy(h2->version, h1->version, 48);
memcpy(h2->start_time, h1->start_time, 48);
memcpy(h2->variable_nm, h1->variable_nm, 48);
memcpy(h2->variable_dim, h1->variable_dim, 48);
h2->nsteps = h1->nsteps;
h2->timestep = h1->timestep;
h2->skip = h1->skip;
h2->ivs = h1->ivs;
h2->i23d = h1->i23d;
h2->vpos = h1->vpos;
h2->sigma = h1->sigma;
h2->zmsl = h1->zmsl;
h2->nvrt = h1->nvrt;
h2->zcor = (float *) malloc(h1->nvrt * sizeof(float));
for (i = 0; i < h1->nvrt; i++) {
h2->zcor[i] = h2->zcor[i];
}
h2->np = h1->np;
h2->ne = h1->ne;
h2->x = (float *) malloc(h1->np * sizeof(float));
h2->y = (float *) malloc(h1->np * sizeof(float));
h2->d = (float *) malloc(h1->np * sizeof(float));
h2->bi = (int *) malloc(h1->np * sizeof(int));
h2->bisave = (int *) malloc(h1->np * sizeof(int));
h2->no = (int *) malloc(h1->np * sizeof(int));
memcpy(h2->x, h1->x, h1->np * sizeof(float));
memcpy(h2->y, h1->y, h1->np * sizeof(float));
memcpy(h2->d, h1->d, h1->np * sizeof(float));
memcpy(h2->bi, h1->bi, h1->np * sizeof(int));
memcpy(h2->bisave, h1->bisave, h1->np * sizeof(int));
h2->etype = (int *) malloc(h1->ne * sizeof(int));
memcpy(h2->etype, h1->etype, h1->ne * sizeof(int));
h2->icon[0] = (int *) malloc(h1->ne * sizeof(int));
h2->icon[1] = (int *) malloc(h1->ne * sizeof(int));
h2->icon[2] = (int *) malloc(h1->ne * sizeof(int));
h2->icon[3] = (int *) malloc(h1->ne * sizeof(int));
memcpy(h2->icon[0], h1->icon[0], h1->ne * sizeof(int));
memcpy(h2->icon[1], h1->icon[1], h1->ne * sizeof(int));
memcpy(h2->icon[2], h1->icon[2], h1->ne * sizeof(int));
if (h1->icon[3] != NULL) {
memcpy(h2->icon[3], h1->icon[3], h1->ne * sizeof(int));
} else {
h2->icon[3] = NULL;
}
h2->nitems = h1->nitems;
memcpy(h2->bi, h1->bi, h1->np * sizeof(int));
memcpy(h2->bisave, h1->bisave, h1->np * sizeof(int));
memcpy(h2->no, h1->no, h1->np * sizeof(int));
h2->hsize = h1->hsize;
h2->ssize = h1->ssize;
return 0;
}
/*!
* Write out data to a single step .61 file
*/
int ElioPut61File(char *fn, ElcircHeader * h, double *v)
{
int i;
FILE *fp;
ElcircTimeStep t;
if ((fp = fopen(fn, "w")) == NULL) {
return ELIO_ERR;
}
if (ElioPutHeader(fp, h)) {
return ELIO_ERR;
}
ElioAllocateTimeStep(h, &t);
t.t = 0.0;
t.it = 1;
for (i = 0; i < h->np; i++) {
t.d[i] = v[i];
}
ElioPutTimeStep(fp, h, t);
ElioFreeTimeStep(&t);
fclose(fp);
return ELIO_OK;
}
/*!
* Return the area for the given element. Element numbering starts from 0.
*
* \param h - Previously read header.
* \param elem - Element number from 0 to compute the center.
*
* Returns 0.0 on error.
*/
double ElioGetElementArea(ElcircHeader * h, int elem)
{
int n1, n2, n3, n4;
double ar = 0.0;
double x1, y1, x2, y2, x3, y3, x4, y4;
if (elem >= 0 && elem < h->ne) {
n1 = h->icon[0][elem];
n2 = h->icon[1][elem];
n3 = h->icon[2][elem];
x1 = h->x[n1];
x2 = h->x[n2];
x3 = h->x[n3];
y1 = h->y[n1];
y2 = h->y[n2];
y3 = h->y[n3];
if (h->etype[elem] == 3) {
ar = 0.5 * ((x1 * y2 - x2 * y1) + (x2 * y3 - x3 * y2) + (x3 * y1 - x1 * y3));
} else if (h->etype[elem] == 4) {
n4 = h->icon[3][elem];
x4 = h->x[n4];
y4 = h->y[n4];
ar = 0.5 * ((x1 * y2 - x2 * y1) + (x2 * y3 - x3 * y2) + (x3 * y4 - x4 * y3) + (x4 * y1 - x1 * y4));
}
}
return ar;
}
/*!
* Return the center of the element 'elem' in (cx, cy).
*
* \param h - Previously read header.
* \param elem - Element number from 0 to compute the center.
* \param *cx - Returns x.
* \param *cy - Returns y.
*
* Returns ELIO_OK on success.
* Returns ELIO_ERR on failure.
*/
int ElioGetElementCenter(ElcircHeader * h, int elem, double *cx, double *cy)
{
int i, n;
if (!h || h->ne <= 0 || elem < 0 || (h->etype[elem] != 3 && h->etype[elem] != 4)) {
return ELIO_ERR;
}
*cx = *cy = 0.0;
for (i = 0; i < h->etype[elem]; i++) {
n = h->icon[i][elem];
*cx += h->x[n];
*cy += h->y[n];
}
*cx /= h->etype[elem];
*cy /= h->etype[elem];
return ELIO_OK;
}
/*!
* Return the center of the element 'elem' in (cx, cy).
*
* \param g - Previously read grid.
* \param elem - Element number from 0 to compute the center.
* \param *cx - Returns x.
* \param *cy - Returns y.
*
* Returns ELIO_OK on success.
* Returns ELIO_ERR on failure.
*/
int ElioGetGridElementCenter(ElioGrid * g, int elem, double *cx, double *cy)
{
int i, n;
if (!g || g->ne <= 0 || elem < 0 || (g->etype[elem] != 3 && g->etype[elem] != 4)) {
return ELIO_ERR;
}
*cx = *cy = 0.0;
for (i = 0; i < g->etype[elem]; i++) {
n = g->icon[i][elem];
*cx += g->x[n];
*cy += g->y[n];
}
*cx /= g->etype[elem];
*cy /= g->etype[elem];
return ELIO_OK;
}
/*!
* Return the area for the given element. Element numbering starts from 0.
*
* Returns 0.0 on error.
*/
double ElioGetGridElementArea(ElioGrid * g, int elem)
{
int n1, n2, n3, n4;
double ar = 0.0;
double x1, y1, x2, y2, x3, y3, x4, y4;
if (elem >= 0 && elem < g->ne) {
n1 = g->icon[0][elem];
n2 = g->icon[1][elem];
n3 = g->icon[2][elem];
x1 = g->x[n1];
x2 = g->x[n2];
x3 = g->x[n3];
y1 = g->y[n1];
y2 = g->y[n2];
y3 = g->y[n3];
if (g->etype[elem] == 3) {
ar = 0.5 * ((x1 * y2 - x2 * y1) + (x2 * y3 - x3 * y2) + (x3 * y1 - x1 * y3));
} else if (g->etype[elem] == 4) {
n4 = g->icon[3][elem];
x4 = g->x[n4];
y4 = g->y[n4];
ar = 0.5 * ((x1 * y2 - x2 * y1) + (x2 * y3 - x3 * y2) + (x3 * y4 - x4 * y3) + (x4 * y1 - x1 * y4));
}
}
return ar;
}
/*!
* Read a grid
*
* \param gname - Grid file name
* \param g - Pointer to a grid structure
*
* Returns ELIO_OK on success.
* Returns ELIO_ERR on failure.
*/
int ElioReadGrid(char *gname, ElioGrid * g)
{
FILE *fp;
char buf[1024];
int i;
if ((fp = fopen(gname, "rb")) == NULL) {
return ELIO_ERR;
}
fgets(buf, 255, fp);
fgets(buf, 255, fp);
sscanf(buf, "%d %d", &g->ne, &g->np);
g->x = (double *) malloc(g->np * sizeof(double));
g->y = (double *) malloc(g->np * sizeof(double));
g->d = (double *) malloc(g->np * sizeof(double));
g->etype = (int *) malloc(g->ne * sizeof(int));
for (i = 0; i < 4; i++) {
g->icon[i] = (int *) malloc(g->ne * sizeof(int));
}
for (i = 0; i < g->np; i++) {
fgets(buf, 255, fp);
sscanf(buf, "%*d %lf %lf %lf", &g->x[i], &g->y[i], &g->d[i]);
}
for (i = 0; i < g->ne; i++) {
fgets(buf, 255, fp);
sscanf(buf, "%*d %d %d %d %d %d", &g->etype[i], &g->icon[0][i], &g->icon[1][i], &g->icon[2][i], &g->icon[3][i]);
g->icon[0][i]--;
g->icon[1][i]--;
g->icon[2][i]--;
if (g->etype[i] == 3) {
g->icon[3][i] = -1;
} else {
g->icon[3][i]--;
}
}
/* could be a boundary in this grid file, try to read it
//3 = Number of open boundaries
//91 = Total number of open boundary nodes
//85 = Number of nodes for open boundary 1
if (fgets(buf, 255, fp) != NULL) {
if (sscanf(buf, "%d", &g->nopen) == 1) {
if (fgets(buf, 255, fp) != NULL) {
if (sscanf(buf, "%d", &g->ntotalopen) == 1) {
for (i=0;inopen;i++) {
if (sscanf(buf, "%d %d", &g->nopen) == 1) {
if (sscanf(buf, "%d", &g->ntotalopen) == 1) {
}
}
}
}
}
}
} */
fclose(fp);
return ELIO_OK;
}
/*!
* Free a grid
*
* \param g - Pointer to a grid structure with already allocated memory
*
* Returns ELIO_OK on success.
*
* No checking is done on validity of the pointers being freed
*/
int ElioFreeGrid(ElioGrid *g)
{
int i;
free(g->x);
free(g->y);
free(g->d);
free(g->etype);
for (i = 0; i < 4; i++) {
free(g->icon[i]);
}
return ELIO_OK;
}
int ElioFindElementInGrid(ElioGrid * g, double xp, double yp)
{
int i, j;
int n0, n1, n2, n3;
double x[4], y[4];
for (i = 0; i < g->ne; i++) {
for (j = 0; j < g->etype[i]; j++) {
x[j] = g->x[g->icon[j][i]];
y[j] = g->y[g->icon[j][i]];
}
//printf("ElioInsideElement %lf %lf %lf %lf %lf %lf %lf %lf\n", xp, yp, x[0], y[0], x[1], y[1], x[2], y[2]);
if (g->etype[i] == 3) {
if (ElioInsideElement(xp, yp, x[0], y[0], x[1], y[1], x[2], y[2])) {
return i;
}
} else {
if (ElioInsideElement4(xp, yp, x[0], y[0], x[1], y[1], x[2], y[2], x[3], y[3])) {
return i;
}
}
}
return -1;
}
int ElioGridFindNearestNode(ElioGrid * g, double x, double y)
{
int i, ind = -1;
double radius;
double tmp, *xord = g->x, *yord = g->y;
if (g->np > 0) {
radius = hypot((x - xord[0]), (y - yord[0]));
ind = 0;
for (i = 1; i < g->np; i++) {
tmp = hypot((x - xord[i]), (y - yord[i]));
if (tmp < radius) {
radius = tmp;
ind = i;
}
}
} else {
ind = -1;
}
return ind;
}
int ElioFindNearestNode(ElcircHeader * h, double x, double y)
{
int i, ind;
double radius;
double tmp;
float *xord = h->x, *yord = h->y;
if (h->np > 0) {
radius = hypot((x - xord[0]), (y - yord[0]));
ind = 0;
for (i = 1; i < h->np; i++) {
tmp = hypot((x - xord[i]), (y - yord[i]));
if (tmp < radius) {
radius = tmp;
ind = i;
}
}
} else {
ind = -1;
}
return ind;
}
int ElioWriteGrid(char *gname, ElioGrid * g)
{
FILE *fp;
char buf[1024];
int i;
if ((fp = fopen(gname, "wb")) == NULL) {
return ELIO_ERR;
}
fprintf(fp, "Grid\n");
fprintf(fp, "%d %d\n", g->ne, g->np);
for (i = 0; i < g->np; i++) {
fprintf(fp, "%d %lf %lf %lf\n", i + 1, g->x[i], g->y[i], g->d[i]);
}
for (i = 0; i < g->ne; i++) {
if (g->etype[i] == 3) {
fprintf(fp, "%d 3 %d %d %d\n", i + 1, g->icon[0][i] + 1, g->icon[1][i] + 1, g->icon[2][i] + 1);
} else if (g->etype[i] == 4) {
fprintf(fp, "%d 4 %d %d %d %d\n", i + 1, g->icon[0][i] + 1, g->icon[1][i] + 1, g->icon[2][i] + 1, g->icon[3][i] + 1);
}
}
fclose(fp);
return ELIO_OK;
}
/*!
* Time/date functions.
*/
static int corietime = 0;
static double coriestart = 0;
/*!
* Turn on CORIE time, should be called just once in any program.
* Multiple calls will foul things up, so don't do it.
*/
void ElioSetCorieTime(int b)
{
corietime = b;
if (b) {
putenv("TZ=PST");
coriestart = ElioGetDay(12, 31, 1995, 0, 0, 0);
} else {
coriestart = 0.0;
}
}
/*!
* Set corietime from a string. 4 digits for year.
*/
void ElioSetStartTime(int b, char *t)
{
int y, m, d, h, mi, s;
corietime = b;
if (b) {
sscanf(t, "%4d%2d%2d%2d%2d%2d", &y, &m, &d, &h, &mi, &s);
coriestart = ElioGetDay(m, d, y, h, mi, s);
} else {
coriestart = 0.0;
}
}
/*!
* Return the corietime constant. If non-zero then corie time is active.
*/
int ElioGetCorieDayConstant(void)
{
return corietime;
}
/*!
* Return corieday relative to now. The variable 'when' can be +-.
*/
double ElioGetCorieDay(int when)
{
double jd = 1;
time_t t;
t = time(NULL) + when * 86400;
jd = ElioGetDay(12, 31, 1995, 0, 0, 0);
jd = t / 86400.0 - jd;
return jd;
}
/*!
* Return the CORIE day or UNIX day + hms as a real number.
*/
double ElioGetDay(int mon, int day, int year, int h, int mi, double se)
{
double frac = (int) se - se;
struct tm t;
time_t j;
t.tm_sec = se;
t.tm_min = mi;
t.tm_hour = h;
t.tm_mday = day;
t.tm_mon = mon - 1;
t.tm_year = year - 1900;
j = mktime(&t);
return ((double) j / 86400.0 - coriestart);
}
/*!
* Convert a CORIE or UNIX day number to m-d-y hhmmss.
*/
void ElioGetDate(double jd, int *m, int *d, int *y, int *h, int *mi, double *sec)
{
struct tm *t;
time_t seconds = (jd + coriestart) * 86400.0;
t = gmtime(&seconds);
*sec = t->tm_sec;
*mi = t->tm_min;
*h = t->tm_hour;
*d = t->tm_mday;
*m = t->tm_mon + 1;
*y = t->tm_year + 1900;
}
/*!
* Convert a day number to y-yearday hhmmss.
*/
void ElioGetYearDay(double jd, int *y, int *yd, int *h, int *mi, double *sec)
{
struct tm *t;
time_t seconds = (jd + coriestart) * 86400.0;
t = gmtime(&seconds);
*sec = t->tm_sec;
*mi = t->tm_min;
*h = t->tm_hour;
*yd = t->tm_yday + 1;
*y = t->tm_year + 1900;
}
/*!
* Inverse bilinear mapping for quadrangles from Joseph.
* Convexity of the quad must have been checked, and (x,y) must
* be inside the quad.
*
*/
int ibilinear(double x1, double x2, double x3, double x4, double y1, double y2, double y3, double y4, double x, double y, double *xi, double *eta, double *shapef)
{
double axi[2], aet[2], bxy[2], root_xi[2], root_et[2];
double x0, y0, dxi, deta, dd, beta, delta, dgamma;
int i, j, icount, icaseno;
static double SMALL = 1.0e-5;
//!... Consts.
x0 = (x1 + x2 + x3 + x4) / 4.0;
y0 = (y1 + y2 + y3 + y4) / 4.0;
axi[0] = x2 - x1 + x3 - x4;
axi[1] = y2 - y1 + y3 - y4;
aet[0] = x3 + x4 - x1 - x2;
aet[1] = y3 + y4 - y1 - y2;
bxy[0] = x1 - x2 + x3 - x4;
bxy[1] = y1 - y2 + y3 - y4;
dxi = 2 * ((x3 - x4) * (y1 - y2) - (y3 - y4) * (x1 - x2));
deta = 2 * ((x4 - x1) * (y3 - y2) - (y4 - y1) * (x3 - x2));
//!... Inverse mapping
if ((fabs(bxy[0]) < SMALL && fabs(bxy[1]) < SMALL)
|| (fabs(dxi) < SMALL && fabs(deta) < SMALL)) {
icaseno = 1;
// if (dxi == 0.0 && deta == 0.0) {
dd = axi[0] * aet[1] - axi[1] * aet[0];
if (dd == 0.0) {
fprintf(stderr, "Case 1 error: %lf\n", dd);
return ELIO_ERR;
}
*xi = 4 * (aet[1] * (x - x0) - aet[0] * (y - y0)) / dd;
*eta = 4 * (axi[0] * (y - y0) - axi[1] * (x - x0)) / dd;
} else if (fabs(dxi) < SMALL && fabs(deta) >= SMALL) {
// } else if (dxi == 0 && deta != 0) {
icaseno = 2;
*eta = 4 * (bxy[1] * (x - x0) - bxy[1] * (y - y0)) / deta;
dd = (axi[0] + *eta * bxy[0]) * (axi[0] + *eta * bxy[0]) + (axi[1] + *eta * bxy[1]) * (axi[1] + *eta * bxy[1]);
if (dd == 0) {
fprintf(stderr, "Case 2 error: &lf\n", dd);
return ELIO_ERR;
}
*xi = ((4 * (x - x0) - *eta * aet[0]) * (axi[0] + *eta * bxy[0]) + (4 * (y - y0) - *eta * aet[1]) * (axi[1] + *eta * bxy[1])) / dd;
;
} else if (fabs(dxi) >= SMALL && fabs(deta) < SMALL) {
icaseno = 3;
// } else if (dxi != 0 && deta == 0) {
*xi = 4 * (bxy[1] * (x - x0) - bxy[0] * (y - y0)) / dxi;
dd = (aet[0] + *xi * bxy[0]) * (aet[0] + *xi * bxy[0]) + (aet[1] + *xi * bxy[1]) * (aet[1] + *xi * bxy[1]);
if (dd == 0) {
fprintf(stderr, "Case 3 error: &lf\n", dd);
return ELIO_ERR;
}
*eta = ((4 * (x - x0) - *xi * axi[0]) * (aet[0] + *xi * bxy[0]) + (4 * (y - y0) - *xi * axi[1]) * (aet[1] + *xi * bxy[1])) / dd;
;
} else {
icaseno = 4;
beta = aet[1] * axi[0] - aet[0] * axi[1] - 4 * (bxy[1] * (x - x0) - bxy[0] * (y - y0));
dgamma = 4 * (aet[0] * (y - y0) - aet[1] * (x - x0));
delta = beta * beta - 4 * dgamma * dxi;
if (delta == 0) {
*xi = (-beta / 2.0 / dxi);
*eta = (4 * (bxy[1] * (x - x0) - bxy[0] * (y - y0)) - *xi * dxi) / deta;
} else if (delta > 0.0) {
root_xi[0] = (-beta + sqrt(delta)) / 2 / dxi;
root_xi[1] = (-beta - sqrt(delta)) / 2 / dxi;
icount = 0;
for (i = 0; i < 2; i++) {
root_et[i] = (4 * (bxy[1] * (x - x0) - bxy[0] * (y - y0)) - root_xi[i] * dxi) / deta;
if (fabs(root_xi[i]) <= 1.1 && fabs(root_et[i]) <= 1.1) {
*xi = root_xi[i];
*eta = root_et[i];
icount = icount + 1;
}
}
if (icount == 2 && fabs(root_xi[0] - root_xi[1]) < SMALL) {
} else if (icount != 1) {
fprintf(stderr, "Abnormal instances %lf %lf %d\n", root_xi[0], root_et[1], icount);
return ELIO_ERR;
}
} else {
fprintf(stderr, "No roots %lf\n", delta);
return ELIO_ERR;
}
}
if (fabs(*xi) > 1.1 || fabs(*eta) > 1.1) {
fprintf(stderr, "Out of bound in ibilinear %lf %lf\n", *xi, *eta);
return ELIO_ERR;
}
*xi = (*xi > -1.0) ? *xi : -1.0;
*eta = (*eta > -1.0) ? *eta : -1.0;
*xi = (*xi < 1.0) ? *xi : 1.0;
*eta = (*eta < 1.0) ? *eta : 1.0;
//xi=dmin1(1.0,dmax1(xi,-1.0));
//eta=dmin1(1.0,dmax1(eta,-1.0));
shapef[0] = (1 - *xi) * (1 - *eta) / 4;
shapef[1] = (1 + *xi) * (1 - *eta) / 4;
shapef[2] = (1 + *xi) * (1 + *eta) / 4;
shapef[3] = (1 - *xi) * (1 + *eta) / 4;
return ELIO_OK;
}
static double C(double sigma, ElcircHeader * h)
{
return (1 - h->thetab) * sinh(h->thetaf * sigma) / sinh(h->thetaf) + h->thetab * (tanh(h->thetaf * (sigma + 0.5)) - tanh(h->thetaf * 0.5)) / (2.0 * tanh(h->thetaf * 0.5));
}
/*!
* Compute the depth at a given node and level for a sigma grid.
*
* Input variables:
*
* \param node = Node number starting from 0
* \param level = Level number starting from 0
* \param eh = Pointer to populated ElcircHeader struct
*
* Returns depth.
*
* Fortran code from ELCIRC
*
* do k=1,nvrt
* z(i,k)=peta(i)*(1+sigma(k))+h_c*sigma(k)+(dp(i)-h_c)*cs(k)
* ! Abnormal cases
* if(ivcor==2.and.(dp(i)<=h_c.or.peta(i)<=-h_c-(dp(i)-h_c)*theta_f/dsinh(theta_f))) then
* iback(i)=0
* z(i,k)=peta(i)*(1+sigma(k))+dp(i)*sigma(k)
* endif
* if(k>=2.and.z(i,k)-z(i,k-1)<=0) then
* write(11,*)'Inverted z-levels at:',i,k,z(i,k)-z(i,k-1),peta(i),dp(i)
* stop
* endif
* enddo !k
*
*/
double ElioGetSigmaDepthAtNode(int node, int level, float eta, ElcircHeader * eh)
{
double z, sigma, h;
sigma = eh->zcor[level];
h = eh->d[node];
if (eh->ivcor == 1) {
z = (h + eta) * sigma + eta;
} else if (eh->ivcor == 2) {
if ((eta + h) > eh->h0 && h > eh->hc && eta > (-eh->hc - (h - eh->hc) * eh->thetaf / sinh(eh->thetaf))) {
z = eta * (1.0 + sigma) + eh->hc * eta + (h - eh->hc) * C(sigma, eh);
} else {
z = (h + eta) * sigma + eta;
}
}
return z;
}
int ElioGetSigmaDepth(int node, float eta, ElcircHeader * eh, double *depths)
{
double z, sigma, h;
int i;
for (i = 0; i < eh->nvrt; i++) {
depths[i] = ElioGetSigmaDepthAtNode(node, i, eta, eh);
}
return ELIO_OK;
}
/*!
* Compute the depth at a given XY location and level for a sigma grid.
*
* Input variables:
*
* \param x = X co-ordinate of location
* \param y = Y co-ordinate of location
* \param level = Level number starting from 0
* \param eh = Pointer to populated ElcircHeader struct
*
* Returns depth.
*
*/
double ElioGetSigmaDepthAtXY(double x, double y, int level, float e, ElcircHeader * eh)
{
double H, h, eta, sigma;
/* Need to interpolate elevation and depth */
//H = eh->d[node] + e;
h = H * eh->zcor[level] + e;
return h;
}
/*!
* Compute the depth at a given XYZ location for a sigma grid.
*
* Input variables:
*
* \param x = X co-ordinate of location
* \param y = Y co-ordinate of location
* \param z = z co-ordinate of location
* \param eh = Pointer to populated ElcircHeader struct
*
* Returns depth.
*
*/
double ElioGetSigmaDepthAtXYZ(double x, double y, double z, float e, ElcircHeader * eh)
{
double H, h, eta, sigma;
//H = eh->d[node] + e;
//h = H * eh->zcor[level] + e;
return h;
}
/*!
* Return the min/max value in an array of doubles, utility function.
*
* Input variables:
*
* \param n = Number of doubles.
* \param ar = Pointer to the doubles - assumed to be a valid pointer.
*
* Returns minimum double found in the array.
*
*/
int ElioMinMax(int n, double *ar, double *dmin, double *dmax)
{
int i;
if (ar == (double *) NULL) {
return ELIO_ERR;
}
*dmax = *dmin = ar[0];
for (i = 1; i < n; i++) {
if (*dmin > ar[i]) {
*dmin = ar[i];
}
if (*dmax < ar[i]) {
*dmax = ar[i];
}
}
return ELIO_OK;
}
/*!
* Return the minimum value in an array of ints, utility function.
*
* Input variables:
*
* \param n = Number of integers.
* \param iar = Pointer to the integers - assumed to be a valid pointer.
*
* Returns minimum integer found in the array.
*
*/
int ElioIntMin(int n, int *iar)
{
int i, im = 0;
im = iar[0];
for (i = 1; i < n; i++) {
if (im > iar[i]) {
im = iar[i];
}
}
return im;
}
/*!
* Return the maximum value in an array of ints, utility function.
*
* Input variables:
*
* \param n = Number of integers.
* \param iar = Pointer to the integers - assumed to be a valid pointer.
*
* Returns maximum integer found in the array.
*
*/
int ElioIntMax(int n, int *iar)
{
int i, im = 0;
im = iar[0];
for (i = 1; i < n; i++) {
if (im < iar[i]) {
im = iar[i];
}
}
return im;
}
/*!
* Return the numeric file version number 2, 3, 4
*
* Input variables:
*
* \param fname = File name.
*
*/
int ElioGetFileVersion(char *fname)
{
FILE *fp;
char magic[50];
fp = fopen(fname, "rb");
if (fp == NULL) {
fprintf(stderr, "ElioGetFileVersion(): Unable to open file %s\n", fname);
return -1;
}
if (fread(magic, sizeof(char), 48, fp) != 48)
return ELIO_FREAD_ERR;
magic[48] = 0;
/* DataFormat v3.0 */
if (strncmp(magic, "DataFormat v4.0", 15) == 0) {
return 4;
} else if (strncmp(magic, "DataFormat v5.0", 15) == 0) {
return 5;
} else if (strncmp(magic, "DataFormat v3.0", 15) == 0) {
return 3;
} else if (strncmp(magic, "DataFormat v2.0", 15) == 0) {
return 2;
} else {
return -1;
}
fclose(fp);
}
/*!
* Find the interval in an array containing the double d, return -1
* if no interval found. Data point is located in between index returned
* and index + 1.
*
* Input variables:
*
* \param n = Number of items in *data.
* \param data = Array to search.
* \param d = Item to locate.
*
* Returns 0 based index found or -1 if less than or n if greater than.
*
*/
int ElioFindIndex(int n, double *data, double d)
{
int i;
if (d < data[0]) {
return -1;
}
if (d > data[n - 1]) {
return n;
}
for (i = 0; i < n - 1; i++) {
if (d >= data[i] && d <= data[i + 1]) {
return i;
}
}
/* Not reached */
return -1;
}
/*!
* Given an array of depths and scalar quatities, interpolate
* the scalar values to all the points in *zp. Clamp to values at
* either end if point to find is out of range. Output to *sp.
*
* Input variables:
*
* \param n = Number of items in *z.
* \param z = Depths.
* \param s = Scalar value.
* \param np = number of points to interpolate.
* \param zp = Depths to interpolate to.
* \param sp = Interpolated scalar values.
*/
void ElioInterpolateArray(int n, double *z, double *s, int np, double *zp, double *sp)
{
int i, j, l1, l2;
double tmp;
for (j = 0; j < np; j++) {
/* Use minimum value */
if (zp[j] < z[0]) {
sp[j] = s[0];
/* Use maximum value */
} else if (zp[j] > z[n - 1]) {
sp[j] = s[n - 1];
/* Use interpolated value */
} else {
for (i = 0; i < n - 1; i++) {
l1 = i;
l2 = i + 1;
if (zp[j] >= z[l1] && zp[j] <= z[l2]) {
break;
}
}
tmp = (z[l2] - z[l1]);
if (tmp != 0.0) {
sp[j] = (zp[j] - z[l1]) / (z[l2] - z[l1]) * (s[l2] - s[l1]) + s[l1];
} else {
fprintf(stderr, "Elio: In ElioInterpolateArray(), z[l2] - z[l1] == 0.0\n");
sp[j] = -9999.0;
}
}
}
}
/*!
* Given an array of depths and scalar quantities, interpolate
* a scalar value given the depth. Clamp to value at
* either end if point to find is out of range. returns the
* interplated value.
*
* Input variables:
*
* \param n = Number of items in *z.
* \param z = Depths.
* \param s = Scalar value.
* \param zp = Depth to interpolate to.
*/
double ElioInterpolate(int n, double *z, double *s, double zp)
{
int i, l1, l2;
double sp = 0.0;
double tmp;
/* Use minimum value */
if (zp < z[0]) {
sp = s[0];
/* Use maximum value */
} else if (zp > z[n - 1]) {
sp = s[n - 1];
/* Use interpolated value */
} else {
for (i = 0; i < n - 1; i++) {
l1 = i;
l2 = i + 1;
if (zp >= z[l1] && zp <= z[l2]) {
break;
}
}
tmp = (z[l2] - z[l1]);
if (tmp != 0.0) {
sp = (zp - z[l1]) / (z[l2] - z[l1]) * (s[l2] - s[l1]) + s[l1];
} else {
fprintf(stderr, "Elio: In ElioInterpolate(), z[l2] - z[l1] == 0.0\n");
sp = -9999.0;
}
}
return sp;
}
/*!
* Given an array of depths and scalar quantities, interpolate
* a scalar value given the index as found from ElioFindIndex().
* Clamp to value at either end if point to find is out of range.
*
* Input variables:
*
* \param n = Number of items in *z.
* \param z = Depths.
* \param s = Scalar value.
* \param ind = Index value.
* \param zp = Depth to use for interpolation.
*/
double ElioInterpolateAtIndex(int n, double *z, double *s, int ind, double zp)
{
int i, l1, l2;
double sp = 0.0;
double tmp;
/* Use minimum value */
if (ind < 0) {
sp = s[0];
/* Use maximum value */
} else if (ind == n) {
sp = s[n - 1];
/* Use interpolated value */
} else {
l1 = ind;
l2 = ind + 1;
tmp = (z[l2] - z[l1]);
if (tmp != 0.0) {
sp = (zp - z[l1]) / (z[l2] - z[l1]) * (s[l2] - s[l1]) + s[l1];
} else {
//fprintf(stderr, "Elio: In ElioInterpolateAtIndex(), z[l2] - z[l1] == 0.0\n");
sp = -9999.0;
}
}
return sp;
}
/*!
* Given an array of depths and scalar quantities, interpolate
* a scalar value given the index as found from ElioFindIndex().
* Clamp to value at either end if point to find is out of range.
*
* Input variables:
*
* \param n = Number of items in *z.
* \param z = Depths.
* \param s = Scalar value.
* \param ind = Index value.
* \param zp = Depth to use for interpolation.
*/
int ElioMakeDepthsOld(ElcircHeader * h, float *d, float *dd)
{
int i, j, k;
for (i = 0; i < h->np * h->nvrt; i++) {
dd[i] = -99.0;
}
for (j = 0; j < h->np; j++) {
// Fill in missing depth values in file - only for Z levels.
for (k = 0; k < h->kz; k++) {
dd[j * h->nvrt + k] = h->zcor[k];
}
// Fill in depth values from zcor.
for (k = h->bi[j]; k < h->nvrt; k++) {
dd[j * h->nvrt + k] = d[h->no[j] + k - h->bi[j]];
}
}
return ELIO_OK;
}
/*!
* Replace the nodes in the grid h with the nodes found in grid g.
*
* Useful for transforming a run done in one projection to another.
*
*/
int ElioReplaceElcircGrid(ElcircHeader * h, ElioGrid * g)
{
int i;
if (h->np != g->np) {
return ELIO_ERR;
}
for (i = 0; i < g->np; i++) {
h->x[i] = g->x[i];
h->y[i] = g->y[i];
}
return ELIO_OK;
}
/*!
* Get the grid from a header and stuff it in an ElioGrid struture
*
*/
int ElioGetGrid(ElcircHeader * h, ElioGrid * g)
{
int i;
g->ne = h->ne;
g->np = h->np;
g->x = (double *) malloc(g->np * sizeof(double));
g->y = (double *) malloc(g->np * sizeof(double));
g->d = (double *) malloc(g->np * sizeof(double));
g->etype = (int *) malloc(g->ne * sizeof(int));
for (i = 0; i < 4; i++) {
g->icon[i] = (int *) malloc(g->ne * sizeof(int));
}
for (i = 0; i < g->np; i++) {
g->x[i] = h->x[i];
g->y[i] = h->y[i];
g->d[i] = h->d[i];
}
for (i = 0; i < g->ne; i++) {
g->etype[i] = h->etype[i];
g->icon[0][i] = h->icon[0][i];
g->icon[1][i] = h->icon[1][i];
g->icon[2][i] = h->icon[2][i];
if (g->etype[i] == 4) {
g->icon[3][i] = h->icon[3][i];
}
}
return ELIO_OK;
}