Skip to content

Commit f63ad24

Browse files
Merge pull request #640 from E3SM-Project/jayeshkrishna/support_nc_zarr_via_netcdf
Adding experimental support for NCZarr format via the NetCDF library. A new I/O type, PIO_IOTYPE_NETCDF4P_NCZARR, has been added to read/write NCZarr files using the NetCDF library
2 parents bc69cb4 + 0239acf commit f63ad24

23 files changed

+470
-70
lines changed

cmake/FindNetCDF.cmake

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ find_valid_components (NetCDF)
3737
#==============================================================================
3838
# SEARCH FOR VALIDATED COMPONENTS
3939
foreach (NCDFcomp IN LISTS NetCDF_FIND_VALID_COMPONENTS)
40-
4140
# If not found already, search...
4241
if (NOT NetCDF_${NCDFcomp}_FOUND)
4342

@@ -147,6 +146,25 @@ foreach (NCDFcomp IN LISTS NetCDF_FIND_VALID_COMPONENTS)
147146
CHECK_FUNCTION_EXISTS(nc__enddef NetCDF_C_NC__ENDDEF_EXISTS)
148147
endif ()
149148

149+
string(TOLOWER "${NCDFcomp}" ncdfcomp)
150+
find_program(NetCDF_${NCDFcomp}_CONFIG_EXE
151+
NAMES n${ncdfcomp}-config
152+
HINTS ${NetCDF_${NCDFcomp}_INCLUDE_DIR}/../bin)
153+
154+
if (NetCDF_${NCDFcomp}_CONFIG_EXE)
155+
message(STATUS "NetCDF_${NCDFcomp}_CONFIG_EXE = ${NetCDF_${NCDFcomp}_CONFIG_EXE}")
156+
execute_process(COMMAND "${NetCDF_${NCDFcomp}_CONFIG_EXE}" "--has-nczarr"
157+
OUTPUT_VARIABLE NetCDF_${NCDFcomp}_has_nczarr
158+
OUTPUT_STRIP_TRAILING_WHITESPACE)
159+
if(${NetCDF_${NCDFcomp}_has_nczarr} STREQUAL "yes")
160+
message(STATUS "NetCDF (${NCDFcomp} component) has NCZarr support")
161+
set(NetCDF_${NCDFcomp}_HAS_NCZARR TRUE CACHE BOOL "Has NCZarr support")
162+
else ()
163+
message(STATUS "NetCDF (${NCDFcomp} component) does not have NCZarr support")
164+
endif ()
165+
else ()
166+
message(STATUS "NetCDF_${NCDFcomp}_CONFIG_EXE not found. Disabling checks for NCZarr support.")
167+
endif ()
150168
endif ()
151169

152170
endif ()

examples/c/CMakeLists.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ else ()
3535
endif ()
3636

3737
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -g -O0")
38-
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0")
38+
# "_XOPEN_SOURCE=500" is required for declaration of realpath()
39+
# used by netcdf4p.c
40+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -D_XOPEN_SOURCE=500")
3941
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0")
4042

4143
#==============================================================================
@@ -81,6 +83,9 @@ endif ()
8183
if (WITH_ADIOS2)
8284
add_spio_executable(test_adios TRUE "" test_adios.c)
8385
endif ()
86+
if (WITH_NETCDF)
87+
add_spio_executable(test_netcdf4p TRUE "" netcdf4p.c)
88+
endif ()
8489

8590
if (PIO_ENABLE_FORTRAN)
8691
if (MPE_C_FOUND)
@@ -107,4 +112,7 @@ else ()
107112
if (WITH_ADIOS2)
108113
add_mpi_test(test_adios EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_adios NUMPROCS 4 TIMEOUT 60)
109114
endif ()
115+
if (WITH_NETCDF)
116+
add_mpi_test(test_netcdf4p EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_netcdf4p NUMPROCS 4 TIMEOUT 60)
117+
endif ()
110118
endif ()

