home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Science / Science.zip / gmt_os2.zip / src / gmt_cdf.c < prev    next >
C/C++ Source or Header  |  1995-02-23  |  17KB  |  513 lines

  1. /*--------------------------------------------------------------------
  2.  *    The GMT-system:    @(#)gmt_cdf.c    2.19  2/23/95
  3.  *
  4.  *    Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
  5.  *    See README file for copying and redistribution conditions.
  6.  *--------------------------------------------------------------------*/
  7. /*
  8.  *
  9.  *    G M T _ C D F . C   R O U T I N E S
  10.  *
  11.  * Takes care of all grd input/output built on NCAR's netCDF routines (which is
  12.  * an XDR implementation)
  13.  * Most functions return the ncerr error value which will be non-zero if
  14.  * an error occured.
  15.  *
  16.  * Author:    Paul Wessel
  17.  * Date:    9-SEP-1992
  18.  * Modified:    27-JUN-1995
  19.  * Version:    3.0
  20.  *
  21.  * Functions include:
  22.  *
  23.  *    cdf_read_grd_info :    Read header from file
  24.  *    cdf_read_grd :        Read header and data set from file
  25.  *    cdf_write_grd_info :    Update header in existing file
  26.  *    cdf_write_grd :        Write header and data set to new file
  27.  *
  28.  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  29.  
  30. #include "gmt.h"
  31.  
  32. int cdf_read_grd_info (file, header)
  33. char *file;
  34. struct GRD_HEADER *header; {
  35.  
  36.     nclong  cdfid, nm[2], start[2], edge[2];
  37.     double dummy[2];
  38.     char text[480];
  39.     
  40.     /* variable ids */
  41.     nclong  x_range_id, y_range_id, z_range_id, inc_id, nm_id, z_id;
  42.  
  43.     if (!strcmp (file,"=")) {    /* Check if piping is attempted */
  44.         fprintf (stderr, "%s: GMT Fatal Error: netcdf-based i/o does not support piping - exiting\n", gmt_program);
  45.         exit (-1);
  46.     }
  47.     
  48.     /* Open file and get info */
  49.     
  50.     if (ncopts) ncopts = 0;
  51.     
  52.     if ((cdfid = ncopen (file, NC_NOWRITE)) == -1) return (-1);
  53.  
  54.     /* Get variable ids */
  55.  
  56.     x_range_id    = ncvarid (cdfid, "x_range");
  57.     y_range_id    = ncvarid (cdfid, "y_range");
  58.     z_range_id    = ncvarid (cdfid, "z_range");
  59.     inc_id        = ncvarid (cdfid, "spacing");
  60.     nm_id        = ncvarid (cdfid, "dimension");
  61.     z_id        = ncvarid (cdfid, "z");
  62.  
  63.     /* Get attributes */
  64.     
  65.     ncattget (cdfid, x_range_id, "units", (void *)header->x_units);
  66.     ncattget (cdfid, y_range_id, "units", (void *)header->y_units);
  67.     ncattget (cdfid, z_range_id, "units", (void *)header->z_units);
  68.     ncattget (cdfid, z_id, "long_name", (void *)header->title);
  69.     ncattget (cdfid, z_id, "scale_factor", (void *) &header->z_scale_factor);
  70.     ncattget (cdfid, z_id, "add_offset", (void *) &header->z_add_offset);
  71.     ncattget (cdfid, z_id, "node_offset", (void *) &header->node_offset);
  72.     ncattget (cdfid, NC_GLOBAL, "title", (void *)header->title);
  73.     ncattget (cdfid, NC_GLOBAL, "source", (void *)text);
  74.     strncpy (header->command, text, 320);
  75.     strncpy (header->remark, &text[320], 160);
  76.     
  77.     /* Get variables */
  78.     
  79.     start[0] = 0;
  80.     edge[0] = 2;
  81.     
  82.     ncvarget(cdfid, x_range_id, start, edge, (void *)dummy);
  83.     header->x_min = dummy[0];
  84.     header->x_max = dummy[1];
  85.     ncvarget(cdfid, y_range_id, start, edge, (void *)dummy);
  86.     header->y_min = dummy[0];
  87.     header->y_max = dummy[1];
  88.     ncvarget(cdfid, inc_id, start, edge, (void *)dummy);
  89.     header->x_inc = dummy[0];
  90.     header->y_inc = dummy[1];
  91.     ncvarget(cdfid, nm_id, start, edge, (void *)nm);
  92.     header->nx = nm[0];
  93.     header->ny = nm[1];
  94.     ncvarget(cdfid, z_range_id, start, edge, (void *)dummy);
  95.     header->z_min = dummy[0];
  96.     header->z_max = dummy[1];
  97.  
  98.     ncclose (cdfid);
  99.     
  100.     return (ncerr);
  101. }
  102.  
  103. int cdf_write_grd_info (file, header)
  104. char *file;
  105. struct GRD_HEADER *header; {
  106.  
  107.     nclong  cdfid, start[2], edge[2], nm[2];
  108.     double dummy[2];
  109.     char text[480];
  110.     
  111.     /* variable ids */
  112.     nclong  x_range_id, y_range_id, z_range_id, inc_id, nm_id, z_id;
  113.  
  114.     if (!strcmp (file,"=")) {    /* Check if piping is attempted */
  115.         fprintf (stderr, "%s: GMT Fatal Error: netcdf-based i/o does not support piping - exiting\n", gmt_program);
  116.         exit (-1);
  117.     }
  118.  
  119.     /* Open file and get info */
  120.     
  121.     if (ncopts) ncopts = 0;
  122.     if ((cdfid = ncopen (file, NC_WRITE)) == -1) return (-1);
  123.  
  124.     /* Get variable ids */
  125.  
  126.     x_range_id    = ncvarid (cdfid, "x_range");
  127.     y_range_id    = ncvarid (cdfid, "y_range");
  128.     z_range_id    = ncvarid (cdfid, "z_range");
  129.     inc_id        = ncvarid (cdfid, "spacing");
  130.     nm_id        = ncvarid (cdfid, "dimension");
  131.     z_id        = ncvarid (cdfid, "z");
  132.  
  133.     /* rewrite attributes */
  134.     
  135.     memset (text, 0, 480);
  136.     
  137.     strcpy (text, header->command);
  138.     strcpy (&text[320], header->remark);
  139.     ncattput (cdfid, x_range_id, "units", NC_CHAR, 80, (void *)header->x_units);
  140.     ncattput (cdfid, y_range_id, "units", NC_CHAR, 80, (void *)header->y_units);
  141.     ncattput (cdfid, z_range_id, "units", NC_CHAR, 80, (void *)header->z_units);
  142.     ncattput (cdfid, z_id, "long_name", NC_CHAR, 80, (void *)header->title);
  143.     ncattput (cdfid, z_id, "scale_factor", NC_DOUBLE, 1,(void *) &header->z_scale_factor);
  144.     ncattput (cdfid, z_id, "add_offset", NC_DOUBLE, 1,(void *) &header->z_add_offset);
  145.     ncattput (cdfid, z_id, "node_offset", NC_LONG, 1,(void *) &header->node_offset);
  146.     ncattput (cdfid, NC_GLOBAL, "title", NC_CHAR, 80, (void *)header->title);
  147.     ncattput (cdfid, NC_GLOBAL, "source", NC_CHAR, 480, (void *)text);
  148.     
  149.     /* rewrite header information */
  150.     
  151.     start[0] = 0;
  152.     edge[0] = 2;
  153.     dummy[0] = header->x_min;
  154.     dummy[1] = header->x_max;
  155.     ncvarput(cdfid, x_range_id, start, edge, (void *)dummy);
  156.     dummy[0] = header->y_min;
  157.     dummy[1] = header->y_max;
  158.     ncvarput(cdfid, y_range_id, start, edge, (void *)dummy);
  159.     dummy[0] = header->x_inc;
  160.     dummy[1] = header->y_inc;
  161.     ncvarput(cdfid, inc_id, start, edge, (void *)dummy);
  162.     nm[0] = header->nx;
  163.     nm[1] = header->ny;
  164.     ncvarput(cdfid, nm_id, start, edge, (void *)nm);
  165.     dummy[0] = header->z_min;
  166.     dummy[1] = header->z_max;
  167.     ncvarput(cdfid, z_range_id, start, edge, (void *)dummy);
  168.  
  169.     ncclose (cdfid);
  170.     
  171.     return (ncerr);
  172. }
  173.  
  174. int cdf_read_grd (file, header, grid, w, e, s, n, pad, complex)
  175. char *file;
  176. struct GRD_HEADER *header;
  177. float *grid;
  178. double w, e, s, n;    /* Sub-region to extract.  Use entire file if 0,0,0,0 */
  179. int pad[];        /* padding on w, e, s, n of grid, respectively */
  180. BOOLEAN complex;    /* TRUE if array is to hold real and imaginary parts */
  181. {
  182.     /*
  183.      * Reads a subset of a grdfile and optionally pads the array with extra rows and columns
  184.      * header values for nx and ny are reset to reflect the dimensions of the logical array,
  185.      * not the physical size (i.e., the padding is not counted in nx and ny)
  186.      */
  187.      
  188.     nclong  cdfid, z_id, j2, one_or_zero, *k, start[2], edge[2];
  189.     nclong first_col, last_col, first_row, last_row;
  190.     nclong i, j, ij, width_in, width_out, height_in, i_0_out, inc = 1;
  191.     
  192.     BOOLEAN geo = FALSE;
  193.     
  194.     float *tmp;
  195.     
  196.     double off, half_or_zero, x, small;
  197.     
  198.     /* Open file and get info */
  199.     
  200.     if (!strcmp (file,"=")) {    /* Check if piping is attempted */
  201.         fprintf (stderr, "%s: GMT Fatal Error: netcdf-based i/o does not support piping - exiting\n", gmt_program);
  202.         exit (-1);
  203.     }
  204.     
  205.     if (ncopts) ncopts = 0;
  206.     if ((cdfid = ncopen (file, NC_NOWRITE)) == -1) return (-1);
  207.  
  208.     /* Get variable id */
  209.  
  210.     z_id = ncvarid (cdfid, "z");
  211.  
  212.     if (w == 0.0 && e == 0.0) {    /* Get entire file */
  213.         w = header->x_min;
  214.         e = header->x_max;
  215.         s = header->y_min;
  216.         n = header->y_max;
  217.     }
  218.  
  219.     /* Must deal with a subregion */
  220.  
  221.     if (w < header->x_min || e > header->x_max) geo = TRUE;    /* Dealing with periodic grid */
  222.     
  223.     one_or_zero = (header->node_offset) ? 0 : 1;
  224.     off = (header->node_offset) ? 0.0 : 0.5;
  225.     
  226.     /* Get dimension of subregion */
  227.     
  228.     width_in  = rint ((e - w) / header->x_inc) + one_or_zero;
  229.     height_in = rint ((n - s) / header->y_inc) + one_or_zero;
  230.     
  231.     /* Get first and last row and column numbers */
  232.     
  233.     small = 0.1 * header->x_inc;
  234.     first_col = floor ((w - header->x_min + small) / header->x_inc);
  235.     last_col  = ceil ((e - header->x_min - small) / header->x_inc) - 1 + one_or_zero;
  236.     small = 0.1 * header->y_inc;
  237.     first_row = floor ((header->y_max - n + small) / header->y_inc);
  238.     last_row  = ceil ((header->y_max - s - small) / header->y_inc) - 1 + one_or_zero;
  239.  
  240.     if ((last_col - first_col + 1) > width_in) last_col--;
  241.     if ((last_row - first_row + 1) > height_in) last_row--;
  242.     if ((last_col - first_col + 1) > width_in) first_col++;
  243.     if ((last_row - first_row + 1) > height_in) first_row++;
  244.     
  245.     width_out = width_in;        /* Width of output array */
  246.     if (pad[0] > 0) width_out += pad[0];
  247.     if (pad[1] > 0) width_out += pad[1];
  248.     
  249.     i_0_out = pad[0];        /* Edge offset in output */
  250.     if (complex) {    /* Need twice as much space and load every 2nd cell */
  251.         width_out *= 2;
  252.         i_0_out *= 2;
  253.         inc = 2;
  254.     }
  255.     
  256.     if (geo) {    /* Must rollover in longitudes */
  257.     
  258.         tmp = (float *) memory (CNULL, (int)header->nx, sizeof (float), "cdf_read_grd");
  259.         k = (nclong *) memory (CNULL, (int)width_in, sizeof (nclong), "cdf_read_grd");
  260.         
  261.         half_or_zero = (header->node_offset) ? 0.5 : 0.0;
  262.         edge[0] = header->nx;
  263.         small = 0.1 * header->x_inc;    /* Anything smaller than 0.5 dx will do */
  264.         for (i = 0; i < width_in; i++) {
  265.             x = w + (i + half_or_zero) * header->x_inc;
  266.             if ((header->x_min - x) > small)
  267.                 x += 360.0;
  268.             else if ((x - header->x_max) > small)
  269.                 x -= 360.0;
  270.             k[i] = (nclong) floor (((x - header->x_min) / header->x_inc) + off);
  271.         }
  272.         for (j = first_row, j2 = 0; j <= last_row; j++, j2++) {
  273.             start[0] = j * header->nx;
  274.             ncvarget (cdfid, z_id, start, edge, (void *)tmp);    /* Get one row */
  275.             ij = (j2 + pad[3]) * width_out + i_0_out;
  276.             for (i = 0; i < width_in; i++) grid[ij+i*inc] = tmp[k[i]];
  277.         }
  278.         free ((char *)k);
  279.     }
  280.     else {    /* A bit easier here */
  281.         if (complex) tmp = (float *) memory (CNULL, (int)width_in, sizeof (float), "cdf_read_grd");
  282.         edge[0] = width_in;
  283.         for (j = first_row, j2 = 0; j <= last_row; j++, j2++) {
  284.             start[0] = j * header->nx + first_col;
  285.             ij = (j2 + pad[3]) * width_out + i_0_out;
  286.             if (complex) {
  287.                 ncvarget (cdfid, z_id, start, edge, (void *)tmp);
  288.                 for (i = 0; i < width_in; i++) grid[ij+2*i] = tmp[i];
  289.             }
  290.             else
  291.                 ncvarget (cdfid, z_id, start, edge, (void *)&grid[ij]);
  292.         }
  293.     }
  294.     
  295.     header->nx = width_in;
  296.     header->ny = height_in;
  297.     header->x_min = w;
  298.     header->x_max = e;
  299.     header->y_min = s;
  300.     header->y_max = n;
  301.  
  302.     header->z_min = MAXDOUBLE;    header->z_max = -MAXDOUBLE;
  303.     for (j = 0; j < header->ny; j++) {
  304.         for (i = 0; i < header->nx; i++) {
  305.             j2 = (complex) ? 2 * (i + pad[0]) : i + pad[0];
  306.             ij = (j + pad[3]) * width_out + j2;
  307.             if (bad_float ((double)grid[ij])) continue;
  308.             header->z_min = MIN (header->z_min, grid[ij]);
  309.             header->z_max = MAX (header->z_max, grid[ij]);
  310.         }
  311.     }
  312.     ncclose (cdfid);
  313.     
  314.     if (complex || geo) free ((char *)tmp);
  315.     return (ncerr);
  316. }
  317.  
  318. int cdf_write_grd (file, header, grid, w, e, s, n, pad, complex)
  319. char *file;
  320. struct GRD_HEADER *header;
  321. float *grid;
  322. double w, e, s, n;    /* Sub-region to write out */
  323. int pad[];        /* padding on w, e, s, n of grid, respectively */
  324. BOOLEAN complex;    /* TRUE if array is to hold real and imaginary parts */
  325. {
  326.     nclong start[2], edge[2];
  327.     nclong i, i2, cdfid, nm[2], inc = 1, *k;
  328.     nclong j, ij, j2, width_in, width_out, height_out, one_or_zero;
  329.     nclong first_col, last_col, first_row, last_row;
  330.     
  331.     BOOLEAN geo = FALSE;
  332.     double dummy[2], off, half_or_zero, small, x;
  333.     
  334.     char text[480];
  335.     
  336.     float *tmp;
  337.     
  338.     /* dimension ids */
  339.     nclong  side_dim, xysize_dim;
  340.  
  341.     /* variable ids */
  342.     nclong  x_range_id, y_range_id, z_range_id, inc_id, nm_id, z_id;
  343.  
  344.     /* variable shapes */
  345.     int dims[1];
  346.  
  347.     if (!strcmp (file,"=")) {    /* Check if piping is attempted */
  348.         fprintf (stderr, "%s: GMT Fatal Error: netcdf-based i/o does not support piping - exiting\n", gmt_program);
  349.         exit (-1);
  350.     }
  351.     
  352.     if (w == 0.0 && e == 0.0) {    /* Write entire grid */
  353.         w = header->x_min;
  354.         e = header->x_max;
  355.         s = header->y_min;
  356.         n = header->y_max;
  357.         pad[0] = pad[1] = pad[2] = pad[3] = 0;
  358.     }
  359.     
  360.     if (w < header->x_min || e > header->x_max) geo = TRUE;    /* Dealing with periodic grid */
  361.     
  362.     one_or_zero = (header->node_offset) ? 0 : 1;
  363.     off = (header->node_offset) ? 0.0 : 0.5;
  364.     
  365.     /* Create file and enter define mode */
  366.     
  367.     if (ncopts) ncopts = 0;
  368.     if ((cdfid = nccreate (file, NC_CLOBBER)) == -1) return (-1);
  369.  
  370.     /* Get dimension of subregion to write */
  371.     
  372.     width_out  = rint ((e - w) / header->x_inc) + one_or_zero;
  373.     height_out = rint ((n - s) / header->y_inc) + one_or_zero;
  374.     
  375.     /* Get first and last row and column numbers */
  376.     
  377.     small = 0.1 * header->x_inc;
  378.     first_col = floor ((w - header->x_min + small) / header->x_inc);
  379.     last_col  = ceil ((e - header->x_min - small) / header->x_inc) -1 + one_or_zero;
  380.     small = 0.1 * header->y_inc;
  381.     first_row = floor ((header->y_max - n + small) / header->y_inc);
  382.     last_row  = ceil ((header->y_max - s - small) / header->y_inc) -1 + one_or_zero;
  383.     
  384.     if ((last_col - first_col + 1) > width_out) last_col--;
  385.     if ((last_row - first_row + 1) > height_out) last_row--;
  386.     if ((last_col - first_col + 1) > width_out) first_col++;
  387.     if ((last_row - first_row + 1) > height_out) first_row++;
  388.  
  389.     width_in = width_out;        /* Physical width of input array */
  390.     if (pad[0] > 0) width_in += pad[0];
  391.     if (pad[1] > 0) width_in += pad[1];
  392.     
  393.     edge[0] = width_out;
  394.     if (complex) inc = 2;
  395.  
  396.     header->x_min = w;
  397.     header->x_max = e;
  398.     header->y_min = s;
  399.     header->y_max = n;
  400.     
  401.     /* define dimensions */
  402.     
  403.     side_dim    = ncdimdef(cdfid, "side", 2);
  404.     xysize_dim    = ncdimdef(cdfid, "xysize", (int) (width_out * height_out));
  405.  
  406.     /* define variables */
  407.  
  408.     dims[0]        = side_dim;
  409.     x_range_id    = ncvardef (cdfid, "x_range", NC_DOUBLE, 1, dims);
  410.     y_range_id    = ncvardef (cdfid, "y_range", NC_DOUBLE, 1, dims);
  411.     z_range_id    = ncvardef (cdfid, "z_range", NC_DOUBLE, 1, dims);
  412.     inc_id        = ncvardef (cdfid, "spacing", NC_DOUBLE, 1, dims);
  413.        nm_id        = ncvardef (cdfid, "dimension", NC_LONG, 1, dims);
  414.  
  415.     dims[0]        = xysize_dim;
  416.     z_id        = ncvardef (cdfid, "z", NC_FLOAT, 1, dims);
  417.  
  418.     /* assign attributes */
  419.     
  420.     strcpy (text, header->command);
  421.     strcpy (&text[320], header->remark);
  422.     ncattput (cdfid, x_range_id, "units", NC_CHAR, 80, (void *)header->x_units);
  423.     ncattput (cdfid, y_range_id, "units", NC_CHAR, 80, (void *)header->y_units);
  424.     ncattput (cdfid, z_range_id, "units", NC_CHAR, 80, (void *)header->z_units);
  425.     ncattput (cdfid, z_id, "long_name", NC_CHAR, 80, (void *)header->title);
  426.     ncattput (cdfid, z_id, "scale_factor", NC_DOUBLE, 1,(void *) &header->z_scale_factor);
  427.     ncattput (cdfid, z_id, "add_offset", NC_DOUBLE, 1,(void *) &header->z_add_offset);
  428.     ncattput (cdfid, z_id, "node_offset", NC_LONG, 1,(void *) &header->node_offset);
  429.     ncattput (cdfid, NC_GLOBAL, "title", NC_CHAR, 80, (void *)header->title);
  430.     ncattput (cdfid, NC_GLOBAL, "source", NC_CHAR, 480, (void *)text);
  431.  
  432.     /* leave define mode */
  433.     
  434.     ncendef (cdfid);
  435.  
  436.     /* Find xmin/zmax */
  437.     
  438.     header->z_min = MAXDOUBLE;    header->z_max = -MAXDOUBLE;
  439.     for (j = first_row, j2 = pad[3]; j <= last_row; j++, j2++) {
  440.         for (i = first_col, i2 = pad[0]; i <= last_col; i++, i2++) {
  441.             ij = (j2 * width_in + i2) * inc;
  442.             if (bad_float ((double)grid[ij])) continue;
  443.             header->z_min = MIN (header->z_min, grid[ij]);
  444.             header->z_max = MAX (header->z_max, grid[ij]);
  445.         }
  446.     }
  447.     
  448.     /* store header information and array */
  449.     
  450.     start[0] = 0;
  451.     edge[0] = 2;
  452.     dummy[0] = header->x_min;
  453.     dummy[1] = header->x_max;
  454.     ncvarput(cdfid, x_range_id, start, edge, (void *)dummy);
  455.     dummy[0] = header->y_min;
  456.     dummy[1] = header->y_max;
  457.     ncvarput(cdfid, y_range_id, start, edge, (void *)dummy);
  458.     dummy[0] = header->x_inc;
  459.     dummy[1] = header->y_inc;
  460.     ncvarput(cdfid, inc_id, start, edge, (void *)dummy);
  461.     nm[0] = width_out;
  462.     nm[1] = height_out;
  463.     ncvarput(cdfid, nm_id, start, edge, (void *)nm);
  464.     dummy[0] = header->z_min;
  465.     dummy[1] = header->z_max;
  466.     ncvarput(cdfid, z_range_id, start, edge, (void *)dummy);
  467.     edge[0] = width_out;
  468.  
  469.     if (geo) {
  470.         tmp = (float *) memory (CNULL, (int)width_in, sizeof (float), "cdf_write_grd");
  471.         k = (nclong *) memory (CNULL, (int)width_out, sizeof (nclong), "cdf_write_grd");
  472.         
  473.         half_or_zero = (header->node_offset) ? 0.5 : 0.0;
  474.         edge[0] = header->nx;
  475.         small = 0.1 * header->x_inc;    /* Anything smaller than 0.5 dx will do */
  476.         for (i = 0; i < width_out; i++) {
  477.             x = w + (i + half_or_zero) * header->x_inc;
  478.             if ((header->x_min - x) > small)
  479.                 x += 360.0;
  480.             else if ((x - header->x_max) > small)
  481.                 x -= 360.0;
  482.             k[i] = (nclong) floor (((x - header->x_min) / header->x_inc) + off);
  483.         }
  484.         i2 = first_col + pad[0];
  485.         for (j = 0, j2 = first_row + pad[3]; j < height_out; j++, j2++) {
  486.             ij = j2 * width_in + i2;
  487.             start[0] = j * width_out;
  488.             for (i = 0; i < width_out; i++) tmp[i] = grid[inc * (ij+k[i])];
  489.             ncvarput (cdfid, z_id, start, edge, (void *)tmp);
  490.         }
  491.         free ((char *)k);
  492.     }
  493.     else {
  494.         if (complex) tmp = (float *) memory (CNULL, (int)width_in, sizeof (float), "cdf_write_grd");
  495.         i2 = first_col + pad[0];
  496.         for (j = 0, j2 = first_row + pad[3]; j < height_out; j++, j2++) {
  497.             ij = j2 * width_in + i2;
  498.             start[0] = j * width_out;
  499.             if (complex) {
  500.                 for (i = 0; i < width_out; i++) tmp[i] = grid[2*(ij+i)];
  501.                 ncvarput (cdfid, z_id, start, edge, (void *)tmp);
  502.             }
  503.             else
  504.                 ncvarput (cdfid, z_id, start, edge, (void *)&grid[ij]);
  505.         }
  506.     }
  507.     ncclose (cdfid);
  508.     
  509.     if (complex || geo) free ((char *)tmp);
  510.     
  511.     return (ncerr);
  512. }
  513.