mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-01-30 16:10:44 +08:00
merge latest trunk changes into my branch
This commit is contained in:
commit
23226e5101
@ -29,6 +29,11 @@ int total_err = 0, err = 0;
|
||||
char *format_name[] = {"", "classic", "64-bit offset", "netCDF-4",
|
||||
"netCDF-4 classic model"};
|
||||
|
||||
#define BAIL(e) do { \
|
||||
printf ("Bailing out in file %s, line %d, error:%s.\n", __FILE__, __LINE__, nc_strerror(e)); \
|
||||
return -1; \
|
||||
} while (0)
|
||||
|
||||
/* This macro prints an error message with line number and name of
|
||||
* test program. */
|
||||
#define ERR do { \
|
||||
|
@ -63,6 +63,8 @@ extern "C" {
|
||||
#define NC_UINT64 11 /* unsigned 8-byte int */
|
||||
#define NC_STRING 12 /* string */
|
||||
|
||||
#define NC_MAX_ATOMIC_TYPE NC_STRING
|
||||
|
||||
/* The following are use internally in support of user-defines
|
||||
* types. They are also the class returned by nc_inq_user_type. */
|
||||
#define NC_VLEN 13 /* used internally for vlen types */
|
||||
|
@ -13,22 +13,28 @@
|
||||
/* Compare two netcdf types for equality. Must have the ncids as well,
|
||||
to find user-defined types. */
|
||||
static int
|
||||
NC_compare_nc_types(int ncid1, int typeid1,
|
||||
int ncid2, int typeid2, int *equalp)
|
||||
NC_compare_nc_types(int ncid1, int typeid1, int ncid2, int typeid2,
|
||||
int *equalp)
|
||||
{
|
||||
int ret = NC_NOERR;
|
||||
if(equalp == NULL) return NC_NOERR;
|
||||
|
||||
/* If you don't care about the answer, neither do I! */
|
||||
if(equalp == NULL)
|
||||
return NC_NOERR;
|
||||
|
||||
/* Assume the types are not equal. If we find any inequality, then
|
||||
exit with NC_NOERR and we're done. */
|
||||
*equalp = 0;
|
||||
|
||||
/* Atomic types are so easy! */
|
||||
if (typeid1 <= ATOMICTYPEMAX) {
|
||||
if (typeid2 != typeid1) return NC_NOERR;
|
||||
if (typeid1 <= NC_MAX_ATOMIC_TYPE)
|
||||
{
|
||||
if (typeid2 != typeid1)
|
||||
return NC_NOERR;
|
||||
*equalp = 1;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
int i, ret, equal1;
|
||||
char name1[NC_MAX_NAME];
|
||||
char name2[NC_MAX_NAME];
|
||||
@ -44,69 +50,81 @@ NC_compare_nc_types(int ncid1, int typeid1,
|
||||
int dimsizes1[NC_MAX_VAR_DIMS];
|
||||
int dimsizes2[NC_MAX_VAR_DIMS];
|
||||
|
||||
ret = nc_inq_user_type(ncid1,typeid1,name1,&size1,&base1,&nelems1,&class1);
|
||||
if(ret) return ret;
|
||||
ret = nc_inq_user_type(ncid2,typeid2,name2,&size2,&base2,&nelems2,&class2);
|
||||
if(ret) return ret;
|
||||
/* Find out about the two types. */
|
||||
if ((ret = nc_inq_user_type(ncid1, typeid1, name1, &size1,
|
||||
&base1, &nelems1, &class1)))
|
||||
return ret;
|
||||
if ((ret = nc_inq_user_type(ncid2, typeid2, name2, &size2,
|
||||
&base2, &nelems2, &class2)))
|
||||
return ret;
|
||||
|
||||
/* Check the obvious. */
|
||||
if(size1 != size2 || class1 != class2 || strcmp(name1,name2))
|
||||
return NC_NOERR;
|
||||
|
||||
/* Check user-defined types in detail. */
|
||||
switch(class1) {
|
||||
switch(class1)
|
||||
{
|
||||
case NC_VLEN:
|
||||
if(base1 <= NC_STRING) {
|
||||
if(base1 != base2) return NC_NOERR;
|
||||
} else {
|
||||
/* User defined type in VLEN! */
|
||||
if((ret = NC_compare_nc_types(ncid1,base1,ncid2,base1,&equal1)))
|
||||
return ret;
|
||||
if(!equal1) return NC_NOERR;
|
||||
}
|
||||
if((ret = NC_compare_nc_types(ncid1, base1, ncid2,
|
||||
base1, &equal1)))
|
||||
return ret;
|
||||
if(!equal1)
|
||||
return NC_NOERR;
|
||||
break;
|
||||
case NC_OPAQUE:
|
||||
/* Already checked size above. */
|
||||
break;
|
||||
case NC_ENUM:
|
||||
if(base1 != base2 || nelems1 != nelems2) return NC_NOERR;
|
||||
value1 = malloc(size1);
|
||||
value2 = malloc(size2);
|
||||
for(i=0;i<nelems1;i++) {
|
||||
ret = nc_inq_enum_member(ncid1,typeid1,i,name1,value1);
|
||||
if(ret) return ret;
|
||||
ret = nc_inq_enum_member(ncid2,typeid2,i,name2,value2);
|
||||
if(ret) goto enumdone;
|
||||
if(strcmp(name1,name2) != 0
|
||||
|| memcmp(value1,value2,size1) != 0)
|
||||
return NC_NOERR;
|
||||
|
||||
if (!(value1 = malloc(size1)))
|
||||
return NC_ENOMEM;
|
||||
if (!(value2 = malloc(size2)))
|
||||
return NC_ENOMEM;
|
||||
|
||||
for(i = 0; i < nelems1; i++)
|
||||
{
|
||||
if ((ret = nc_inq_enum_member(ncid1, typeid1, i, name1,
|
||||
value1)) ||
|
||||
(ret = nc_inq_enum_member(ncid2, typeid2, i, name2,
|
||||
value2)) ||
|
||||
strcmp(name1, name2) || memcmp(value1, value2, size1))
|
||||
{
|
||||
free(value1);
|
||||
free(value2);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
enumdone:
|
||||
free(value1); free(value2);
|
||||
free(value1);
|
||||
free(value2);
|
||||
break;
|
||||
case NC_COMPOUND:
|
||||
if(nelems1 != nelems2) return NC_NOERR;
|
||||
if(nelems1 != nelems2)
|
||||
return NC_NOERR;
|
||||
|
||||
/* Compare each field. Each must be equal! */
|
||||
for(i=0;i<nelems1;i++) {
|
||||
for(i = 0; i < nelems1; i++)
|
||||
{
|
||||
int j;
|
||||
ret = nc_inq_compound_field(ncid1,typeid1,i,name1,&offset1,&ftype1,&ndims1,dimsizes1);
|
||||
if(ret) return ret;
|
||||
ret = nc_inq_compound_field(ncid2,typeid2,i,name2,&offset2,&ftype2,&ndims2,dimsizes2);
|
||||
if(ret) return ret;
|
||||
if(ndims1 != ndims2) return NC_NOERR;
|
||||
for(j=0;j<ndims1;j++) {
|
||||
if(dimsizes1[j] != dimsizes2[j]) return NC_NOERR;
|
||||
}
|
||||
/* Handle atomic types. */
|
||||
if(ftype1 <= NC_STRING) {
|
||||
if(ftype1 != ftype2) return NC_NOERR;
|
||||
} else { /* Dang! *More* user-defined types!
|
||||
Look up the field types in each file. */
|
||||
/* Compare user-defined field types. */
|
||||
if((ret = NC_compare_nc_types(ncid1,ftype1,ncid2,ftype2,&equal1)))
|
||||
return ret;
|
||||
if(!equal1) return NC_NOERR;
|
||||
}
|
||||
if ((ret = nc_inq_compound_field(ncid1, typeid1, i, name1, &offset1,
|
||||
&ftype1, &ndims1, dimsizes1)))
|
||||
return ret;
|
||||
if ((ret = nc_inq_compound_field(ncid2, typeid2, i, name2, &offset2,
|
||||
&ftype2, &ndims2, dimsizes2)))
|
||||
return ret;
|
||||
if(ndims1 != ndims2)
|
||||
return NC_NOERR;
|
||||
for(j = 0; j < ndims1;j++)
|
||||
if(dimsizes1[j] != dimsizes2[j])
|
||||
return NC_NOERR;
|
||||
|
||||
/* Compare user-defined field types. */
|
||||
if((ret = NC_compare_nc_types(ncid1, ftype1, ncid2, ftype2,
|
||||
&equal1)))
|
||||
return ret;
|
||||
if(!equal1)
|
||||
return NC_NOERR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -158,15 +176,19 @@ NC_rec_find_nc_type(int ncid1, nc_type tid1, int ncid2, nc_type* tid2)
|
||||
return ret;
|
||||
if (nids)
|
||||
{
|
||||
if (!(ids = (int*)malloc(nids*sizeof(int))))
|
||||
if (!(ids = (int *)malloc(nids * sizeof(int))))
|
||||
return NC_ENOMEM;
|
||||
if ((ret = nc_inq_grps(ncid1,&nids,ids)))
|
||||
if ((ret = nc_inq_grps(ncid1, &nids, ids)))
|
||||
{
|
||||
free(ids);
|
||||
return ret;
|
||||
for(i = 0; i < nids; i++)
|
||||
}
|
||||
for (i = 0; i < nids; i++)
|
||||
{
|
||||
ret = NC_rec_find_nc_type(ncid1, tid1, ids[i], tid2);
|
||||
if(ret && ret != NC_EBADTYPE) break;
|
||||
if(tid2 && *tid2 != 0) /* found */
|
||||
if (ret && ret != NC_EBADTYPE)
|
||||
break;
|
||||
if (tid2 && *tid2 != 0) /* found */
|
||||
{
|
||||
free(ids);
|
||||
return NC_NOERR;
|
||||
@ -183,11 +205,16 @@ static int
|
||||
NC_find_equal_type(int ncid1, nc_type xtype1, int ncid2, nc_type *xtype2)
|
||||
{
|
||||
int ret = NC_NOERR;
|
||||
|
||||
/* Check input */
|
||||
if(xtype1 <= NC_NAT) return NC_EINVAL;
|
||||
if(xtype1 <= NC_NAT)
|
||||
return NC_EINVAL;
|
||||
|
||||
/* Handle atomic types. */
|
||||
if (xtype1 <= ATOMICTYPEMAX) {
|
||||
if(xtype2) *xtype2 = xtype1;
|
||||
if (xtype1 <= NC_MAX_ATOMIC_TYPE)
|
||||
{
|
||||
if(xtype2)
|
||||
*xtype2 = xtype1;
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
@ -438,28 +465,26 @@ nc_copy_att(int ncid_in, int varid_in, const char *name,
|
||||
size_t len;
|
||||
void *data=NULL;
|
||||
int res;
|
||||
|
||||
#ifdef USE_NETCDF4
|
||||
|
||||
LOG((2, "nc_copy_att: ncid_in 0x%x varid_in %d name %s",
|
||||
ncid_in, varid_in, name));
|
||||
#endif
|
||||
|
||||
|
||||
/* Find out about the attribute and allocate memory for the
|
||||
data. */
|
||||
if ((res = nc_inq_att(ncid_in, varid_in, name, &xtype, &len)))
|
||||
return res;
|
||||
|
||||
|
||||
/* Can't copy to same var in same file. */
|
||||
if (ncid_in == ncid_out && varid_in == varid_out)
|
||||
return NC_NOERR;
|
||||
|
||||
#ifndef USE_NETCDF4
|
||||
if (xtype <= NC_DOUBLE) {
|
||||
if (xtype < NC_STRING)
|
||||
{
|
||||
/* Handle atomic types. */
|
||||
if (len) {
|
||||
if (len)
|
||||
if (!(data = malloc(len * NC_atomictypelen(xtype))))
|
||||
return NC_ENOMEM;
|
||||
}
|
||||
|
||||
res = nc_get_att(ncid_in, varid_in, name, data);
|
||||
if (!res)
|
||||
res = nc_put_att(ncid_out, varid_out, name, xtype,
|
||||
@ -467,20 +492,9 @@ nc_copy_att(int ncid_in, int varid_in, const char *name,
|
||||
if (len)
|
||||
free(data);
|
||||
}
|
||||
#else /*!USE_NETCDF4*/
|
||||
if(xtype < NC_STRING) {
|
||||
/* Handle atomic types. */
|
||||
if (len)
|
||||
if (!(data = malloc(len * NC_atomictypelen(xtype))))
|
||||
return NC_ENOMEM;
|
||||
|
||||
res = nc_get_att(ncid_in, varid_in, name, data);
|
||||
if (!res)
|
||||
res = nc_put_att(ncid_out, varid_out, name, xtype,
|
||||
len, data);
|
||||
if (len)
|
||||
free(data);
|
||||
} else if (xtype == NC_STRING) {
|
||||
#ifdef USE_NETCDF4
|
||||
else if (xtype == NC_STRING)
|
||||
{
|
||||
/* Copy string attributes. */
|
||||
char **str_data;
|
||||
if (!(str_data = malloc(sizeof(char *) * len)))
|
||||
@ -491,7 +505,9 @@ nc_copy_att(int ncid_in, int varid_in, const char *name,
|
||||
(const char **)str_data);
|
||||
nc_free_string(len, str_data);
|
||||
free(str_data);
|
||||
} else/*x*/ {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy user-defined type attributes. */
|
||||
int class;
|
||||
size_t size;
|
||||
@ -503,33 +519,35 @@ nc_copy_att(int ncid_in, int varid_in, const char *name,
|
||||
which we had to "duplicate" here */
|
||||
if ((res = NC_find_equal_type(ncid_in, xtype, ncid_out, &xtype_out)))
|
||||
return res;
|
||||
if(xtype_out != 0) {
|
||||
if (xtype_out)
|
||||
{
|
||||
/* We found an equal type! */
|
||||
if((res = nc_inq_user_type(ncid_in, xtype, NULL, &size,
|
||||
if ((res = nc_inq_user_type(ncid_in, xtype, NULL, &size,
|
||||
NULL, NULL, &class)))
|
||||
return res;
|
||||
if(class == NC_VLEN) { /* VLENs are different... */
|
||||
if (class == NC_VLEN) /* VLENs are different... */
|
||||
{
|
||||
nc_vlen_t *vldata;
|
||||
int i;
|
||||
if(!(vldata = malloc(sizeof(nc_vlen_t) * len)))
|
||||
if (!(vldata = malloc(sizeof(nc_vlen_t) * len)))
|
||||
return NC_ENOMEM;
|
||||
if((res = nc_get_att(ncid_in, varid_in, name, vldata)))
|
||||
if ((res = nc_get_att(ncid_in, varid_in, name, vldata)))
|
||||
return res;
|
||||
if((res = nc_put_att(ncid_out, varid_out, name, xtype_out,
|
||||
if ((res = nc_put_att(ncid_out, varid_out, name, xtype_out,
|
||||
len, vldata)))
|
||||
return res;
|
||||
for(i=0;i<len;i++) {
|
||||
if((res = nc_free_vlen(&vldata[i]))) return res;
|
||||
}
|
||||
for (i = 0; i < len; i++)
|
||||
if((res = nc_free_vlen(&vldata[i])))
|
||||
return res;
|
||||
free(vldata);
|
||||
} else {/* not VLEN */
|
||||
if(!(data = malloc(size * len)))
|
||||
}
|
||||
else /* not VLEN */
|
||||
{
|
||||
if (!(data = malloc(size * len)))
|
||||
return NC_ENOMEM;
|
||||
if((res = nc_get_att(ncid_in, varid_in, name, data)))
|
||||
return res;
|
||||
if((res = nc_put_att(ncid_out, varid_out, name, xtype_out,
|
||||
len, data)))
|
||||
return res;
|
||||
res = nc_get_att(ncid_in, varid_in, name, data);
|
||||
if (!res)
|
||||
res = nc_put_att(ncid_out, varid_out, name, xtype_out, len, data);
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
@ -14,15 +14,13 @@ list='tst_h_dimscales tst_h_files '\
|
||||
'tst_h_grps tst_h_wrt_cmp tst_h_rd_cmp tst_h_vl tst_h_atts '\
|
||||
'tst_h_dimscales3 tst_h_files2 tst_h_compounds '\
|
||||
'tst_h_vars tst_h_opaques tst_h_compounds2 '\
|
||||
'tst_compounds '\
|
||||
'tst_h_vars2 tst_h_vars3 tst_h_strings tst_compounds '\
|
||||
'tst_files tst_utf8 tst_fillbug '\
|
||||
'tst_vars3 tst_xplatform tst_dims '\
|
||||
'tst_dims2 tst_dims3 tst_varms tst_unlim_vars '\
|
||||
'tst_endian_fill tst_compounds2'
|
||||
'tst_endian_fill tst_compounds2 tst_chunks tst_coords tst_vars'
|
||||
|
||||
# These don't work yet: tst_h_vars3
|
||||
# tst_h_strings tst_h_atts3 tst_h_vars2 tst_vars tst_fills tst_chunks
|
||||
# tst_coords tst_xplatform2
|
||||
# These don't work yet: tst_h_atts3 tst_fills tst_xplatform2
|
||||
|
||||
for tst in $list; do
|
||||
echo ""
|
||||
|
@ -61,17 +61,18 @@ main(int argc, char **argv)
|
||||
if (strcmp(data_in[i], "")) ERR;
|
||||
if (strcmp(data_in[DATA_START], data_out[0])) ERR;
|
||||
|
||||
/* Close everything up. */
|
||||
/* Close everything up. Don't forget to free the string! */
|
||||
if (nc_free_string(DATA_START + 1, data_in)) ERR;
|
||||
if (nc_close(ncid)) ERR;
|
||||
|
||||
/* Now re-open file, read data, and check values again. */
|
||||
if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
|
||||
if (nc_inq_varid(ncid, STRING_VAR_NAME, &varid_in)) ERR;
|
||||
if (nc_inq_varid(ncid, STRING_VAR_NAME, &varid_in)) ERR;
|
||||
if (nc_get_att_string(ncid, varid_in, "_FillValue", (char **)missing_val_in)) ERR;
|
||||
if (strcmp(missing_val[0], missing_val_in[0])) ERR;
|
||||
if (nc_free_string(FILLVALUE_LEN, (char **)missing_val_in)) ERR;
|
||||
/*if (nc_free_string(FILLVALUE_LEN, (char **)missing_val_in[0])) ERR;*/
|
||||
if (nc_close(ncid)) ERR;
|
||||
free(data_in);
|
||||
free(data_in);
|
||||
}
|
||||
|
||||
SUMMARIZE_ERR;
|
||||
|
@ -295,6 +295,7 @@ main(int argc, char **argv)
|
||||
nc_vlen_t vlen_of_comp_out[DIM1_LEN];
|
||||
struct s2 comp_array_of_comp_out[DIM2_LEN];
|
||||
struct s3 comp_array_of_vlen_of_comp_out[DIM3_LEN];
|
||||
char zero = 0;
|
||||
|
||||
printf("\nTesting nested types across platforms.\n");
|
||||
|
||||
@ -346,16 +347,16 @@ main(int argc, char **argv)
|
||||
/* Create a simple compound type which has different sizes on
|
||||
* different platforms - our old friend struct s1. */
|
||||
if (nc_def_compound(ncid, sizeof(struct s1), S1_TYPE_NAME, &s1_typeid)) ERR;
|
||||
if (nc_insert_compound(ncid, s1_typeid, X_NAME,
|
||||
if (nc_insert_compound(ncid, s1_typeid, X_NAME,
|
||||
NC_COMPOUND_OFFSET(struct s1, x), NC_FLOAT)) ERR;
|
||||
if (nc_insert_compound(ncid, s1_typeid, Y_NAME,
|
||||
if (nc_insert_compound(ncid, s1_typeid, Y_NAME,
|
||||
NC_COMPOUND_OFFSET(struct s1, y), NC_DOUBLE)) ERR;
|
||||
|
||||
/* Now make a new type: a vlen of our compound type. */
|
||||
if (nc_def_vlen(ncid, VLEN_NAME, s1_typeid, &vlen_typeid)) ERR;
|
||||
|
||||
/* Write the output data as an attribute. */
|
||||
if (nc_put_att(ncid, NC_GLOBAL, VLEN_ATT_NAME, vlen_typeid,
|
||||
if (nc_put_att(ncid, NC_GLOBAL, VLEN_ATT_NAME, vlen_typeid,
|
||||
DIM1_LEN, vlen_of_comp_out)) ERR;
|
||||
|
||||
/* How does it look? */
|
||||
@ -379,7 +380,7 @@ main(int argc, char **argv)
|
||||
{
|
||||
strcat(file_in, getenv("srcdir"));
|
||||
strcat(file_in, "/");
|
||||
}
|
||||
}
|
||||
strcat(file_in, REF_FILE_NAME_1);
|
||||
|
||||
/* Check out the same file, generated on buddy and included with
|
||||
@ -438,7 +439,7 @@ main(int argc, char **argv)
|
||||
{
|
||||
strcat(file_in, getenv("srcdir"));
|
||||
strcat(file_in, "/");
|
||||
}
|
||||
}
|
||||
strcat(file_in, REF_FILE_NAME_2);
|
||||
|
||||
/* Check out the same file, generated on buddy and included with
|
||||
|
@ -16,8 +16,6 @@ AM_CPPFLAGS += -I$(top_srcdir)/libsrc4 -I$(top_srcdir)/libsrc
|
||||
# Our test programs and sources. (tst_h_vl2 must come after tst_vl.)
|
||||
NC4_TEST_PROGS = t_type cdm_sea_soundings tst_camrun tst_vl tst_atts \
|
||||
tst_atts2 tst_vars2 tst_files tst_files2
|
||||
cdm_sea_soundings_SOURCES = cdm_sea_soundings.c tests.h
|
||||
tst_camrun_SOURCES = tst_camrun.c tests.h
|
||||
|
||||
check_PROGRAMS = $(NC4_TEST_PROGS)
|
||||
TESTS = $(NC4_TEST_PROGS)
|
||||
@ -28,16 +26,11 @@ TESTS += tst_v2
|
||||
endif # BUILD_V2
|
||||
|
||||
if LARGE_FILE_TESTS
|
||||
tst_large_SOURCES = tst_large.c tests.h
|
||||
check_PROGRAMS += tst_large
|
||||
TESTS += tst_large
|
||||
endif # LARGE_FILE_TESTS
|
||||
|
||||
if BUILD_BENCHMARKS
|
||||
bm_file_SOURCES = bm_file.c tests.h
|
||||
tst_create_files_SOURCES = tst_create_files.c tests.h
|
||||
tst_ar4_SOURCES = tst_ar4.c tests.h
|
||||
tst_chunks_SOURCES = tst_chunks.c tests.h
|
||||
check_PROGRAMS += tst_create_files bm_file tst_chunks tst_ar4 \
|
||||
tst_ar4_3d tst_ar4_4d
|
||||
TESTS += tst_ar4_3d tst_create_files run_bm_test1.sh run_bm_elena.sh \
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
$Id: cdm_sea_soundings.c,v 1.5 2010/05/25 13:53:04 ed Exp $
|
||||
*/
|
||||
#include <tests.h>
|
||||
#include <nc_tests.h>
|
||||
|
||||
#define FILE_NAME "cdm_sea_soundings.nc"
|
||||
#define DIM_NAME "Sounding"
|
||||
|
@ -1,66 +0,0 @@
|
||||
/* This is part of the netCDF package.
|
||||
Copyright 2005 University Corporation for Atmospheric Research/Unidata
|
||||
See COPYRIGHT file for conditions of use.
|
||||
|
||||
Common includes, defines, etc., for test code in the nc_test4
|
||||
directory.
|
||||
|
||||
$Id: tests.h,v 1.6 2010/05/25 13:53:04 ed Exp $
|
||||
*/
|
||||
#ifndef _NC_TEST4_TESTS_
|
||||
#define _NC_TEST4_TESTS_
|
||||
|
||||
#include <config.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef USE_PARALLEL
|
||||
#include <netcdf_par.h>
|
||||
#include <mpi.h>
|
||||
#ifndef MPI_FILE_NULL /*MPIO may be defined in mpi.h already */
|
||||
#include <mpio.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <netcdf.h>
|
||||
|
||||
int total_err = 0, err = 0;
|
||||
|
||||
/* This is handy for print statements. */
|
||||
char *format_name[] = {"", "classic", "64-bit offset", "netCDF-4", "netCDF-4 strict NC3"};
|
||||
|
||||
#define BAIL(e) do { \
|
||||
printf ("Bailing out in file %s, line %d, error:%s.\n", __FILE__, __LINE__, nc_strerror(e)); \
|
||||
return -1; \
|
||||
} while (0)
|
||||
|
||||
#define ERR do { \
|
||||
fflush(stdout); /* Make sure our stdout is synced with stderr. */ \
|
||||
err++; \
|
||||
fprintf(stderr, "unexpected result, %s, line: %d\n", __FILE__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#define SUMMARIZE_ERR do { \
|
||||
if (err) \
|
||||
{ \
|
||||
printf("%d failures\n", err); \
|
||||
total_err += err; \
|
||||
err = 0; \
|
||||
} \
|
||||
else \
|
||||
printf("ok.\n"); \
|
||||
} while (0)
|
||||
|
||||
/* Print out our number of errors, if any, and exit badly. */
|
||||
#define FINAL_RESULTS do { \
|
||||
if (total_err) \
|
||||
{ \
|
||||
printf("%d errors detected! Sorry!\n", total_err); \
|
||||
return 2; \
|
||||
} \
|
||||
printf("*** Tests successful!\n"); \
|
||||
return 0; \
|
||||
} while (0)
|
||||
|
||||
#endif /* _NC_TEST4_TESTS_ */
|
@ -18,6 +18,70 @@ int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
printf("\n*** Testing netcdf-4 attribute copies.\n");
|
||||
printf("*** testing compound attribute copy to different type of same name...");
|
||||
{
|
||||
#define CMP_NAME1 "Ireland"
|
||||
#define I1_NAME "Cork"
|
||||
#define I2_NAME "Dublin"
|
||||
#define DIM_LEN 3
|
||||
#define ATT_NAME3 "Rain"
|
||||
#define NUM_FILES 2
|
||||
|
||||
int ncid[NUM_FILES], typeid;
|
||||
char file_name[NUM_FILES][NC_MAX_NAME + 1] = {FILE_NAME1, FILE_NAME2};
|
||||
int i;
|
||||
struct s1
|
||||
{
|
||||
int i1;
|
||||
int i2;
|
||||
};
|
||||
struct s1 data[DIM_LEN];
|
||||
struct s2
|
||||
{
|
||||
short i1;
|
||||
int i2;
|
||||
};
|
||||
|
||||
/* Create some phony data. */
|
||||
for (i = 0; i < DIM_LEN; i++)
|
||||
{
|
||||
data[i].i1 = 32768;
|
||||
data[i].i2 = 32767;
|
||||
}
|
||||
|
||||
/* Create two files with different compound types of the same name. */
|
||||
for (i = 0; i < NUM_FILES; i++)
|
||||
if (nc_create(file_name[i], NC_NETCDF4, &ncid[i])) ERR;
|
||||
|
||||
/* Define s1 in file 1. */
|
||||
if (nc_def_compound(ncid[0], sizeof(struct s1), CMP_NAME1, &typeid)) ERR;
|
||||
if (nc_insert_compound(ncid[0], typeid, I1_NAME,
|
||||
NC_COMPOUND_OFFSET(struct s1, i1), NC_INT)) ERR;
|
||||
if (nc_insert_compound(ncid[0], typeid, I2_NAME,
|
||||
NC_COMPOUND_OFFSET(struct s1, i2), NC_INT)) ERR;
|
||||
|
||||
/* Define s2 in file 2, but named the same as s1. */
|
||||
if (nc_def_compound(ncid[1], sizeof(struct s2), CMP_NAME1, &typeid)) ERR;
|
||||
if (nc_insert_compound(ncid[1], typeid, I1_NAME,
|
||||
NC_COMPOUND_OFFSET(struct s2, i1), NC_SHORT)) ERR;
|
||||
if (nc_insert_compound(ncid[1], typeid, I2_NAME,
|
||||
NC_COMPOUND_OFFSET(struct s2, i2), NC_INT)) ERR;
|
||||
|
||||
|
||||
/* Write an att in one file. */
|
||||
if (nc_put_att(ncid[0], NC_GLOBAL, ATT_NAME3, typeid, DIM_LEN,
|
||||
data)) ERR;
|
||||
|
||||
/* Try to copy. It must fail, because the two types are not the
|
||||
* same. */
|
||||
if (nc_copy_att(ncid[0], NC_GLOBAL, ATT_NAME3, ncid[1],
|
||||
NC_GLOBAL) != NC_EBADTYPE) ERR;
|
||||
|
||||
/* Close the files. */
|
||||
for (i = 0; i < NUM_FILES; i++)
|
||||
if (nc_close(ncid[i])) ERR;
|
||||
}
|
||||
SUMMARIZE_ERR;
|
||||
printf("*** testing string attribute copy...");
|
||||
{
|
||||
#define ATT_NAME "Irish_Leader"
|
||||
@ -138,70 +202,6 @@ main(int argc, char **argv)
|
||||
if (nc_close(ncid[1])) ERR;
|
||||
}
|
||||
SUMMARIZE_ERR;
|
||||
printf("*** testing compound attribute copy to different type of same name...");
|
||||
{
|
||||
#define CMP_NAME1 "Ireland"
|
||||
#define I1_NAME "Cork"
|
||||
#define I2_NAME "Dublin"
|
||||
#define DIM_LEN 3
|
||||
#define ATT_NAME3 "Rain"
|
||||
#define NUM_FILES 2
|
||||
|
||||
int ncid[NUM_FILES], typeid;
|
||||
char file_name[NUM_FILES][NC_MAX_NAME + 1] = {FILE_NAME1, FILE_NAME2};
|
||||
int i;
|
||||
struct s1
|
||||
{
|
||||
int i1;
|
||||
int i2;
|
||||
};
|
||||
struct s1 data[DIM_LEN];
|
||||
struct s2
|
||||
{
|
||||
short i1;
|
||||
int i2;
|
||||
};
|
||||
|
||||
/* Create some phony data. */
|
||||
for (i = 0; i < DIM_LEN; i++)
|
||||
{
|
||||
data[i].i1 = 32768;
|
||||
data[i].i2 = 32767;
|
||||
}
|
||||
|
||||
/* Create two files with different compound types of the same name. */
|
||||
for (i = 0; i < NUM_FILES; i++)
|
||||
if (nc_create(file_name[i], NC_NETCDF4, &ncid[i])) ERR;
|
||||
|
||||
/* Define s1 in file 1. */
|
||||
if (nc_def_compound(ncid[0], sizeof(struct s1), CMP_NAME1, &typeid)) ERR;
|
||||
if (nc_insert_compound(ncid[0], typeid, I1_NAME,
|
||||
NC_COMPOUND_OFFSET(struct s1, i1), NC_INT)) ERR;
|
||||
if (nc_insert_compound(ncid[0], typeid, I2_NAME,
|
||||
NC_COMPOUND_OFFSET(struct s1, i2), NC_INT)) ERR;
|
||||
|
||||
/* Define s2 in file 2, but named the same as s1. */
|
||||
if (nc_def_compound(ncid[1], sizeof(struct s2), CMP_NAME1, &typeid)) ERR;
|
||||
if (nc_insert_compound(ncid[1], typeid, I1_NAME,
|
||||
NC_COMPOUND_OFFSET(struct s2, i1), NC_SHORT)) ERR;
|
||||
if (nc_insert_compound(ncid[1], typeid, I2_NAME,
|
||||
NC_COMPOUND_OFFSET(struct s2, i2), NC_INT)) ERR;
|
||||
|
||||
|
||||
/* Write an att in one file. */
|
||||
if (nc_put_att(ncid[0], NC_GLOBAL, ATT_NAME3, typeid, DIM_LEN,
|
||||
data)) ERR;
|
||||
|
||||
/* Try to copy. It must fail, because the two types are not the
|
||||
* same. */
|
||||
if (nc_copy_att(ncid[0], NC_GLOBAL, ATT_NAME3, ncid[1],
|
||||
NC_GLOBAL) != NC_EBADTYPE) ERR;
|
||||
|
||||
/* Close the files. */
|
||||
for (i = 0; i < NUM_FILES; i++)
|
||||
if (nc_close(ncid[i])) ERR;
|
||||
}
|
||||
SUMMARIZE_ERR;
|
||||
printf("*** testing simple enum attribute copy...");
|
||||
{
|
||||
#define DIM_LEN_10 10
|
||||
|
@ -7,7 +7,7 @@
|
||||
$Id: tst_mpi_parallel.c,v 1.2 2009/08/19 15:58:57 ed Exp $
|
||||
*/
|
||||
|
||||
#include "tests.h"
|
||||
#include <nc_tests.h>
|
||||
#include <mpi.h>
|
||||
|
||||
#define FILE "tst_mpi_parallel.bin"
|
||||
|
@ -9,7 +9,7 @@ Dennis Nadeau.
|
||||
$Id: tst_nc4perf.c,v 1.4 2009/08/19 15:58:57 ed Exp $
|
||||
*/
|
||||
|
||||
#include "tests.h"
|
||||
#include "nc_tests.h"
|
||||
|
||||
#define FILENAME "tst_nc4perf.nc"
|
||||
#define NDIMS1 2
|
||||
|
@ -13,7 +13,7 @@ $Id: tst_parallel.c,v 1.7 2009/08/19 15:58:57 ed Exp $
|
||||
* clog2TOslog2) and then used in the analysis program jumpshot. */
|
||||
/*#define USE_MPE 1*/
|
||||
|
||||
#include "tests.h"
|
||||
#include <nc_tests.h>
|
||||
#include <mpi.h>
|
||||
#ifdef USE_MPE
|
||||
#include <mpe.h>
|
||||
|
@ -9,7 +9,7 @@
|
||||
* clog2TOslog2) and then used in the analysis program jumpshot. */
|
||||
/*#define USE_MPE 1*/
|
||||
|
||||
#include "tests.h"
|
||||
#include <nc_tests.h>
|
||||
#include <mpi.h>
|
||||
#include <pnetcdf.h>
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tests.h"
|
||||
#include <nc_tests.h>
|
||||
|
||||
#define FILE_NAME "tst_parallel3.nc"
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* clog2TOslog2) and then used in the analysis program jumpshot. */
|
||||
/*#define USE_MPE 1*/
|
||||
|
||||
#include "tests.h"
|
||||
#include <nc_tests.h>
|
||||
#include <mpi.h>
|
||||
#ifdef USE_MPE
|
||||
#include <mpe.h>
|
||||
@ -171,7 +171,7 @@ main(int argc, char **argv)
|
||||
if ((ret = nc_open_par(file_name, NC_NOWRITE, comm, info, &ncid)))
|
||||
{
|
||||
printf("ret = %d\n", ret);
|
||||
ERR;
|
||||
ERR_RET;
|
||||
}
|
||||
if (nc_inq(ncid, &ndims_in, &nvars_in, &natts_in, &unlimdimid_in)) ERR;
|
||||
if (ndims_in != NDIMS || nvars_in != 1 || natts_in != 1 ||
|
||||
|
@ -148,11 +148,13 @@ endif #BUILD_BENCHMARKS
|
||||
|
||||
# Test parallel I/O.
|
||||
if TEST_PARALLEL
|
||||
check_PROGRAMS += f90tst_parallel f90tst_parallel2 f90tst_parallel3
|
||||
check_PROGRAMS += f90tst_parallel f90tst_parallel2 f90tst_parallel3 \
|
||||
f90tst_nc4_par
|
||||
#f90tst_parallel_fill
|
||||
f90tst_parallel_SOURCES = f90tst_parallel.f90
|
||||
f90tst_parallel2_SOURCES = f90tst_parallel2.f90
|
||||
f90tst_parallel3_SOURCES = f90tst_parallel3.f90
|
||||
f90tst_nc4_par_SOURCES = f90tst_nc4_par.f90
|
||||
#f90tst_parallel_fill_SOURCES = f90tst_parallel_fill.f90
|
||||
TESTS += run_f90_par_test.sh
|
||||
CLEANFILES += f90tst_parallel*.nc
|
||||
|
82
nf_test/f90tst_nc4_par.f90
Normal file
82
nf_test/f90tst_nc4_par.f90
Normal file
@ -0,0 +1,82 @@
|
||||
! This parallel test was contributed by Jim Edwards at UCAR. Thanks Jim!
|
||||
program f90tst_nc4_par
|
||||
use netcdf
|
||||
use mpi
|
||||
implicit none
|
||||
|
||||
character (len = *), parameter :: FILE_NAME = "f90tst_nc4_par.nc"
|
||||
integer :: nmode, ierr, fh, my_task, nprocs, i, varid
|
||||
integer :: dimid(3), start(3), count(3)
|
||||
real :: f(3)
|
||||
|
||||
|
||||
call MPI_INIT(ierr)
|
||||
call MPI_COMM_RANK(MPI_COMM_WORLD, my_task, ierr)
|
||||
call MPI_COMM_SIZE(MPI_COMM_WORLD, nprocs, ierr)
|
||||
|
||||
if(nprocs/=8)then
|
||||
stop 'requires 8 tasks'
|
||||
end if
|
||||
|
||||
|
||||
nmode = ior(NF90_CLOBBER,NF90_NETCDF4)
|
||||
nmode = IOR(nmode, nf90_mpiio)
|
||||
|
||||
call handle_err(nf90_create(FILE_NAME, nmode, fh, &
|
||||
comm = MPI_COMM_WORLD, info = MPI_INFO_NULL))
|
||||
|
||||
call handle_err(nf90_set_fill(fh, NF90_NOFILL, nmode))
|
||||
|
||||
|
||||
call handle_err(nf90_def_dim(fh, 'dim1', 6, dimid(1)))
|
||||
call handle_err(nf90_def_dim(fh, 'dim2', 4, dimid(2)))
|
||||
call handle_err(nf90_def_dim(fh, 'dim3', 1, dimid(3)))
|
||||
|
||||
|
||||
call handle_err(nf90_def_var(fh, 'var1', NF90_DOUBLE, dimid, varid))
|
||||
call handle_err(nf90_enddef(fh))
|
||||
|
||||
|
||||
do i=1,3
|
||||
f(i) = my_task*3+i
|
||||
end do
|
||||
|
||||
count = (/3,1,1/)
|
||||
start(1) = mod(my_task,2)*3+1
|
||||
start(2) = my_task/2+1
|
||||
start(3) = 1
|
||||
|
||||
print *,my_task, start, count, f
|
||||
|
||||
call handle_err(nf90_put_var(fh, varid, f,start=start,count=count))
|
||||
|
||||
call handle_err(nf90_close(fh))
|
||||
|
||||
! Reopen the file and check it.
|
||||
call handle_err(nf90_open(FILE_NAME, NF90_MPIIO, fh, &
|
||||
comm = MPI_COMM_WORLD, info = MPI_INFO_NULL))
|
||||
|
||||
call handle_err(nf90_get_var(fh, varid, f, start=start, count=count))
|
||||
do i=1,3
|
||||
if (f(i) .ne. my_task*3+i) stop 3
|
||||
end do
|
||||
|
||||
call handle_err(nf90_close(fh))
|
||||
call MPI_Finalize(ierr)
|
||||
|
||||
contains
|
||||
! This subroutine handles errors by printing an error message and
|
||||
! exiting with a non-zero status.
|
||||
subroutine handle_err(errcode)
|
||||
use netcdf
|
||||
implicit none
|
||||
integer, intent(in) :: errcode
|
||||
|
||||
if(errcode /= nf90_noerr) then
|
||||
print *, 'Error: ', trim(nf90_strerror(errcode))
|
||||
stop 2
|
||||
endif
|
||||
end subroutine handle_err
|
||||
|
||||
end program f90tst_nc4_par
|
||||
|
@ -22,10 +22,9 @@
|
||||
integer NUM_PROC
|
||||
parameter (NUM_PROC = 4)
|
||||
integer ncid, varid, dimids(MAX_DIMS)
|
||||
integer x_dimid, y_dimid, contig
|
||||
integer x_dimid, y_dimid
|
||||
integer data_out(NY / 2, NX / 2), data_in(NY / 2, NX / 2)
|
||||
integer mode_flag
|
||||
integer nvars, ngatts, ndims, unlimdimid, file_format
|
||||
integer x, y, retval
|
||||
integer p, my_rank, ierr
|
||||
integer start(MAX_DIMS), count(MAX_DIMS)
|
||||
|
@ -4,5 +4,7 @@ sleep 2
|
||||
mpiexec -n 4 ./f90tst_parallel
|
||||
mpiexec -n 4 ./f90tst_parallel2
|
||||
mpiexec -n 4 ./f90tst_parallel3
|
||||
mpiexec -n 8 ./f90tst_nc4_par1
|
||||
mpiexec -n 8 ./f90tst_nc4_par
|
||||
#mpiexec -n 4 ./f90tst_parallel_fill
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user