examples/c/netcdf4p.c

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
#include <stdio.h>
2+
#include <limits.h>
3+
#include <stdlib.h>
4+
#include <libgen.h>
5+
#include <sys/types.h>
6+
#include <sys/stat.h>
7+
#include <mpi.h>
8+
#include <pio.h>
9+
#include "pio_config.h"
10+
#include <assert.h>
11+
#include <math.h>
12+
#include <string.h>
13+
#ifdef SPIO_ENABLE_GPTL_TIMING
14+
#include <gptl.h>
15+
#endif
16+
#if PIO_USE_NETCDF4
17+
#include <netcdf.h>
18+
#endif
19+
20+
#if PIO_USE_NETCDF4
21+
#define ERR(rank, ret, err_msg) do{\
22+
if(ret != NC_NOERR){\
23+
printf("[%d]: FATAL ERROR : ", rank); \
24+
printf(err_msg); \
25+
printf(" (err = %d, line no = %d)\n", ret, __LINE__);\
26+
return ret; \
27+
}\
28+
}while(0)
29+
#endif
30+
31+
#define NDIMS 3
32+
#define DIM_TIME_SZ 1
33+
#define DIM_LEV_SZ 5
34+
#define DIM_NCOLS_SZ_PER_PROC 10
35+
#define FILE_PATH_MAX_SZ PATH_MAX+1
36+
37+
#if PIO_USE_NETCDF4
38+
39+
int get_nczarr_fname(MPI_Comm comm, int comm_rank, int comm_sz,
40+
const char *fname, size_t fname_sz, char *nczarr_fname, size_t nczarr_fname_sz)
41+
{
42+
const char *nczarr_prefix = "file://";
43+
const char *nczarr_suffix = "#mode=nczarr,file";
44+
char real_fname[FILE_PATH_MAX_SZ + 1] = "\0";
45+
46+
assert(nczarr_fname_sz >= fname_sz);
47+
48+
int real_fname_len = 0;
49+
if(comm_rank == 0){
50+
char real_dname[FILE_PATH_MAX_SZ + 1];
51+
char dname[FILE_PATH_MAX_SZ + 1];
52+
char bname[FILE_PATH_MAX_SZ + 1];
53+
54+
strncpy(dname, fname, FILE_PATH_MAX_SZ); dname[FILE_PATH_MAX_SZ] = '\0';
55+
strncpy(bname, fname, FILE_PATH_MAX_SZ); bname[FILE_PATH_MAX_SZ] = '\0';
56+
57+
char *dname_ptr = dirname(dname);
58+
char *bname_ptr = basename(bname);
59+
60+
char *real_dname_ptr = realpath(dname_ptr, real_dname);
61+
ERR(comm_rank, (real_dname_ptr != NULL) ? 0 : -1, "Converting relative file path/name to full/real path failed");
62+
63+
snprintf(real_fname, FILE_PATH_MAX_SZ, "%s/%s", real_dname_ptr, bname_ptr);
64+
65+
//int ret = mkdir(real_fname, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP);
66+
//ERR(comm_rank, ((ret == -1) && (errno == EEXIST)) ? 0 : ret, "Creating directory, for NCZarr file, failed");
67+
68+
real_fname_len = strlen(real_fname) + 1;
69+
}
70+
71+
MPI_Bcast(&real_fname_len, 1, MPI_INT, 0, comm);
72+
assert(((int )nczarr_fname_sz) >= real_fname_len);
73+
74+
MPI_Bcast(real_fname, real_fname_len, MPI_CHAR, 0, comm);
75+
76+
snprintf(nczarr_fname, nczarr_fname_sz, "%s%s%s", nczarr_prefix, real_fname, nczarr_suffix);
77+
78+
return NC_NOERR;
79+
}
80+
81+
int test_nc_file_ops(MPI_Comm comm, const char *fname, size_t fname_sz, int omode)
82+
{
83+
int ret = NC_NOERR;
84+
int fh = -1;
85+
int comm_rank, comm_sz;
86+
const char *dim_names[] = {"time", "lev", "ncols"};
87+
int dim_ids[NDIMS];
88+
int varid = -1;
89+
90+
MPI_Comm_rank(comm, &comm_rank);
91+
MPI_Comm_size(comm, &comm_sz);
92+
93+
ret = nc_create_par(fname, omode, comm, MPI_INFO_NULL, &fh); ERR(comm_rank, ret, "Creating file failed");
94+
95+
size_t dim_sz[NDIMS] = {DIM_TIME_SZ, DIM_LEV_SZ, DIM_NCOLS_SZ_PER_PROC * comm_sz};
96+
for(int i=0; i < NDIMS; i++){
97+
ret = nc_def_dim(fh, dim_names[i], dim_sz[i], &dim_ids[i]); ERR(comm_rank, ret, "Defining dimension in file failed");
98+
}
99+
100+
double var[DIM_TIME_SZ][DIM_LEV_SZ][DIM_NCOLS_SZ_PER_PROC];
101+
for(int i = 0; i < DIM_TIME_SZ; i++){
102+
for(int j = 0; j < DIM_LEV_SZ; j++){
103+
for(int k = 0; k < DIM_NCOLS_SZ_PER_PROC; k++){
104+
var[i][j][k] = i * (DIM_LEV_SZ * DIM_NCOLS_SZ_PER_PROC * comm_sz) + j * (DIM_NCOLS_SZ_PER_PROC * comm_sz) + (DIM_NCOLS_SZ_PER_PROC * comm_rank) + k;
105+
}
106+
}
107+
}
108+
ret = nc_def_var(fh, "tmp_var", NC_DOUBLE, NDIMS, dim_ids, &varid); ERR(comm_rank, ret, "Defining variable (\"tmp_var\") failed");
109+
110+
ret = nc_enddef(fh); ERR(comm_rank, ret, "Ending define mode failed");
111+
112+
char info[] = "SCORPIO test";
113+
ret = nc_put_att_text(fh, NC_GLOBAL, "info", strlen(info) + 1, info); ERR(comm_rank, ret, "Adding global attribute (\"info\" failed");
114+
115+
ret = nc_var_par_access(fh, varid, NC_COLLECTIVE); ERR(comm_rank, ret, "Setting parallel/collective access for variable failed");
116+
117+
size_t starts[NDIMS] = {0, 0, comm_rank * DIM_NCOLS_SZ_PER_PROC};
118+
size_t counts[NDIMS] = {DIM_TIME_SZ, DIM_LEV_SZ, DIM_NCOLS_SZ_PER_PROC};
119+
ret = nc_put_vara_double(fh, varid, starts, counts, (const double *)var); ERR(comm_rank, ret, "Writing variable in parallel failed");
120+
121+
ret = nc_close(fh); ERR(comm_rank, ret, "Closing file failed");
122+
123+
if(comm_rank == 0){
124+
printf("Testing %s : SUCCESS\n", fname); fflush(stdout);
125+
}
126+
127+
return ret;
128+
}
129+
130+
int test_netcdf4p(MPI_Comm comm)
131+
{
132+
int omode = NC_MPIIO | NC_CLOBBER | NC_NETCDF4;
133+
const char fname[] = "spio_test_netcdf4p.nc";
134+
135+
return test_nc_file_ops(comm, fname, strlen(fname) + 1, omode);
136+
}
137+
138+
int test_netcdf4p_nczarr(MPI_Comm comm)
139+
{
140+
int ret = NC_NOERR;
141+
int omode = NC_CLOBBER | NC_NETCDF4;
142+
const char fname[] = "./spio_test_netcdf4p_nczarr.file";
143+
char nczarr_fname[FILE_PATH_MAX_SZ + 1] = "\0";
144+
int comm_rank, comm_sz;
145+
146+
MPI_Comm_rank(comm, &comm_rank);
147+
MPI_Comm_size(comm, &comm_sz);
148+
149+
ret = get_nczarr_fname(comm, comm_rank, comm_sz, fname, strlen(fname) + 1, nczarr_fname, FILE_PATH_MAX_SZ + 1);
150+
ERR(comm_rank, ret, "Getting NCZarr file name failed");
151+
152+
return test_nc_file_ops(comm, nczarr_fname, strlen(nczarr_fname) + 1, omode);
153+
}
154+
#endif
155+
156+
int main(int argc, char *argv[])
157+
{
158+
int ret = NC_NOERR;
159+
160+
#if PIO_USE_NETCDF4
161+
#ifdef SPIO_ENABLE_GPTL_TIMING
162+
GPTLinitialize();
163+
#endif
164+
MPI_Init(&argc, &argv);
165+
166+
ret = test_netcdf4p(MPI_COMM_WORLD);
167+
168+
if(ret == NC_NOERR){
169+
if((argc > 1) && (strcmp(argv[1], "--test-nczarr") == 0)){
170+
ret = test_netcdf4p_nczarr(MPI_COMM_WORLD);
171+
}
172+
}
173+
174+
MPI_Finalize();
175+
#ifdef SPIO_ENABLE_GPTL_TIMING
176+
GPTLfinalize();
177+
#endif
178+
#endif
179+
180+
return ret;
181+
}

