|
rschlitzer@awi-bremerhaven.de
Reiner Schlitzer
registered since: 24.04.2008
Posts: 185
|
Hi Benedict:
Below please find the C source code of the grd2nc converter. You need netcdf to compile and run the code. The path to the source netcdf file in main() needs to be adapted.
Reiner Schlitzer
_______________________________________________________________________________
#include <windows.h>
#include <stdio.h>
#include "string.h"
#include <netcdf.h>
/* GRD info */
typedef struct tagGRDINFO
{
char szTitle[256]; size_t side,xysize; int node_offset,dimension[4];
double scale_factor,add_offset,x_range[4],y_range[4],z_range[4],spacing[4];
} GRDINFO;
/*------------------------------------------------------------------------*/
void rmext(char* szPathName)
/*------------------------------------------------------------------------
in-place removal of extension (last .* sequence) from full path-name.
R. Schlitzer
------------------------------------------------------------------------*/
{
char *psz=strchr(szPathName,(int) '.');
if (psz)
{
int l=strlen(szPathName); psz=szPathName+l-1;
while (psz>szPathName && *psz!='.' && *psz!='\\') --psz;
if (*psz=='.') *psz='\0';
}
}
/*------------------------------------------------------------------------*/
int loadGrdData(short *pF,double *pXg,double *pYg,int nXg,int nYg,
int ix0,int iy0,char *szFN,GRDINFO *pgi)
/*------------------------------------------------------------------------
extract z-values from GRD file szFN and setup x/y grids. GRDINFO
*pgi must have been obtained by a previous call to
loadGrdInfo. extracts nYg lines (top/north iy0 to bottom/south)
starting at x-index ix0 (then nXg consecutive values). return value
1 indicates success.
R. Schlitzer
------------------------------------------------------------------------*/
{
int ix,iy,fileID,varID,n,ii,NX=pgi->dimension[0];
size_t start,count=nXg; ptrdiff_t stride=1;
double x0,y0,dx=pgi->spacing[0],dy=pgi->spacing[1];
/* set the x/y grid */
x0=pgi->x_range[0]+ix0*dx; y0=pgi->y_range[1]-iy0*dy;
for (ix=0; ix<nXg; ix++) pXg[ix]=x0+ix*dx;
for (iy=0; iy<nYg; iy++) pYg[iy]=y0-iy*dy;
if (nc_open(szFN,NC_NOWRITE,&fileID)!=NC_NOERR) return 0;
if (nc_inq_varid(fileID,"z",&varID)!=NC_NOERR)
{ nc_close(fileID); return 0; }
/* load GRD data */
for (iy=0; iy<nYg; iy++)
{
ii=iy*nXg; start=(iy0+iy)*NX+ix0; count=n=min(nXg,NX-ix0);
nc_get_vars_short(fileID,varID,&start,&count,&stride,&pF[ii]);
/* fold around right boundary, if necessary */
if (n<nXg)
{
ii+=n; start=(iy0+iy)*NX; count=nXg-n;
nc_get_vars_short(fileID,varID,&start,&count,&stride,&pF[ii]);
}
}
nc_close(fileID); return 1;
}
/*------------------------------------------------------------------------*/
int loadGrdInfo(char *szFN,GRDINFO *pgi)
/*------------------------------------------------------------------------
R. Schlitzer
------------------------------------------------------------------------*/
{
int fileID,varID;
if (nc_open(szFN,NC_NOWRITE,&fileID)!=NC_NOERR) return 0;
if (nc_inq_dimid(fileID,"side",&varID)!=NC_NOERR)
{ nc_close(fileID); return 0; }
nc_inq_dimlen(fileID,varID,&pgi->side);
if (nc_inq_dimid(fileID,"xysize",&varID)!=NC_NOERR)
{ nc_close(fileID); return 0; }
nc_inq_dimlen(fileID,varID,&pgi->xysize);
if (nc_inq_varid(fileID,"dimension",&varID)!=NC_NOERR)
{ nc_close(fileID); return 0; }
nc_get_var_int(fileID,varID,pgi->dimension);
if (nc_inq_varid(fileID,"x_range",&varID)!=NC_NOERR)
{ nc_close(fileID); return 0; }
nc_get_var_double(fileID,varID,pgi->x_range);
if (nc_inq_varid(fileID,"y_range",&varID)!=NC_NOERR)
{ nc_close(fileID); return 0; }
nc_get_var_double(fileID,varID,pgi->y_range);
if (nc_inq_varid(fileID,"z_range",&varID)!=NC_NOERR)
{ nc_close(fileID); return 0; }
nc_get_var_double(fileID,varID,pgi->z_range);
if (nc_inq_varid(fileID,"spacing",&varID)!=NC_NOERR)
{ nc_close(fileID); return 0; }
nc_get_var_double(fileID,varID,pgi->spacing);
if (nc_inq_varid(fileID,"z",&varID)!=NC_NOERR)
{ nc_close(fileID); return 0; }
nc_get_att_int(fileID,varID,"node_offset",&pgi->node_offset);
nc_get_att_double(fileID,varID,"add_offset",&pgi->add_offset);
nc_get_att_double(fileID,varID,"scale_factor",&pgi->scale_factor);
ZeroMemory(pgi->szTitle,sizeof(pgi->szTitle));
nc_get_att_text(fileID,NC_GLOBAL,"title",pgi->szTitle);
nc_close(fileID); return 1;
}
/*------------------------------------------------------------------------*/
void grd2nc(char *szIFN)
/*------------------------------------------------------------------------
convert a .grd file into a COARDS compliant .nc file.
R. Schlitzer
------------------------------------------------------------------------*/
{
int i,nX,nY,ier=0,ncID,dimID[2],varID[3]; short *z;
double *X,*Y; char szOFN[256],szB[256]; GRDINFO gi;
/* load data from grd file */
if ((ier=loadGrdInfo(szIFN,&gi)))
{
/* allocate memory */
nX=gi.dimension[0]; nY=gi.dimension[1];
X=(double *) malloc(nX*sizeof(double));
Y=(double *) malloc(nY*sizeof(double));
z=(short *) malloc(nX*nY*sizeof(short));
if (!X || !Y || !z) return;
/* load data from grd file */
ier=loadGrdData(z,X,Y,nX,nY,0,0,szIFN,&gi);
/* create nc file */
strcpy(szOFN,szIFN); rmext(szOFN); strcat(szOFN,"_cf.nc");
if (nc_create(szOFN,0,&ncID)!=NC_NOERR) return;
/* define dimensions and variables */
if (nc_def_dim(ncID,"lon",(size_t) nX,&dimID[1])!=NC_NOERR) return;
if (nc_def_dim(ncID,"lat",(size_t) nY,&dimID[0])!=NC_NOERR) return;
if (nc_def_var(ncID,"lon",NC_DOUBLE,
1,&dimID[1],&varID[1])!=NC_NOERR) return;
if (nc_put_att_text(ncID,varID[1],
"long_name",9,"Longitude")!=NC_NOERR) return;
if (nc_put_att_text(ncID,varID[1],
"units",12,"degrees_east")!=NC_NOERR) return;
sprintf(szB,"%g - %g",X[0],X[nX-1]); i=strlen(szB);
if (nc_put_att_text(ncID,varID[1],"range",i,szB)!=NC_NOERR) return;
if (nc_def_var(ncID,"lat",NC_DOUBLE,
1,&dimID[0],&varID[0])!=NC_NOERR) return;
if (nc_put_att_text(ncID,varID[0],
"long_name",8,"Latitude")!=NC_NOERR) return;
if (nc_put_att_text(ncID,varID[0],
"units",13,"degrees_north")!=NC_NOERR) return;
sprintf(szB,"%g - %g",Y[0],Y[nY-1]); i=strlen(szB);
if (nc_put_att_text(ncID,varID[0],"range",i,szB)!=NC_NOERR) return;
if (nc_def_var(ncID,"Height",NC_SHORT,
2,dimID,&varID[2])!=NC_NOERR) return;
if (nc_put_att_text(ncID,varID[2],
"long_name",9,"Elevation")!=NC_NOERR) return;
if (nc_put_att_text(ncID,varID[2],
"units",1,"m")!=NC_NOERR) return;
if (nc_put_att_text(ncID,NC_GLOBAL,"title",26,
"GEBCO_08 - 0.5 minute grid")!=NC_NOERR) return;
if (nc_put_att_text(ncID,NC_GLOBAL,"references",46,
"GEBCO_08 Grid, version 20100927, www.gebco.net")!=NC_NOERR) return;
if (nc_put_att_text(ncID,NC_GLOBAL,"history",70,
"converted with grd2nc (R. Schlitzer)")!=NC_NOERR) return;
if (nc_enddef(ncID)!=NC_NOERR) return;
/* write variable data to nc file */
if (nc_put_var_double(ncID,varID[0],Y)!=NC_NOERR) return;
if (nc_put_var_double(ncID,varID[1],X)!=NC_NOERR) return;
if (nc_put_var_short(ncID,varID[2],z)!=NC_NOERR) return;
/* close nc file */
nc_close(ncID);
}
else
{ sprintf(szB,"%s not a valid .grd file!\n",szIFN); puts(szB); }
}
/*------------------------------------------------------------------------*/
main(int argc,char *argv[])
/*------------------------------------------------------------------------
convert a .grd file into a COARDS compliant .nc file.
R. Schlitzer
------------------------------------------------------------------------*/
{
char szGRD[]="c:\\rschlitz\\data\\odv\\Bathymetry\\GEBCO_08\\20100927\\gebco_08.nc";
//puts("grd2nc\n\nEnter grd-file name: "); gets(szGRD);
grd2nc(szGRD);
return 0;
}
|