home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: Science
/
Science.zip
/
gmt_os2.zip
/
src
/
gmt_cdf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-23
|
17KB
|
513 lines
/*--------------------------------------------------------------------
* The GMT-system: @(#)gmt_cdf.c 2.19 2/23/95
*
* Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
* See README file for copying and redistribution conditions.
*--------------------------------------------------------------------*/
/*
*
* G M T _ C D F . C R O U T I N E S
*
* Takes care of all grd input/output built on NCAR's netCDF routines (which is
* an XDR implementation)
* Most functions return the ncerr error value which will be non-zero if
* an error occured.
*
* Author: Paul Wessel
* Date: 9-SEP-1992
* Modified: 27-JUN-1995
* Version: 3.0
*
* Functions include:
*
* cdf_read_grd_info : Read header from file
* cdf_read_grd : Read header and data set from file
* cdf_write_grd_info : Update header in existing file
* cdf_write_grd : Write header and data set to new file
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
#include "gmt.h"
int cdf_read_grd_info (file, header)
char *file;
struct GRD_HEADER *header; {
nclong cdfid, nm[2], start[2], edge[2];
double dummy[2];
char text[480];
/* variable ids */
nclong x_range_id, y_range_id, z_range_id, inc_id, nm_id, z_id;
if (!strcmp (file,"=")) { /* Check if piping is attempted */
fprintf (stderr, "%s: GMT Fatal Error: netcdf-based i/o does not support piping - exiting\n", gmt_program);
exit (-1);
}
/* Open file and get info */
if (ncopts) ncopts = 0;
if ((cdfid = ncopen (file, NC_NOWRITE)) == -1) return (-1);
/* Get variable ids */
x_range_id = ncvarid (cdfid, "x_range");
y_range_id = ncvarid (cdfid, "y_range");
z_range_id = ncvarid (cdfid, "z_range");
inc_id = ncvarid (cdfid, "spacing");
nm_id = ncvarid (cdfid, "dimension");
z_id = ncvarid (cdfid, "z");
/* Get attributes */
ncattget (cdfid, x_range_id, "units", (void *)header->x_units);
ncattget (cdfid, y_range_id, "units", (void *)header->y_units);
ncattget (cdfid, z_range_id, "units", (void *)header->z_units);
ncattget (cdfid, z_id, "long_name", (void *)header->title);
ncattget (cdfid, z_id, "scale_factor", (void *) &header->z_scale_factor);
ncattget (cdfid, z_id, "add_offset", (void *) &header->z_add_offset);
ncattget (cdfid, z_id, "node_offset", (void *) &header->node_offset);
ncattget (cdfid, NC_GLOBAL, "title", (void *)header->title);
ncattget (cdfid, NC_GLOBAL, "source", (void *)text);
strncpy (header->command, text, 320);
strncpy (header->remark, &text[320], 160);
/* Get variables */
start[0] = 0;
edge[0] = 2;
ncvarget(cdfid, x_range_id, start, edge, (void *)dummy);
header->x_min = dummy[0];
header->x_max = dummy[1];
ncvarget(cdfid, y_range_id, start, edge, (void *)dummy);
header->y_min = dummy[0];
header->y_max = dummy[1];
ncvarget(cdfid, inc_id, start, edge, (void *)dummy);
header->x_inc = dummy[0];
header->y_inc = dummy[1];
ncvarget(cdfid, nm_id, start, edge, (void *)nm);
header->nx = nm[0];
header->ny = nm[1];
ncvarget(cdfid, z_range_id, start, edge, (void *)dummy);
header->z_min = dummy[0];
header->z_max = dummy[1];
ncclose (cdfid);
return (ncerr);
}
int cdf_write_grd_info (file, header)
char *file;
struct GRD_HEADER *header; {
nclong cdfid, start[2], edge[2], nm[2];
double dummy[2];
char text[480];
/* variable ids */
nclong x_range_id, y_range_id, z_range_id, inc_id, nm_id, z_id;
if (!strcmp (file,"=")) { /* Check if piping is attempted */
fprintf (stderr, "%s: GMT Fatal Error: netcdf-based i/o does not support piping - exiting\n", gmt_program);
exit (-1);
}
/* Open file and get info */
if (ncopts) ncopts = 0;
if ((cdfid = ncopen (file, NC_WRITE)) == -1) return (-1);
/* Get variable ids */
x_range_id = ncvarid (cdfid, "x_range");
y_range_id = ncvarid (cdfid, "y_range");
z_range_id = ncvarid (cdfid, "z_range");
inc_id = ncvarid (cdfid, "spacing");
nm_id = ncvarid (cdfid, "dimension");
z_id = ncvarid (cdfid, "z");
/* rewrite attributes */
memset (text, 0, 480);
strcpy (text, header->command);
strcpy (&text[320], header->remark);
ncattput (cdfid, x_range_id, "units", NC_CHAR, 80, (void *)header->x_units);
ncattput (cdfid, y_range_id, "units", NC_CHAR, 80, (void *)header->y_units);
ncattput (cdfid, z_range_id, "units", NC_CHAR, 80, (void *)header->z_units);
ncattput (cdfid, z_id, "long_name", NC_CHAR, 80, (void *)header->title);
ncattput (cdfid, z_id, "scale_factor", NC_DOUBLE, 1,(void *) &header->z_scale_factor);
ncattput (cdfid, z_id, "add_offset", NC_DOUBLE, 1,(void *) &header->z_add_offset);
ncattput (cdfid, z_id, "node_offset", NC_LONG, 1,(void *) &header->node_offset);
ncattput (cdfid, NC_GLOBAL, "title", NC_CHAR, 80, (void *)header->title);
ncattput (cdfid, NC_GLOBAL, "source", NC_CHAR, 480, (void *)text);
/* rewrite header information */
start[0] = 0;
edge[0] = 2;
dummy[0] = header->x_min;
dummy[1] = header->x_max;
ncvarput(cdfid, x_range_id, start, edge, (void *)dummy);
dummy[0] = header->y_min;
dummy[1] = header->y_max;
ncvarput(cdfid, y_range_id, start, edge, (void *)dummy);
dummy[0] = header->x_inc;
dummy[1] = header->y_inc;
ncvarput(cdfid, inc_id, start, edge, (void *)dummy);
nm[0] = header->nx;
nm[1] = header->ny;
ncvarput(cdfid, nm_id, start, edge, (void *)nm);
dummy[0] = header->z_min;
dummy[1] = header->z_max;
ncvarput(cdfid, z_range_id, start, edge, (void *)dummy);
ncclose (cdfid);
return (ncerr);
}
int cdf_read_grd (file, header, grid, w, e, s, n, pad, complex)
char *file;
struct GRD_HEADER *header;
float *grid;
double w, e, s, n; /* Sub-region to extract. Use entire file if 0,0,0,0 */
int pad[]; /* padding on w, e, s, n of grid, respectively */
BOOLEAN complex; /* TRUE if array is to hold real and imaginary parts */
{
/*
* Reads a subset of a grdfile and optionally pads the array with extra rows and columns
* header values for nx and ny are reset to reflect the dimensions of the logical array,
* not the physical size (i.e., the padding is not counted in nx and ny)
*/
nclong cdfid, z_id, j2, one_or_zero, *k, start[2], edge[2];
nclong first_col, last_col, first_row, last_row;
nclong i, j, ij, width_in, width_out, height_in, i_0_out, inc = 1;
BOOLEAN geo = FALSE;
float *tmp;
double off, half_or_zero, x, small;
/* Open file and get info */
if (!strcmp (file,"=")) { /* Check if piping is attempted */
fprintf (stderr, "%s: GMT Fatal Error: netcdf-based i/o does not support piping - exiting\n", gmt_program);
exit (-1);
}
if (ncopts) ncopts = 0;
if ((cdfid = ncopen (file, NC_NOWRITE)) == -1) return (-1);
/* Get variable id */
z_id = ncvarid (cdfid, "z");
if (w == 0.0 && e == 0.0) { /* Get entire file */
w = header->x_min;
e = header->x_max;
s = header->y_min;
n = header->y_max;
}
/* Must deal with a subregion */
if (w < header->x_min || e > header->x_max) geo = TRUE; /* Dealing with periodic grid */
one_or_zero = (header->node_offset) ? 0 : 1;
off = (header->node_offset) ? 0.0 : 0.5;
/* Get dimension of subregion */
width_in = rint ((e - w) / header->x_inc) + one_or_zero;
height_in = rint ((n - s) / header->y_inc) + one_or_zero;
/* Get first and last row and column numbers */
small = 0.1 * header->x_inc;
first_col = floor ((w - header->x_min + small) / header->x_inc);
last_col = ceil ((e - header->x_min - small) / header->x_inc) - 1 + one_or_zero;
small = 0.1 * header->y_inc;
first_row = floor ((header->y_max - n + small) / header->y_inc);
last_row = ceil ((header->y_max - s - small) / header->y_inc) - 1 + one_or_zero;
if ((last_col - first_col + 1) > width_in) last_col--;
if ((last_row - first_row + 1) > height_in) last_row--;
if ((last_col - first_col + 1) > width_in) first_col++;
if ((last_row - first_row + 1) > height_in) first_row++;
width_out = width_in; /* Width of output array */
if (pad[0] > 0) width_out += pad[0];
if (pad[1] > 0) width_out += pad[1];
i_0_out = pad[0]; /* Edge offset in output */
if (complex) { /* Need twice as much space and load every 2nd cell */
width_out *= 2;
i_0_out *= 2;
inc = 2;
}
if (geo) { /* Must rollover in longitudes */
tmp = (float *) memory (CNULL, (int)header->nx, sizeof (float), "cdf_read_grd");
k = (nclong *) memory (CNULL, (int)width_in, sizeof (nclong), "cdf_read_grd");
half_or_zero = (header->node_offset) ? 0.5 : 0.0;
edge[0] = header->nx;
small = 0.1 * header->x_inc; /* Anything smaller than 0.5 dx will do */
for (i = 0; i < width_in; i++) {
x = w + (i + half_or_zero) * header->x_inc;
if ((header->x_min - x) > small)
x += 360.0;
else if ((x - header->x_max) > small)
x -= 360.0;
k[i] = (nclong) floor (((x - header->x_min) / header->x_inc) + off);
}
for (j = first_row, j2 = 0; j <= last_row; j++, j2++) {
start[0] = j * header->nx;
ncvarget (cdfid, z_id, start, edge, (void *)tmp); /* Get one row */
ij = (j2 + pad[3]) * width_out + i_0_out;
for (i = 0; i < width_in; i++) grid[ij+i*inc] = tmp[k[i]];
}
free ((char *)k);
}
else { /* A bit easier here */
if (complex) tmp = (float *) memory (CNULL, (int)width_in, sizeof (float), "cdf_read_grd");
edge[0] = width_in;
for (j = first_row, j2 = 0; j <= last_row; j++, j2++) {
start[0] = j * header->nx + first_col;
ij = (j2 + pad[3]) * width_out + i_0_out;
if (complex) {
ncvarget (cdfid, z_id, start, edge, (void *)tmp);
for (i = 0; i < width_in; i++) grid[ij+2*i] = tmp[i];
}
else
ncvarget (cdfid, z_id, start, edge, (void *)&grid[ij]);
}
}
header->nx = width_in;
header->ny = height_in;
header->x_min = w;
header->x_max = e;
header->y_min = s;
header->y_max = n;
header->z_min = MAXDOUBLE; header->z_max = -MAXDOUBLE;
for (j = 0; j < header->ny; j++) {
for (i = 0; i < header->nx; i++) {
j2 = (complex) ? 2 * (i + pad[0]) : i + pad[0];
ij = (j + pad[3]) * width_out + j2;
if (bad_float ((double)grid[ij])) continue;
header->z_min = MIN (header->z_min, grid[ij]);
header->z_max = MAX (header->z_max, grid[ij]);
}
}
ncclose (cdfid);
if (complex || geo) free ((char *)tmp);
return (ncerr);
}
int cdf_write_grd (file, header, grid, w, e, s, n, pad, complex)
char *file;
struct GRD_HEADER *header;
float *grid;
double w, e, s, n; /* Sub-region to write out */
int pad[]; /* padding on w, e, s, n of grid, respectively */
BOOLEAN complex; /* TRUE if array is to hold real and imaginary parts */
{
nclong start[2], edge[2];
nclong i, i2, cdfid, nm[2], inc = 1, *k;
nclong j, ij, j2, width_in, width_out, height_out, one_or_zero;
nclong first_col, last_col, first_row, last_row;
BOOLEAN geo = FALSE;
double dummy[2], off, half_or_zero, small, x;
char text[480];
float *tmp;
/* dimension ids */
nclong side_dim, xysize_dim;
/* variable ids */
nclong x_range_id, y_range_id, z_range_id, inc_id, nm_id, z_id;
/* variable shapes */
int dims[1];
if (!strcmp (file,"=")) { /* Check if piping is attempted */
fprintf (stderr, "%s: GMT Fatal Error: netcdf-based i/o does not support piping - exiting\n", gmt_program);
exit (-1);
}
if (w == 0.0 && e == 0.0) { /* Write entire grid */
w = header->x_min;
e = header->x_max;
s = header->y_min;
n = header->y_max;
pad[0] = pad[1] = pad[2] = pad[3] = 0;
}
if (w < header->x_min || e > header->x_max) geo = TRUE; /* Dealing with periodic grid */
one_or_zero = (header->node_offset) ? 0 : 1;
off = (header->node_offset) ? 0.0 : 0.5;
/* Create file and enter define mode */
if (ncopts) ncopts = 0;
if ((cdfid = nccreate (file, NC_CLOBBER)) == -1) return (-1);
/* Get dimension of subregion to write */
width_out = rint ((e - w) / header->x_inc) + one_or_zero;
height_out = rint ((n - s) / header->y_inc) + one_or_zero;
/* Get first and last row and column numbers */
small = 0.1 * header->x_inc;
first_col = floor ((w - header->x_min + small) / header->x_inc);
last_col = ceil ((e - header->x_min - small) / header->x_inc) -1 + one_or_zero;
small = 0.1 * header->y_inc;
first_row = floor ((header->y_max - n + small) / header->y_inc);
last_row = ceil ((header->y_max - s - small) / header->y_inc) -1 + one_or_zero;
if ((last_col - first_col + 1) > width_out) last_col--;
if ((last_row - first_row + 1) > height_out) last_row--;
if ((last_col - first_col + 1) > width_out) first_col++;
if ((last_row - first_row + 1) > height_out) first_row++;
width_in = width_out; /* Physical width of input array */
if (pad[0] > 0) width_in += pad[0];
if (pad[1] > 0) width_in += pad[1];
edge[0] = width_out;
if (complex) inc = 2;
header->x_min = w;
header->x_max = e;
header->y_min = s;
header->y_max = n;
/* define dimensions */
side_dim = ncdimdef(cdfid, "side", 2);
xysize_dim = ncdimdef(cdfid, "xysize", (int) (width_out * height_out));
/* define variables */
dims[0] = side_dim;
x_range_id = ncvardef (cdfid, "x_range", NC_DOUBLE, 1, dims);
y_range_id = ncvardef (cdfid, "y_range", NC_DOUBLE, 1, dims);
z_range_id = ncvardef (cdfid, "z_range", NC_DOUBLE, 1, dims);
inc_id = ncvardef (cdfid, "spacing", NC_DOUBLE, 1, dims);
nm_id = ncvardef (cdfid, "dimension", NC_LONG, 1, dims);
dims[0] = xysize_dim;
z_id = ncvardef (cdfid, "z", NC_FLOAT, 1, dims);
/* assign attributes */
strcpy (text, header->command);
strcpy (&text[320], header->remark);
ncattput (cdfid, x_range_id, "units", NC_CHAR, 80, (void *)header->x_units);
ncattput (cdfid, y_range_id, "units", NC_CHAR, 80, (void *)header->y_units);
ncattput (cdfid, z_range_id, "units", NC_CHAR, 80, (void *)header->z_units);
ncattput (cdfid, z_id, "long_name", NC_CHAR, 80, (void *)header->title);
ncattput (cdfid, z_id, "scale_factor", NC_DOUBLE, 1,(void *) &header->z_scale_factor);
ncattput (cdfid, z_id, "add_offset", NC_DOUBLE, 1,(void *) &header->z_add_offset);
ncattput (cdfid, z_id, "node_offset", NC_LONG, 1,(void *) &header->node_offset);
ncattput (cdfid, NC_GLOBAL, "title", NC_CHAR, 80, (void *)header->title);
ncattput (cdfid, NC_GLOBAL, "source", NC_CHAR, 480, (void *)text);
/* leave define mode */
ncendef (cdfid);
/* Find xmin/zmax */
header->z_min = MAXDOUBLE; header->z_max = -MAXDOUBLE;
for (j = first_row, j2 = pad[3]; j <= last_row; j++, j2++) {
for (i = first_col, i2 = pad[0]; i <= last_col; i++, i2++) {
ij = (j2 * width_in + i2) * inc;
if (bad_float ((double)grid[ij])) continue;
header->z_min = MIN (header->z_min, grid[ij]);
header->z_max = MAX (header->z_max, grid[ij]);
}
}
/* store header information and array */
start[0] = 0;
edge[0] = 2;
dummy[0] = header->x_min;
dummy[1] = header->x_max;
ncvarput(cdfid, x_range_id, start, edge, (void *)dummy);
dummy[0] = header->y_min;
dummy[1] = header->y_max;
ncvarput(cdfid, y_range_id, start, edge, (void *)dummy);
dummy[0] = header->x_inc;
dummy[1] = header->y_inc;
ncvarput(cdfid, inc_id, start, edge, (void *)dummy);
nm[0] = width_out;
nm[1] = height_out;
ncvarput(cdfid, nm_id, start, edge, (void *)nm);
dummy[0] = header->z_min;
dummy[1] = header->z_max;
ncvarput(cdfid, z_range_id, start, edge, (void *)dummy);
edge[0] = width_out;
if (geo) {
tmp = (float *) memory (CNULL, (int)width_in, sizeof (float), "cdf_write_grd");
k = (nclong *) memory (CNULL, (int)width_out, sizeof (nclong), "cdf_write_grd");
half_or_zero = (header->node_offset) ? 0.5 : 0.0;
edge[0] = header->nx;
small = 0.1 * header->x_inc; /* Anything smaller than 0.5 dx will do */
for (i = 0; i < width_out; i++) {
x = w + (i + half_or_zero) * header->x_inc;
if ((header->x_min - x) > small)
x += 360.0;
else if ((x - header->x_max) > small)
x -= 360.0;
k[i] = (nclong) floor (((x - header->x_min) / header->x_inc) + off);
}
i2 = first_col + pad[0];
for (j = 0, j2 = first_row + pad[3]; j < height_out; j++, j2++) {
ij = j2 * width_in + i2;
start[0] = j * width_out;
for (i = 0; i < width_out; i++) tmp[i] = grid[inc * (ij+k[i])];
ncvarput (cdfid, z_id, start, edge, (void *)tmp);
}
free ((char *)k);
}
else {
if (complex) tmp = (float *) memory (CNULL, (int)width_in, sizeof (float), "cdf_write_grd");
i2 = first_col + pad[0];
for (j = 0, j2 = first_row + pad[3]; j < height_out; j++, j2++) {
ij = j2 * width_in + i2;
start[0] = j * width_out;
if (complex) {
for (i = 0; i < width_out; i++) tmp[i] = grid[2*(ij+i)];
ncvarput (cdfid, z_id, start, edge, (void *)tmp);
}
else
ncvarput (cdfid, z_id, start, edge, (void *)&grid[ij]);
}
}
ncclose (cdfid);
if (complex || geo) free ((char *)tmp);
return (ncerr);
}