src/clib/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ if (WITH_NETCDF)
110110
PUBLIC ${NetCDF_C_LIBRARIES})
111111
if (${NetCDF_C_HAS_PARALLEL})
112112
set(PIO_USE_NETCDF4 1)
113+
if (${NetCDF_C_HAS_NCZARR})
114+
set(PIO_USE_NETCDF4_NCZARR 1)
115+
target_compile_definitions (pioc
116+
PUBLIC _SPIO_HAS_NETCDF4_NCZARR)
117+
else ()
118+
set(PIO_USE_NETCDF4_NCZARR 0)
119+
endif ()
113120
else ()
114121
set(PIO_USE_NETCDF4 0)
115122
endif ()

src/clib/pio.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,14 +1213,17 @@ enum PIO_IOTYPE
12131213
/** NetCDF4 (HDF5) parallel */
12141214
PIO_IOTYPE_NETCDF4P = 4,
12151215

1216+
/** NetCDF4 (HDF5) parallel NCZarr */
1217+
PIO_IOTYPE_NETCDF4P_NCZARR = 5,
1218+
12161219
/** ADIOS parallel */
1217-
PIO_IOTYPE_ADIOS = 5,
1220+
PIO_IOTYPE_ADIOS = 6,
12181221

12191222
/** ADIOS parallel with compression */
1220-
PIO_IOTYPE_ADIOSC = 6,
1223+
PIO_IOTYPE_ADIOSC = 7,
12211224

