2010-06-03 21:24:43 +08:00
|
|
|
/* This is part of the netCDF package.
|
2018-12-07 06:27:32 +08:00
|
|
|
Copyright 2018 University Corporation for Atmospheric Research/Unidata
|
2010-06-03 21:24:43 +08:00
|
|
|
See COPYRIGHT file for conditions of use.
|
|
|
|
|
2016-10-22 03:24:40 +08:00
|
|
|
Test netcdf-4 compound type feature.
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
$Id: tst_compounds2.c,v 1.15 2010/05/25 13:53:04 ed Exp $
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <nc_tests.h>
|
2016-10-22 03:24:40 +08:00
|
|
|
#include "err_macros.h"
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
#define FILE_NAME "tst_compounds2.nc"
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
|
2016-10-22 03:24:40 +08:00
|
|
|
printf("\n*** Testing netcdf-4 user defined type functions, even more.\n");
|
|
|
|
printf("*** testing compound var containing byte arrays of various size...");
|
2010-06-03 21:24:43 +08:00
|
|
|
{
|
2016-10-22 03:24:40 +08:00
|
|
|
#define DIM1_LEN 1
|
2010-06-03 21:24:43 +08:00
|
|
|
#define ARRAY_LEN (NC_MAX_NAME + 1)
|
|
|
|
int ncid;
|
|
|
|
size_t len;
|
|
|
|
nc_type xtype, type_id;
|
|
|
|
int dim_sizes[] = {ARRAY_LEN};
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
struct s1
|
|
|
|
{
|
|
|
|
unsigned char x[ARRAY_LEN];
|
|
|
|
float y;
|
|
|
|
};
|
|
|
|
struct s1 data_out[DIM1_LEN], data_in[DIM1_LEN];
|
|
|
|
char *dummy;
|
|
|
|
|
|
|
|
printf("array len=%d... ", ARRAY_LEN);
|
|
|
|
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
|
|
* is only needed to pass valgrind. */
|
2016-10-22 03:24:40 +08:00
|
|
|
if (!(dummy = calloc(sizeof(struct s1), DIM1_LEN)))
|
|
|
|
return NC_ENOMEM;
|
|
|
|
memcpy((void *)data_out, (void *)dummy, sizeof(struct s1) * DIM1_LEN);
|
|
|
|
free(dummy);
|
2010-06-03 21:24:43 +08:00
|
|
|
|
2016-10-22 03:24:40 +08:00
|
|
|
/* Create some phony data. */
|
2010-06-03 21:24:43 +08:00
|
|
|
for (i = 0; i < DIM1_LEN; i++)
|
|
|
|
{
|
2023-10-26 23:01:24 +08:00
|
|
|
data_out[i].y = 99.99f;
|
2010-06-03 21:24:43 +08:00
|
|
|
for (j = 0; j < ARRAY_LEN; j++)
|
2024-03-12 00:53:35 +08:00
|
|
|
data_out[i].x[j] = (unsigned char)j;
|
2010-06-03 21:24:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a file with a nested compound type attribute and variable. */
|
2016-10-22 03:24:40 +08:00
|
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
2010-06-03 21:24:43 +08:00
|
|
|
|
|
|
|
/* Now define the compound type. */
|
|
|
|
if (nc_def_compound(ncid, sizeof(struct s1), "c", &type_id)) ERR;
|
|
|
|
if (nc_insert_array_compound(ncid, type_id, "x",
|
|
|
|
NC_COMPOUND_OFFSET(struct s1, x), NC_UBYTE, 1, dim_sizes)) ERR;
|
|
|
|
if (nc_insert_compound(ncid, type_id, "y",
|
|
|
|
NC_COMPOUND_OFFSET(struct s1, y), NC_FLOAT)) ERR;
|
|
|
|
|
|
|
|
/* Write it as an attribute. */
|
|
|
|
if (nc_put_att(ncid, NC_GLOBAL, "a1", type_id, DIM1_LEN, data_out)) ERR;
|
|
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
|
|
|
|
/* Read the att and check values. */
|
|
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
|
|
if (nc_get_att(ncid, NC_GLOBAL, "a1", data_in)) ERR;
|
|
|
|
for (i=0; i<DIM1_LEN; i++)
|
|
|
|
{
|
|
|
|
if (data_in[i].y != data_out[i].y) ERR;
|
|
|
|
for (j = 0; j < ARRAY_LEN; j++)
|
|
|
|
if (data_in[i].x[j] != data_out[i].x[j]) ERR_RET;
|
|
|
|
}
|
2016-10-22 03:24:40 +08:00
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Use the inq functions to learn about the compound type. */
|
|
|
|
if (nc_inq_att(ncid, NC_GLOBAL, "a1", &xtype, &len)) ERR;
|
|
|
|
if (len != DIM1_LEN) ERR;
|
2016-10-22 03:24:40 +08:00
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Finish checking the containing compound type. */
|
|
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
SUMMARIZE_ERR;
|
|
|
|
printf("*** testing compound var on different machines...");
|
|
|
|
{
|
|
|
|
#define DIM1_LEN 1
|
|
|
|
#define NAME1 "x"
|
|
|
|
#define NAME2 "y"
|
|
|
|
int ncid;
|
|
|
|
size_t len;
|
|
|
|
nc_type xtype, type_id;
|
|
|
|
char field_name_in[NC_MAX_NAME + 1];
|
|
|
|
size_t offset_in;
|
|
|
|
int field_ndims;
|
|
|
|
nc_type field_typeid;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
struct s1
|
|
|
|
{
|
|
|
|
float x;
|
|
|
|
double y;
|
|
|
|
};
|
|
|
|
struct s1 data_out[DIM1_LEN], data_in[DIM1_LEN];
|
|
|
|
char *dummy;
|
|
|
|
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
|
|
* is only needed to pass valgrind. */
|
|
|
|
if (!(dummy = calloc(sizeof(struct s1), DIM1_LEN)))
|
|
|
|
return NC_ENOMEM;
|
|
|
|
memcpy((void *)data_out, (void *)dummy, sizeof(struct s1) * DIM1_LEN);
|
|
|
|
free(dummy);
|
|
|
|
|
|
|
|
/* Create some phony data. */
|
|
|
|
for (i = 0; i < DIM1_LEN; i++)
|
|
|
|
{
|
|
|
|
data_out[i].x = 1;
|
|
|
|
data_out[i].y = -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a file with a nested compound type attribute and variable. */
|
|
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
|
|
|
|
|
|
/* Now define the compound type. */
|
|
|
|
if (nc_def_compound(ncid, sizeof(struct s1), "c", &type_id)) ERR;
|
|
|
|
if (nc_insert_compound(ncid, type_id, NAME1,
|
|
|
|
NC_COMPOUND_OFFSET(struct s1, x), NC_FLOAT)) ERR;
|
|
|
|
if (nc_insert_compound(ncid, type_id, NAME2,
|
|
|
|
NC_COMPOUND_OFFSET(struct s1, y), NC_DOUBLE)) ERR;
|
|
|
|
|
|
|
|
/* Write it as an attribute. */
|
|
|
|
if (nc_put_att(ncid, NC_GLOBAL, "a1", type_id, DIM1_LEN, data_out)) ERR;
|
|
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
|
|
|
|
/* Read the att and check values. */
|
|
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
|
|
if (nc_get_att(ncid, NC_GLOBAL, "a1", data_in)) ERR;
|
|
|
|
for (i = 0; i < DIM1_LEN; i++)
|
|
|
|
if (data_in[i].x != data_out[i].x || data_in[i].y != data_out[i].y) ERR;
|
2016-10-22 03:24:40 +08:00
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Use the inq functions to learn about the compound type. */
|
|
|
|
if (nc_inq_att(ncid, NC_GLOBAL, "a1", &xtype, &len)) ERR;
|
|
|
|
if (len != DIM1_LEN) ERR;
|
|
|
|
if (nc_inq_compound_field(ncid, xtype, 0, field_name_in,
|
|
|
|
&offset_in, &field_typeid, &field_ndims, NULL)) ERR;
|
|
|
|
if (strcmp(field_name_in, NAME1) || field_typeid != NC_FLOAT || field_ndims) ERR;
|
|
|
|
printf("offset x: %d ", (int)offset_in);
|
|
|
|
if (nc_inq_compound_field(ncid, xtype, 1, field_name_in,
|
|
|
|
&offset_in, &field_typeid, &field_ndims, NULL)) ERR;
|
|
|
|
if (strcmp(field_name_in, NAME2) || field_typeid != NC_DOUBLE || field_ndims) ERR;
|
|
|
|
printf("offset y: %d NC_COMPOUND_OFFSET(struct s1, y): %d ", (int)offset_in,
|
|
|
|
(int)NC_COMPOUND_OFFSET(struct s1, y));
|
2016-10-22 03:24:40 +08:00
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Finish checking the containing compound type. */
|
|
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
SUMMARIZE_ERR;
|
|
|
|
printf("*** testing compound var containing compound var, on different machines...");
|
|
|
|
{
|
|
|
|
#define DIM1_LEN 1
|
|
|
|
#define S1_NAME_X "x"
|
|
|
|
#define S1_NAME_Y "y"
|
|
|
|
#define S2_NAME_S1 "s1"
|
|
|
|
#define NUM_TYPES 2
|
|
|
|
#define INNER_TYPE_NAME "c"
|
|
|
|
#define OUTER_TYPE_NAME "d"
|
|
|
|
#define ATT_NAME "a1"
|
|
|
|
|
|
|
|
int ncid;
|
|
|
|
size_t len;
|
|
|
|
nc_type inner_typeid = 0, outer_typeid, s1_typeid, s2_typeid;
|
|
|
|
char field_name_in[NC_MAX_NAME + 1];
|
|
|
|
size_t offset_in;
|
|
|
|
int field_ndims;
|
|
|
|
nc_type field_typeid;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
struct s1
|
|
|
|
{
|
|
|
|
float x;
|
|
|
|
double y;
|
|
|
|
};
|
|
|
|
struct s2
|
|
|
|
{
|
|
|
|
struct s1 s1;
|
|
|
|
};
|
|
|
|
struct s2 data_out[DIM1_LEN], data_in[DIM1_LEN];
|
|
|
|
int ntypes, typeids[NUM_TYPES];
|
|
|
|
size_t size_in, nfields_in;
|
|
|
|
char name_in[NC_MAX_NAME + 1];
|
|
|
|
int t;
|
|
|
|
char *dummy;
|
|
|
|
|
|
|
|
/* REALLY initialize the data (even the gaps in the structs). This
|
|
|
|
* is only needed to pass valgrind. */
|
|
|
|
if (!(dummy = calloc(sizeof(struct s2), DIM1_LEN)))
|
|
|
|
return NC_ENOMEM;
|
|
|
|
memcpy((void *)data_out, (void *)dummy, sizeof(struct s2) * DIM1_LEN);
|
|
|
|
free(dummy);
|
|
|
|
|
|
|
|
/* Create some phony data. */
|
|
|
|
for (i = 0; i < DIM1_LEN; i++)
|
|
|
|
{
|
|
|
|
data_out[i].s1.x = 1;
|
|
|
|
data_out[i].s1.y = -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a file with a nested compound type attribute and variable. */
|
|
|
|
if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR;
|
|
|
|
|
|
|
|
/* Now define the inner compound type. */
|
|
|
|
if (nc_def_compound(ncid, sizeof(struct s1), INNER_TYPE_NAME, &s1_typeid)) ERR;
|
|
|
|
if (nc_insert_compound(ncid, s1_typeid, S1_NAME_X,
|
|
|
|
NC_COMPOUND_OFFSET(struct s1, x), NC_FLOAT)) ERR;
|
|
|
|
if (nc_insert_compound(ncid, s1_typeid, S1_NAME_Y,
|
|
|
|
NC_COMPOUND_OFFSET(struct s1, y), NC_DOUBLE)) ERR;
|
|
|
|
|
|
|
|
/* Define the outer compound type. */
|
|
|
|
if (nc_def_compound(ncid, sizeof(struct s2), OUTER_TYPE_NAME, &s2_typeid)) ERR;
|
|
|
|
if (nc_insert_compound(ncid, s2_typeid, S2_NAME_S1,
|
|
|
|
NC_COMPOUND_OFFSET(struct s2, s1), s1_typeid)) ERR;
|
|
|
|
|
|
|
|
/* Write it as an attribute. */
|
|
|
|
if (nc_put_att(ncid, NC_GLOBAL, ATT_NAME, s2_typeid, DIM1_LEN, data_out)) ERR;
|
|
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
|
|
|
|
/* Read the att and check values. */
|
|
|
|
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
|
|
|
if (nc_get_att(ncid, NC_GLOBAL, ATT_NAME, data_in)) ERR;
|
|
|
|
for (i = 0; i < DIM1_LEN; i++)
|
|
|
|
if (data_in[i].s1.x != data_out[i].s1.x || data_in[i].s1.y != data_out[i].s1.y) ERR;
|
2016-10-22 03:24:40 +08:00
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Use the inq functions to learn about the compound type. */
|
|
|
|
if (nc_inq_typeids(ncid, &ntypes, typeids)) ERR;
|
|
|
|
if (ntypes != NUM_TYPES) ERR;
|
|
|
|
for (t = 0; t < NUM_TYPES; t++)
|
|
|
|
{
|
|
|
|
if (nc_inq_compound(ncid, typeids[t], name_in, &size_in, &nfields_in)) ERR;
|
|
|
|
if (!strcmp(name_in, INNER_TYPE_NAME))
|
|
|
|
inner_typeid = typeids[t];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* What type is the attribute? */
|
|
|
|
if (nc_inq_att(ncid, NC_GLOBAL, ATT_NAME, &outer_typeid, &len)) ERR;
|
|
|
|
if (len != DIM1_LEN) ERR;
|
|
|
|
if (nc_inq_compound_field(ncid, outer_typeid, 0, field_name_in,
|
|
|
|
&offset_in, &field_typeid, &field_ndims, NULL)) ERR;
|
|
|
|
if (strcmp(field_name_in, S2_NAME_S1) || field_typeid != inner_typeid || field_ndims) ERR;
|
|
|
|
if (nc_inq_compound_field(ncid, field_typeid, 1, field_name_in,
|
|
|
|
&offset_in, &field_typeid, &field_ndims, NULL)) ERR;
|
|
|
|
if (strcmp(field_name_in, S1_NAME_Y) || field_typeid != NC_DOUBLE || field_ndims) ERR;
|
2016-10-22 03:24:40 +08:00
|
|
|
|
2010-06-03 21:24:43 +08:00
|
|
|
/* Finish checking the containing compound type. */
|
|
|
|
if (nc_close(ncid)) ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
SUMMARIZE_ERR;
|
|
|
|
FINAL_RESULTS;
|
|
|
|
}
|