12221225
/** HDF5 parallel */
1223-
PIO_IOTYPE_HDF5 = 7
1226+
PIO_IOTYPE_HDF5 = 8
12241227
};
12251228

12261229
/**

src/clib/pio_config.h.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@
7676
* in the NetCDF library, 0 otherwise */
7777
#define PIO_USE_NETCDF4 @PIO_USE_NETCDF4@
7878

79+
/** Set to 1 if the library is configured to use the NetCDF4 features,
80+
* and has NCZarr support, 0 otherwise */
81+
#define PIO_USE_NETCDF4_NCZARR @PIO_USE_NETCDF4_NCZARR@
82+
7983
/** Set to 1 if the library is configured to use the ADIOS library,
8084
* 0 otherwise */
8185
#define PIO_USE_ADIOS @PIO_USE_ADIOS@

src/clib/pio_darray.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar
509509
switch (file->iotype)
510510
{
511511
case PIO_IOTYPE_NETCDF4P:
512+
case PIO_IOTYPE_NETCDF4P_NCZARR:
512513
case PIO_IOTYPE_PNETCDF:
513514
case PIO_IOTYPE_HDF5:
514515
if ((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc,
@@ -595,6 +596,7 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar
595596
{
596597
case PIO_IOTYPE_PNETCDF:
597598
case PIO_IOTYPE_NETCDF4P:
599+
case PIO_IOTYPE_NETCDF4P_NCZARR:
598600
if ((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc,
599601
DARRAY_FILL, frame)))
600602
{
@@ -3924,6 +3926,7 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen,
39243926
break;
39253927
case PIO_IOTYPE_PNETCDF:
39263928
case PIO_IOTYPE_NETCDF4P:
3929+
case PIO_IOTYPE_NETCDF4P_NCZARR:
39273930
if ((ierr = pio_read_darray_nc(file, fndims, iodesc, varid, iobuf)))
39283931
{
39293932
GPTLstop("PIO:PIOc_read_darray");

src/clib/pio_darray_int.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ int write_darray_multi_par(file_desc_t *file, int nvars, int fndims, const int *
246246
{
247247
#ifdef _NETCDF4
248248
case PIO_IOTYPE_NETCDF4P:
249+
case PIO_IOTYPE_NETCDF4P_NCZARR:
249250
/* For each variable to be written. */
250251
for (int nv = 0; nv < nvars; nv++)
251252
{
@@ -262,7 +263,7 @@ int write_darray_multi_par(file_desc_t *file, int nvars, int fndims, const int *
262263
if(ierr != NC_NOERR)
263264
{
264265
ierr = pio_err(ios, file, ierr, __FILE__, __LINE__,
265-
"Writing variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_NETCDF4P iotype failed. Changing parallel access for variable (%s, varid=%d) to collective failed", nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, varids[nv]), varids[nv]);
266+
"Writing variables (number of variables = %d) to file (%s, ncid=%d) using %s iotype failed. Changing parallel access for variable (%s, varid=%d) to collective failed", nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype), pio_get_vname_from_file(file, varids[nv]), varids[nv]);
266267
break;
267268
}
268269

@@ -306,13 +307,13 @@ int write_darray_multi_par(file_desc_t *file, int nvars, int fndims, const int *
306307
break;
307308
default:
308309
ierr = pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__,
309-
"Writing variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_NETCDF4P iotype failed. Unsupported variable data type (type=%d)", nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype);
310+
"Writing variables (number of variables = %d) to file (%s, ncid=%d) using %s iotype failed. Unsupported variable data type (type=%d)", nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype), iodesc->piotype);
310311
break;
311312
}
312313
if(ierr != NC_NOERR)
313314
{
314315
ierr = pio_err(ios, file, ierr, __FILE__, __LINE__,
315-
"Writing variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_NETCDF4P iotype failed. Writing variable (%s, varid=%d) failed", nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, varids[nv]), varids[nv]);
316+
"Writing variables (number of variables = %d) to file (%s, ncid=%d) using %s iotype failed. Writing variable (%s, varid=%d) failed", nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype), pio_get_vname_from_file(file, varids[nv]), varids[nv]);
316317
break;
317318
}
318319
}
@@ -1249,6 +1250,7 @@ int pio_read_darray_nc(file_desc_t *file, int fndims, io_desc_t *iodesc, int vid
12491250
{
12501251
#ifdef _NETCDF4
12511252
case PIO_IOTYPE_NETCDF4P:
1253+
case PIO_IOTYPE_NETCDF4P_NCZARR:
12521254
/* ierr = nc_get_vara(file->fh, vid, start, count, bufptr); */
12531255
switch (iodesc->piotype)
12541256
{
@@ -1290,7 +1292,7 @@ int pio_read_darray_nc(file_desc_t *file, int fndims, io_desc_t *iodesc, int vid
12901292
break;
12911293
default:
12921294
ierr = pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__,
1293-
"Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed with iotype=PIO_IOTYPE_NETCDF4P. Unsupported variable type (type=%d)", pio_get_vname_from_file(file, vid), vid, pio_get_fname_from_file(file), file->pio_ncid, file->iotype);
1295+
"Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed with iotype=%s. Unsupported variable type (type=%d)", pio_get_vname_from_file(file, vid), vid, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype), file->iotype);
12941296
break;
12951297
}
12961298
break;
@@ -1359,7 +1361,7 @@ int pio_read_darray_nc(file_desc_t *file, int fndims, io_desc_t *iodesc, int vid
13591361
LOG((1, "nc*_get_var* failed, ierr = %d", ierr));
13601362
GPTLstop("PIO:read_darray_nc");
13611363
return pio_err(NULL, file, ierr, __FILE__, __LINE__,
1362-
"Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed with iotype=%s. The underlying I/O library (%s) call, nc*_get_var*, failed.", pio_get_vname_from_file(file, vid), vid, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype), (file->iotype == PIO_IOTYPE_NETCDF4P) ? "NetCDF" : "PnetCDF");
1364+
"Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed with iotype=%s. The underlying I/O library (%s) call, nc*_get_var*, failed.", pio_get_vname_from_file(file, vid), vid, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype), ((file->iotype == PIO_IOTYPE_NETCDF4P) || (file->iotype == PIO_IOTYPE_NETCDF4P_NCZARR)) ? "NetCDF" : "PnetCDF");
13631365
}
13641366

13651367
/* Stop timing this function. */

0 commit comments

Comments
 (0)