diff --git a/ChangeLog b/ChangeLog index 2c69a9388abc04de92e964ba3091bd5415c3353f..5f89a5a62ad56453e31c49bf4c1d0e98d62c2d77 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2017-05-16 Uwe Schulzweida + + * Version 1.8.2 released + +2017-05-15 Uwe Schulzweida + + * added env. variable CDI_COORDINATES_LONLAT to change the order of lon and lat for the coordinates attribute. + +2017-05-12 Uwe Schulzweida + + * merged branch charxy [Fabian Wachsmann] + +2017-04-25 Uwe Schulzweida + + * initialize taxisptr->units to NULL after calling delete_refcount_string() [Bug #7691] + +2017-04-21 Uwe Schulzweida + + * gribapiGetDiskRepresentation: Wrong result with SZIP compressed GRIB records [Bug #7650] + 2017-04-13 Uwe Schulzweida * Version 1.8.1 released diff --git a/configure b/configure index 896321c1689a8953ac8dae86100bcd32b27b793e..3b6c032eea31600e5ee8353544cf3478a19661f4 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for cdi 1.8.1. +# Generated by GNU Autoconf 2.68 for cdi 1.8.2. # # Report bugs to <http://mpimet.mpg.de/cdi>. # @@ -570,8 +570,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='cdi' PACKAGE_TARNAME='cdi' -PACKAGE_VERSION='1.8.1' -PACKAGE_STRING='cdi 1.8.1' +PACKAGE_VERSION='1.8.2' +PACKAGE_STRING='cdi 1.8.2' PACKAGE_BUGREPORT='http://mpimet.mpg.de/cdi' PACKAGE_URL='' @@ -1463,7 +1463,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures cdi 1.8.1 to adapt to many kinds of systems. +\`configure' configures cdi 1.8.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1533,7 +1533,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of cdi 1.8.1:";; + short | recursive ) echo "Configuration of cdi 1.8.2:";; esac cat <<\_ACEOF @@ -1728,7 +1728,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -cdi configure 1.8.1 +cdi configure 1.8.2 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -2573,7 +2573,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by cdi $as_me 1.8.1, which was +It was created by cdi $as_me 1.8.2, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -3525,7 +3525,7 @@ fi # Define the identity of the package. PACKAGE='cdi' - VERSION='1.8.1' + VERSION='1.8.2' cat >>confdefs.h <<_ACEOF @@ -23442,7 +23442,7 @@ Usage: $0 [OPTIONS] Report bugs to <bug-libtool@gnu.org>." lt_cl_version="\ -cdi config.lt 1.8.1 +cdi config.lt 1.8.2 configured by $0, generated by GNU Autoconf 2.68. Copyright (C) 2011 Free Software Foundation, Inc. @@ -27533,12 +27533,12 @@ return H5get_libversion (); return 0; } _ACEOF -for ac_lib in '' netcdf; do +for ac_lib in '' netcdf hdf5; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib - LIBS="-l$ac_lib -lhdf5 $ac_func_search_save_LIBS" + LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_H5get_libversion=$ac_res @@ -29996,7 +29996,7 @@ cat >>confdefs.h <<_ACEOF _ACEOF -ac_config_files="$ac_config_files tests/test_cksum_grib tests/test_cksum_nc tests/test_cksum_nc2 tests/test_cksum_nc4 tests/test_cksum_extra tests/test_cksum_service tests/test_cksum_ieg tests/test_chunk_cksum tests/test_f2003 tests/pio_write_run tests/pio_write_deco2d_run tests/pio_cksum_mpinonb tests/pio_cksum_mpi_fw_ordered tests/pio_cksum_mpi_fw_at_all tests/pio_cksum_mpi_fw_at_reblock tests/pio_cksum_fpguard tests/pio_cksum_asynch tests/pio_cksum_writer tests/pio_cksum_cdf tests/test_resource_copy_mpi_run tests/test_cdf_transformation tables/gen_tableheaderfile util/serialrun" +ac_config_files="$ac_config_files tests/test_cksum_grib tests/test_cksum_nc tests/test_cksum_nc2 tests/test_cksum_nc4 tests/test_cksum_extra tests/test_cksum_service tests/test_cksum_ieg tests/test_chunk_cksum tests/test_f2003 tests/pio_write_run tests/pio_write_deco2d_run tests/pio_cksum_mpinonb tests/pio_cksum_mpi_fw_ordered tests/pio_cksum_mpi_fw_at_all tests/pio_cksum_mpi_fw_at_reblock tests/pio_cksum_fpguard tests/pio_cksum_asynch tests/pio_cksum_writer tests/pio_cksum_cdf tests/test_resource_copy_mpi_run tests/test_cdf_transformation tests/test_cdf_const tables/gen_tableheaderfile util/serialrun" ac_config_files="$ac_config_files Makefile src/Makefile interfaces/Makefile app/Makefile tests/Makefile examples/Makefile cdi.settings examples/pio/Makefile src/pkgconfig/cdi.pc src/pkgconfig/cdipio.pc" @@ -30620,7 +30620,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by cdi $as_me 1.8.1, which was +This file was extended by cdi $as_me 1.8.2, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -30686,7 +30686,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -cdi config.status 1.8.1 +cdi config.status 1.8.2 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" @@ -31387,6 +31387,7 @@ do "tests/pio_cksum_cdf") CONFIG_FILES="$CONFIG_FILES tests/pio_cksum_cdf" ;; "tests/test_resource_copy_mpi_run") CONFIG_FILES="$CONFIG_FILES tests/test_resource_copy_mpi_run" ;; "tests/test_cdf_transformation") CONFIG_FILES="$CONFIG_FILES tests/test_cdf_transformation" ;; + "tests/test_cdf_const") CONFIG_FILES="$CONFIG_FILES tests/test_cdf_const" ;; "tables/gen_tableheaderfile") CONFIG_FILES="$CONFIG_FILES tables/gen_tableheaderfile" ;; "util/serialrun") CONFIG_FILES="$CONFIG_FILES util/serialrun" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; @@ -33211,6 +33212,7 @@ _LT_EOF "tests/pio_cksum_cdf":F) chmod a+x "$ac_file" ;; "tests/test_resource_copy_mpi_run":F) chmod a+x "$ac_file" ;; "tests/test_cdf_transformation":F) chmod a+x "$ac_file" ;; + "tests/test_cdf_const":F) chmod a+x "$ac_file" ;; "tables/gen_tableheaderfile":F) chmod a+x "$ac_file" ;; "util/serialrun":F) chmod a+x "$ac_file" ;; diff --git a/configure.ac b/configure.ac index 8ffba062058b6bfe48f65ab799a63d5e24b1f3fb..4b1ad308859344189d9a1bc717d2e38dfaadadf1 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ # autoconf 2.68 # libtool 2.4.2 -AC_INIT([cdi], [1.8.1], [http://mpimet.mpg.de/cdi]) +AC_INIT([cdi], [1.8.2], [http://mpimet.mpg.de/cdi]) AC_DEFINE_UNQUOTED(CDI, ["$PACKAGE_VERSION"], [CDI version]) @@ -412,6 +412,7 @@ AC_CONFIG_FILES([tests/test_cksum_grib \ tests/pio_cksum_cdf \ tests/test_resource_copy_mpi_run \ tests/test_cdf_transformation \ + tests/test_cdf_const \ tables/gen_tableheaderfile \ util/serialrun],[chmod a+x "$ac_file"]) diff --git a/doc/tex/c_quick_ref.tex b/doc/tex/c_quick_ref.tex index f84540a742de35270ba3c94c97528d939cf120b9..1cedc77297cce942ba5427211751da4517d6393a 100644 --- a/doc/tex/c_quick_ref.tex +++ b/doc/tex/c_quick_ref.tex @@ -405,6 +405,15 @@ Get the type of a Grid. Get the UUID of an unstructured grid. +\section*{\tt \htmlref{gridInqXIsc}{gridInqXIsc}} + +\begin{verbatim} + int gridInqXIsc (int gridID); +\end{verbatim} + +Find out whether X-coordinate is of type CHAR. + + \section*{\tt \htmlref{gridInqXbounds}{gridInqXbounds}} \begin{verbatim} @@ -477,6 +486,15 @@ Get one value of a X-axis. Get all values of a X-axis. +\section*{\tt \htmlref{gridInqYIsc}{gridInqYIsc}} + +\begin{verbatim} + int gridInqYIsc (int gridID); +\end{verbatim} + +Find out whether Y-coordinate is of type CHAR. + + \section*{\tt \htmlref{gridInqYbounds}{gridInqYbounds}} \begin{verbatim} diff --git a/doc/tex/f_quick_ref.tex b/doc/tex/f_quick_ref.tex index c43127e1ae6c7c1fc4194c1005ba1ac3d43177db..78386764101325a7a2c3183c7d2891395f2beb03 100644 --- a/doc/tex/f_quick_ref.tex +++ b/doc/tex/f_quick_ref.tex @@ -407,6 +407,15 @@ Get the type of a Grid. Get the UUID of an unstructured grid. +\section*{\tt \htmlref{gridInqXIsc}{gridInqXIsc}} + +\begin{verbatim} + INTEGER FUNCTION gridInqXIsc (INTEGER gridID) +\end{verbatim} + +Find out whether X-coordinate is of type CHAR. + + \section*{\tt \htmlref{gridInqXbounds}{gridInqXbounds}} \begin{verbatim} @@ -479,6 +488,15 @@ Get one value of a X-axis. Get all values of a X-axis. +\section*{\tt \htmlref{gridInqYIsc}{gridInqYIsc}} + +\begin{verbatim} + INTEGER FUNCTION gridInqYIsc (INTEGER gridID) +\end{verbatim} + +Find out whether Y-coordinate is of type CHAR. + + \section*{\tt \htmlref{gridInqYbounds}{gridInqYbounds}} \begin{verbatim} diff --git a/examples/Makefile.am b/examples/Makefile.am index c518697aa155ed52d007190c781e62f278f04dfb..a6387b5e387b39b00a69397a7e75ceaf9ea9f4b7 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,35 +2,37 @@ # EXTRA_DIST = cdi_read_f2003.f90 cdi_write_f2003.f90 # -noinst_PROGRAMS = cdi_write cdi_write_ens cdi_write_hybrid cdi_read cdi_copy +noinst_PROGRAMS = cdi_write cdi_write_ens cdi_write_hybrid cdi_read \ + cdi_copy if CREATE_ISOC noinst_PROGRAMS += cdi_read_f2003 cdi_write_f2003 endif +if ENABLE_NETCDF + noinst_PROGRAMS += cdi_write_const +endif # AM_CPPFLAGS = -I$(top_srcdir)/src AM_FCFLAGS = $(FPP_INCOPT)$(top_srcdir)/src $(FC_MOD_FLAG)../src +LDADD = $(top_builddir)/src/libcdi.la # cdi_write_SOURCES = cdi_write.c -cdi_write_LDADD = $(top_builddir)/src/libcdi.la # cdi_write_ens_SOURCES = cdi_write_ens.c -cdi_write_ens_LDADD = $(top_builddir)/src/libcdi.la +# +cdi_write_const_SOURCES = cdi_write_const.c # cdi_write_hybrid_SOURCES = cdi_write_hybrid.c -cdi_write_hybrid_LDADD = $(top_builddir)/src/libcdi.la # cdi_read_SOURCES = cdi_read.c -cdi_read_LDADD = $(top_builddir)/src/libcdi.la # cdi_copy_SOURCES = cdi_copy.c -cdi_copy_LDADD = $(top_builddir)/src/libcdi.la # cdi_read_f2003_SOURCES = cdi_read_f2003.f90 -cdi_read_f2003_LDADD = $(top_builddir)/src/libcdi.la $(top_builddir)/src/mo_cdi.o +cdi_read_f2003_LDADD = $(top_builddir)/src/mo_cdi.o $(top_builddir)/src/libcdi.la cdi_read_f2003.$(OBJEXT): $(top_builddir)/src/mo_cdi.$(FCMODEXT) # cdi_write_f2003_SOURCES = cdi_write_f2003.f90 -cdi_write_f2003_LDADD = $(top_builddir)/src/libcdi.la $(top_builddir)/src/mo_cdi.$(OBJEXT) +cdi_write_f2003_LDADD = $(top_builddir)/src/mo_cdi.$(OBJEXT) $(top_builddir)/src/libcdi.la cdi_write_f2003.$(OBJEXT): $(top_builddir)/src/mo_cdi.$(FCMODEXT) # diff --git a/examples/Makefile.in b/examples/Makefile.in index 68520694f0cfb7e63bed499546c4a2b3c9e61b53..76603af1bf6332f0aa5fdceaea5d9667cb29dcc1 100644 --- a/examples/Makefile.in +++ b/examples/Makefile.in @@ -80,8 +80,9 @@ build_triplet = @build@ host_triplet = @host@ noinst_PROGRAMS = cdi_write$(EXEEXT) cdi_write_ens$(EXEEXT) \ cdi_write_hybrid$(EXEEXT) cdi_read$(EXEEXT) cdi_copy$(EXEEXT) \ - $(am__EXEEXT_1) + $(am__EXEEXT_1) $(am__EXEEXT_2) @CREATE_ISOC_TRUE@am__append_1 = cdi_read_f2003 cdi_write_f2003 +@ENABLE_NETCDF_TRUE@am__append_2 = cdi_write_const subdir = examples DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/config/mkinstalldirs \ @@ -123,9 +124,11 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @CREATE_ISOC_TRUE@am__EXEEXT_1 = cdi_read_f2003$(EXEEXT) \ @CREATE_ISOC_TRUE@ cdi_write_f2003$(EXEEXT) +@ENABLE_NETCDF_TRUE@am__EXEEXT_2 = cdi_write_const$(EXEEXT) PROGRAMS = $(noinst_PROGRAMS) am_cdi_copy_OBJECTS = cdi_copy.$(OBJEXT) cdi_copy_OBJECTS = $(am_cdi_copy_OBJECTS) +cdi_copy_LDADD = $(LDADD) cdi_copy_DEPENDENCIES = $(top_builddir)/src/libcdi.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -136,37 +139,45 @@ cdi_copy_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(cdi_copy_LDFLAGS) $(LDFLAGS) -o $@ am_cdi_read_OBJECTS = cdi_read.$(OBJEXT) cdi_read_OBJECTS = $(am_cdi_read_OBJECTS) +cdi_read_LDADD = $(LDADD) cdi_read_DEPENDENCIES = $(top_builddir)/src/libcdi.la cdi_read_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(cdi_read_LDFLAGS) $(LDFLAGS) -o $@ am_cdi_read_f2003_OBJECTS = cdi_read_f2003.$(OBJEXT) cdi_read_f2003_OBJECTS = $(am_cdi_read_f2003_OBJECTS) -cdi_read_f2003_DEPENDENCIES = $(top_builddir)/src/libcdi.la \ - $(top_builddir)/src/mo_cdi.o +cdi_read_f2003_DEPENDENCIES = $(top_builddir)/src/mo_cdi.o \ + $(top_builddir)/src/libcdi.la cdi_read_f2003_LINK = $(LIBTOOL) $(AM_V_lt) --tag=FC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(FCLD) \ $(AM_FCFLAGS) $(FCFLAGS) $(cdi_read_f2003_LDFLAGS) $(LDFLAGS) \ -o $@ am_cdi_write_OBJECTS = cdi_write.$(OBJEXT) cdi_write_OBJECTS = $(am_cdi_write_OBJECTS) +cdi_write_LDADD = $(LDADD) cdi_write_DEPENDENCIES = $(top_builddir)/src/libcdi.la cdi_write_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(cdi_write_LDFLAGS) $(LDFLAGS) -o $@ +am_cdi_write_const_OBJECTS = cdi_write_const.$(OBJEXT) +cdi_write_const_OBJECTS = $(am_cdi_write_const_OBJECTS) +cdi_write_const_LDADD = $(LDADD) +cdi_write_const_DEPENDENCIES = $(top_builddir)/src/libcdi.la am_cdi_write_ens_OBJECTS = cdi_write_ens.$(OBJEXT) cdi_write_ens_OBJECTS = $(am_cdi_write_ens_OBJECTS) +cdi_write_ens_LDADD = $(LDADD) cdi_write_ens_DEPENDENCIES = $(top_builddir)/src/libcdi.la am_cdi_write_f2003_OBJECTS = cdi_write_f2003.$(OBJEXT) cdi_write_f2003_OBJECTS = $(am_cdi_write_f2003_OBJECTS) -cdi_write_f2003_DEPENDENCIES = $(top_builddir)/src/libcdi.la \ - $(top_builddir)/src/mo_cdi.$(OBJEXT) +cdi_write_f2003_DEPENDENCIES = $(top_builddir)/src/mo_cdi.$(OBJEXT) \ + $(top_builddir)/src/libcdi.la cdi_write_f2003_LINK = $(LIBTOOL) $(AM_V_lt) --tag=FC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(FCLD) \ $(AM_FCFLAGS) $(FCFLAGS) $(cdi_write_f2003_LDFLAGS) $(LDFLAGS) \ -o $@ am_cdi_write_hybrid_OBJECTS = cdi_write_hybrid.$(OBJEXT) cdi_write_hybrid_OBJECTS = $(am_cdi_write_hybrid_OBJECTS) +cdi_write_hybrid_LDADD = $(LDADD) cdi_write_hybrid_DEPENDENCIES = $(top_builddir)/src/libcdi.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) @@ -219,12 +230,12 @@ am__v_FCLD_0 = @echo " FCLD " $@; am__v_FCLD_1 = SOURCES = $(cdi_copy_SOURCES) $(cdi_read_SOURCES) \ $(cdi_read_f2003_SOURCES) $(cdi_write_SOURCES) \ - $(cdi_write_ens_SOURCES) $(cdi_write_f2003_SOURCES) \ - $(cdi_write_hybrid_SOURCES) + $(cdi_write_const_SOURCES) $(cdi_write_ens_SOURCES) \ + $(cdi_write_f2003_SOURCES) $(cdi_write_hybrid_SOURCES) DIST_SOURCES = $(cdi_copy_SOURCES) $(cdi_read_SOURCES) \ $(cdi_read_f2003_SOURCES) $(cdi_write_SOURCES) \ - $(cdi_write_ens_SOURCES) $(cdi_write_f2003_SOURCES) \ - $(cdi_write_hybrid_SOURCES) + $(cdi_write_const_SOURCES) $(cdi_write_ens_SOURCES) \ + $(cdi_write_f2003_SOURCES) $(cdi_write_hybrid_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -440,27 +451,25 @@ EXTRA_DIST = cdi_read_f2003.f90 cdi_write_f2003.f90 # AM_CPPFLAGS = -I$(top_srcdir)/src AM_FCFLAGS = $(FPP_INCOPT)$(top_srcdir)/src $(FC_MOD_FLAG)../src +LDADD = $(top_builddir)/src/libcdi.la # cdi_write_SOURCES = cdi_write.c -cdi_write_LDADD = $(top_builddir)/src/libcdi.la # cdi_write_ens_SOURCES = cdi_write_ens.c -cdi_write_ens_LDADD = $(top_builddir)/src/libcdi.la +# +cdi_write_const_SOURCES = cdi_write_const.c # cdi_write_hybrid_SOURCES = cdi_write_hybrid.c -cdi_write_hybrid_LDADD = $(top_builddir)/src/libcdi.la # cdi_read_SOURCES = cdi_read.c -cdi_read_LDADD = $(top_builddir)/src/libcdi.la # cdi_copy_SOURCES = cdi_copy.c -cdi_copy_LDADD = $(top_builddir)/src/libcdi.la # cdi_read_f2003_SOURCES = cdi_read_f2003.f90 -cdi_read_f2003_LDADD = $(top_builddir)/src/libcdi.la $(top_builddir)/src/mo_cdi.o +cdi_read_f2003_LDADD = $(top_builddir)/src/mo_cdi.o $(top_builddir)/src/libcdi.la # cdi_write_f2003_SOURCES = cdi_write_f2003.f90 -cdi_write_f2003_LDADD = $(top_builddir)/src/libcdi.la $(top_builddir)/src/mo_cdi.$(OBJEXT) +cdi_write_f2003_LDADD = $(top_builddir)/src/mo_cdi.$(OBJEXT) $(top_builddir)/src/libcdi.la # @ENABLE_ALL_STATIC_TRUE@cdi_write_LDFLAGS = -all-static @@ -528,6 +537,10 @@ cdi_write$(EXEEXT): $(cdi_write_OBJECTS) $(cdi_write_DEPENDENCIES) $(EXTRA_cdi_w @rm -f cdi_write$(EXEEXT) $(AM_V_CCLD)$(cdi_write_LINK) $(cdi_write_OBJECTS) $(cdi_write_LDADD) $(LIBS) +cdi_write_const$(EXEEXT): $(cdi_write_const_OBJECTS) $(cdi_write_const_DEPENDENCIES) $(EXTRA_cdi_write_const_DEPENDENCIES) + @rm -f cdi_write_const$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(cdi_write_const_OBJECTS) $(cdi_write_const_LDADD) $(LIBS) + cdi_write_ens$(EXEEXT): $(cdi_write_ens_OBJECTS) $(cdi_write_ens_DEPENDENCIES) $(EXTRA_cdi_write_ens_DEPENDENCIES) @rm -f cdi_write_ens$(EXEEXT) $(AM_V_CCLD)$(LINK) $(cdi_write_ens_OBJECTS) $(cdi_write_ens_LDADD) $(LIBS) @@ -549,6 +562,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdi_copy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdi_read.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdi_write.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdi_write_const.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdi_write_ens.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdi_write_hybrid.Po@am__quote@ diff --git a/m4/acx_options.m4 b/m4/acx_options.m4 index 44fe876f0b700fd820fe5072a5f29e6fdba02400..997cb0dfe47d4ca3be01d3d634924ae8d4817ff9 100644 --- a/m4/acx_options.m4 +++ b/m4/acx_options.m4 @@ -144,8 +144,8 @@ AS_IF([test "x$ENABLE_NC4HDF5" = "xyes"], [AC_DEFINE([HAVE_NC4HDF5_THREADSAFE],[1],[Define to 1 for NetCDF4/HDF5 threadsafe support])],,[-lhdf5])]) AS_IF([test "x$ENABLE_NC4HDF5" = "xyes"], - [AC_SEARCH_LIBS([H5get_libversion], [netcdf], - [AC_DEFINE([HAVE_H5GET_LIBVERSION],[1],[Define to 1 for H5get_libversion support])],,[-lhdf5])]) + [AC_SEARCH_LIBS([H5get_libversion], [netcdf hdf5], + [AC_DEFINE([HAVE_H5GET_LIBVERSION],[1],[Define to 1 for H5get_libversion support])],,)]) AC_SUBST([ENABLE_NETCDF]) AC_SUBST([ENABLE_NC2]) diff --git a/src/Makefile.am b/src/Makefile.am index 0bdb6c46247208c9b485f72b221b5208ba493c64..e3b8f1370692bdc7fbda378b3f60aea6cb736b9c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -75,6 +75,7 @@ libcdi_la_SOURCES = \ servicelib.c \ stream_cdf_i.c \ stream_cdf_o.c \ + stream_cdf_time.c \ stream_cdf.h \ stream_cgribex.c \ stream_cgribex.h \ diff --git a/src/Makefile.in b/src/Makefile.in index 8d724bdd6beaa406f78234f941d4262a2068d14d..5d24144402a9990aceaca0be9a91c2b11ed9f489 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -180,13 +180,13 @@ am__libcdi_la_SOURCES_DIST = basetime.c basetime.h binary.c binary.h \ namespace.c namespace.h serialize.h serialize.c \ referenceCounting.c referenceCounting.h resource_handle.c \ resource_handle.h service.h servicelib.c stream_cdf_i.c \ - stream_cdf_o.c stream_cdf.h stream_cgribex.c stream_cgribex.h \ - stream_ext.c stream_ext.h stream_grb.c stream_grb.h \ - stream_gribapi.h stream_history.c stream_ieg.c stream_ieg.h \ - cdi_int.c cdi_int.h stream_record.c stream_srv.c stream_srv.h \ - stream_var.c grb_write.c grb_read.c cdf_write.c cdf_read.c \ - cdf_lazy_grid.c cdf_lazy_grid.h subtype.c subtype.h swap.h \ - table.c table.h tablepar.h taxis.c taxis.h timebase.c \ + stream_cdf_o.c stream_cdf_time.c stream_cdf.h stream_cgribex.c \ + stream_cgribex.h stream_ext.c stream_ext.h stream_grb.c \ + stream_grb.h stream_gribapi.h stream_history.c stream_ieg.c \ + stream_ieg.h cdi_int.c cdi_int.h stream_record.c stream_srv.c \ + stream_srv.h stream_var.c grb_write.c grb_read.c cdf_write.c \ + cdf_read.c cdf_lazy_grid.c cdf_lazy_grid.h subtype.c subtype.h \ + swap.h table.c table.h tablepar.h taxis.c taxis.h timebase.c \ timebase.h tsteps.c util.c varscan.c varscan.h version.c \ vlist.c vlist.h cdi_att.c cdi_att.h vlist_var.c vlist_var.h \ zaxis.c zaxis.h stream.c stream_write.c stream_read.c swap.c \ @@ -203,15 +203,16 @@ am_libcdi_la_OBJECTS = basetime.lo binary.lo calendar.lo cdf.lo \ gaussgrid.lo gribapi.lo grid.lo ieglib.lo input_file.lo \ institution.lo model.lo namespace.lo serialize.lo \ referenceCounting.lo resource_handle.lo servicelib.lo \ - stream_cdf_i.lo stream_cdf_o.lo stream_cgribex.lo \ - stream_ext.lo stream_grb.lo stream_history.lo stream_ieg.lo \ - cdi_int.lo stream_record.lo stream_srv.lo stream_var.lo \ - grb_write.lo grb_read.lo cdf_write.lo cdf_read.lo \ - cdf_lazy_grid.lo subtype.lo table.lo taxis.lo timebase.lo \ - tsteps.lo util.lo varscan.lo version.lo vlist.lo cdi_att.lo \ - vlist_var.lo zaxis.lo stream.lo stream_write.lo stream_read.lo \ - swap.lo iterator.lo iterator_fallback.lo iterator_grib.lo \ - $(am__objects_2) $(am__objects_4) + stream_cdf_i.lo stream_cdf_o.lo stream_cdf_time.lo \ + stream_cgribex.lo stream_ext.lo stream_grb.lo \ + stream_history.lo stream_ieg.lo cdi_int.lo stream_record.lo \ + stream_srv.lo stream_var.lo grb_write.lo grb_read.lo \ + cdf_write.lo cdf_read.lo cdf_lazy_grid.lo subtype.lo table.lo \ + taxis.lo timebase.lo tsteps.lo util.lo varscan.lo version.lo \ + vlist.lo cdi_att.lo vlist_var.lo zaxis.lo stream.lo \ + stream_write.lo stream_read.lo swap.lo iterator.lo \ + iterator_fallback.lo iterator_grib.lo $(am__objects_2) \ + $(am__objects_4) libcdi_la_OBJECTS = $(am_libcdi_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -520,18 +521,19 @@ libcdi_la_SOURCES = basetime.c basetime.h binary.c binary.h calendar.c \ serialize.h serialize.c referenceCounting.c \ referenceCounting.h resource_handle.c resource_handle.h \ service.h servicelib.c stream_cdf_i.c stream_cdf_o.c \ - stream_cdf.h stream_cgribex.c stream_cgribex.h stream_ext.c \ - stream_ext.h stream_grb.c stream_grb.h stream_gribapi.h \ - stream_history.c stream_ieg.c stream_ieg.h cdi_int.c cdi_int.h \ - stream_record.c stream_srv.c stream_srv.h stream_var.c \ - grb_write.c grb_read.c cdf_write.c cdf_read.c cdf_lazy_grid.c \ - cdf_lazy_grid.h subtype.c subtype.h swap.h table.c table.h \ - tablepar.h taxis.c taxis.h timebase.c timebase.h tsteps.c \ - util.c varscan.c varscan.h version.c vlist.c vlist.h cdi_att.c \ - cdi_att.h vlist_var.c vlist_var.h zaxis.c zaxis.h stream.c \ - stream_write.c stream_read.c swap.c iterator.c iterator.h \ - iterator_fallback.c iterator_fallback.h iterator_grib.c \ - iterator_grib.h $(am__append_2) $(am__append_3) + stream_cdf_time.c stream_cdf.h stream_cgribex.c \ + stream_cgribex.h stream_ext.c stream_ext.h stream_grb.c \ + stream_grb.h stream_gribapi.h stream_history.c stream_ieg.c \ + stream_ieg.h cdi_int.c cdi_int.h stream_record.c stream_srv.c \ + stream_srv.h stream_var.c grb_write.c grb_read.c cdf_write.c \ + cdf_read.c cdf_lazy_grid.c cdf_lazy_grid.h subtype.c subtype.h \ + swap.h table.c table.h tablepar.h taxis.c taxis.h timebase.c \ + timebase.h tsteps.c util.c varscan.c varscan.h version.c \ + vlist.c vlist.h cdi_att.c cdi_att.h vlist_var.c vlist_var.h \ + zaxis.c zaxis.h stream.c stream_write.c stream_read.c swap.c \ + iterator.c iterator.h iterator_fallback.c iterator_fallback.h \ + iterator_grib.c iterator_grib.h $(am__append_2) \ + $(am__append_3) # cfortran.h is an optional part of libcdi libcdi_la_USE_FC_extra_sources = \ @@ -750,6 +752,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_cdf_i.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_cdf_o.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_cdf_time.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_cgribex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_ext.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream_grb.Plo@am__quote@ @@ -942,8 +945,8 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -@ENABLE_CDI_LIB_FALSE@uninstall-local: @ENABLE_CDI_LIB_FALSE@install-exec-local: +@ENABLE_CDI_LIB_FALSE@uninstall-local: clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ diff --git a/src/cdf_read.c b/src/cdf_read.c index ba33aad3674633772aff70d745508486c96e59d9..a81ccb75723838a1be5899f69f79afc22ccb4fbc 100644 --- a/src/cdf_read.c +++ b/src/cdf_read.c @@ -23,8 +23,8 @@ void cdfReadGridTraj(stream_t *streamptr, int gridID) int fileID = streamptr->fileID; int gridindex = vlistGridIndex(vlistID, gridID); - int lonID = streamptr->ncgrid[gridindex].xdimID; - int latID = streamptr->ncgrid[gridindex].ydimID; + int lonID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X]; + int latID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y]; int tsID = streamptr->curTsID; size_t index = (size_t)tsID; @@ -56,8 +56,8 @@ void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], s } else { - xid = streamptr->ncgrid[gridindex].xdimID; - yid = streamptr->ncgrid[gridindex].ydimID; + xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X]; + yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y]; } int zaxisindex = vlistZaxisIndex(vlistID, zaxisID); int zid = streamptr->zaxisID[zaxisindex]; @@ -369,12 +369,12 @@ void cdfInqDimIds(stream_t *streamptr, int varId, int (*outDimIds)[3]) break; case GRID_UNSTRUCTURED: - (*outDimIds)[0] = streamptr->ncgrid[gridindex].xdimID; + (*outDimIds)[0] = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X]; break; default: - (*outDimIds)[0] = streamptr->ncgrid[gridindex].xdimID; - (*outDimIds)[1] = streamptr->ncgrid[gridindex].ydimID; + (*outDimIds)[0] = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X]; + (*outDimIds)[1] = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y]; break; } diff --git a/src/cdf_util.c b/src/cdf_util.c index c0a93e7804366f4855159b86b9b3411989bdb94e..9f7ace1cebc317bd439e9b4067705869c9331abd 100644 --- a/src/cdf_util.c +++ b/src/cdf_util.c @@ -37,10 +37,8 @@ int get_timeunit(size_t len, const char *ptu) else if ( str_is_equal(ptu, "calendar_month") ) timeunit = TUNIT_MONTH; else if ( str_is_equal(ptu, "year") ) timeunit = TUNIT_YEAR; } - else if ( len == 1 ) - { - if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND; - } + else if ( len == 1 && ptu[0] == 's' ) + timeunit = TUNIT_SECOND; return timeunit; } @@ -265,6 +263,8 @@ void set_gridtype(const char *attstring, int *gridtype) *gridtype = GRID_UNSTRUCTURED; else if ( strcmp(attstring, "curvilinear") == 0 ) *gridtype = GRID_CURVILINEAR; + else if ( strcmp(attstring, "characterxy") == 0 ) + *gridtype = GRID_CHARXY; else if ( strcmp(attstring, "sinusoidal") == 0 ) ; else if ( strcmp(attstring, "laea") == 0 ) diff --git a/src/cdf_write.c b/src/cdf_write.c index 7ee19b624711dcbd1589295c41903d8acb046792..a3a3b9857a9e6a2cf04772423eff0224366fc02f 100644 --- a/src/cdf_write.c +++ b/src/cdf_write.c @@ -355,8 +355,8 @@ int cdfDefVar(stream_t *streamptr, int varID) int gridindex = nc_grid_index(streamptr, gridID); if ( gridtype != GRID_TRAJECTORY ) { - xid = streamptr->ncgrid[gridindex].xdimID; - yid = streamptr->ncgrid[gridindex].ydimID; + xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X]; + yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y]; if ( xid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, xid, &xsize); if ( yid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, yid, &ysize); } @@ -570,7 +570,7 @@ int cdfDefVar(stream_t *streamptr, int varID) } if ( gridtype != GRID_GENERIC && gridtype != GRID_LONLAT && gridtype != GRID_GAUSSIAN && - gridtype != GRID_PROJECTION && gridtype != GRID_CURVILINEAR ) + gridtype != GRID_PROJECTION && gridtype != GRID_CURVILINEAR && gridtype != GRID_CHARXY ) { size_t len = strlen(gridNamePtr(gridtype)); if ( len > 0 ) @@ -589,8 +589,8 @@ int cdfDefVar(stream_t *streamptr, int varID) } else if ( gridtype == GRID_LONLAT && xid == CDI_UNDEFID && yid == CDI_UNDEFID && gridsize == 1 ) { - int ncxvarID = streamptr->ncgrid[gridindex].xvarID; - int ncyvarID = streamptr->ncgrid[gridindex].yvarID; + int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X]; + int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y]; if ( ncyvarID != CDI_UNDEFID ) { size_t len = strlen(coordinates); @@ -607,20 +607,39 @@ int cdfDefVar(stream_t *streamptr, int varID) else if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR ) { char cellarea[CDI_MAX_NAME] = "area: "; - int ncxvarID = streamptr->ncgrid[gridindex].xvarID; - int ncyvarID = streamptr->ncgrid[gridindex].yvarID; - int ncavarID = streamptr->ncgrid[gridindex].avarID; - if ( ncyvarID != CDI_UNDEFID ) + int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X]; + int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y]; + int ncavarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_A]; + // CMOR order: coordinates = "lat lon" + if ( cdiCoordinatesLonLat ) { - size_t len = strlen(coordinates); - if ( len ) coordinates[len++] = ' '; - cdf_inq_varname(fileID, ncyvarID, coordinates+len); + if ( ncxvarID != CDI_UNDEFID ) + { + size_t len = strlen(coordinates); + if ( len ) coordinates[len++] = ' '; + cdf_inq_varname(fileID, ncxvarID, coordinates+len); + } + if ( ncyvarID != CDI_UNDEFID ) + { + size_t len = strlen(coordinates); + if ( len ) coordinates[len++] = ' '; + cdf_inq_varname(fileID, ncyvarID, coordinates+len); + } } - if ( ncxvarID != CDI_UNDEFID ) + else { - size_t len = strlen(coordinates); - if ( len ) coordinates[len++] = ' '; - cdf_inq_varname(fileID, ncxvarID, coordinates+len); + if ( ncyvarID != CDI_UNDEFID ) + { + size_t len = strlen(coordinates); + if ( len ) coordinates[len++] = ' '; + cdf_inq_varname(fileID, ncyvarID, coordinates+len); + } + if ( ncxvarID != CDI_UNDEFID ) + { + size_t len = strlen(coordinates); + if ( len ) coordinates[len++] = ' '; + cdf_inq_varname(fileID, ncxvarID, coordinates+len); + } } if ( ncavarID != CDI_UNDEFID ) @@ -646,6 +665,23 @@ int cdfDefVar(stream_t *streamptr, int varID) cdf_put_att_text(fileID, ncvarid, "axis", iax, axis); cdf_put_att_int(fileID, ncvarid, "truncation", NC_INT, 1, &gridTruncation); } + else if ( gridtype == GRID_CHARXY ) + { + if ( gridInqXIsc(gridID) ) + { + int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X]; + size_t len = strlen(coordinates); + if ( len ) coordinates[len++] = ' '; + cdf_inq_varname(fileID, ncxvarID, coordinates+len); + } + else if ( gridInqYIsc(gridID) ) + { + int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y]; + size_t len = strlen(coordinates); + if ( len ) coordinates[len++] = ' '; + cdf_inq_varname(fileID, ncyvarID, coordinates+len); + } + } size_t len = strlen(coordinates); if ( len ) cdf_put_att_text(fileID, ncvarid, "coordinates", len, coordinates); @@ -754,8 +790,8 @@ static void cdfWriteGridTraj(stream_t *streamptr, int gridID) { int gridindex = nc_grid_index(streamptr, gridID); - int lonID = streamptr->ncgrid[gridindex].xdimID; - int latID = streamptr->ncgrid[gridindex].ydimID; + int lonID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X]; + int latID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y]; double xlon = gridInqXval(gridID, 0); double xlat = gridInqYval(gridID, 0); @@ -980,8 +1016,8 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data else { int gridindex = nc_grid_index(streamptr, gridID); - xid = streamptr->ncgrid[gridindex].xdimID; - yid = streamptr->ncgrid[gridindex].ydimID; + xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X]; + yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y]; } int zaxisindex = vlistZaxisIndex(vlistID, zaxisID); @@ -1077,8 +1113,8 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype, else { int gridindex = nc_grid_index(streamptr, gridID); - xid = streamptr->ncgrid[gridindex].xdimID; - yid = streamptr->ncgrid[gridindex].ydimID; + xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X]; + yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y]; } int zaxisindex = vlistZaxisIndex(vlistID, zaxisID); @@ -1175,8 +1211,8 @@ void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp else { int gridindex = nc_grid_index(streamptr, gridID); - xid = streamptr->ncgrid[gridindex].xdimID; - yid = streamptr->ncgrid[gridindex].ydimID; + xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X]; + yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y]; } int zaxisindex = vlistZaxisIndex(vlistID, zaxisID); diff --git a/src/cdi.h b/src/cdi.h index 67a378c35ba71edb926d1dbfc1540bab425bb3fe..22c54eb66f21ad9200b39881ea0a94cf2d63a0ed 100644 --- a/src/cdi.h +++ b/src/cdi.h @@ -40,6 +40,7 @@ extern "C" { #define CDI_ELIBNAVAIL -22 // xxx library not available #define CDI_EUFSTRUCT -23 // Unsupported file structure #define CDI_EUNC4 -24 // Unsupported NetCDF4 structure +#define CDI_EDIMSIZE -25 // Invalid dimension size #define CDI_ELIMIT -99 // Internal limits exceeded /* File types */ @@ -162,6 +163,7 @@ extern "C" { #define GRID_CURVILINEAR 10 /* Curvilinear grid */ #define GRID_LCC 11 /* Lambert Conformal Conic (GRIB) */ #define GRID_PROJECTION 12 /* Projected coordinates */ +#define GRID_CHARXY 13 /* One horizontal character dimension */ #define CDI_PROJ_RLL 21 /* Rotated Latitude Longitude */ #define CDI_PROJ_LCC 22 /* Lambert Conformal Conic */ @@ -196,6 +198,7 @@ extern "C" { #define ZAXIS_SEDIMENT_BOTTOM_TW 23 /* Bottom Of Sediment Layer Penetrated By Thermal Wave */ #define ZAXIS_MIX_LAYER 24 /* Mixing Layer */ #define ZAXIS_REFERENCE 25 /* zaxis reference number */ +#define ZAXIS_CHAR 26 /* Area types */ /* SUBTYPE types */ @@ -787,12 +790,24 @@ void gridDefXvals(int gridID, const double xvals[]); /* gridInqXvals: Get all values of a X-axis */ int gridInqXvals(int gridID, double xvals[]); +/* gridInqXIsc: Find out whether X-coordinate is of type CHAR */ +int gridInqXIsc(int gridID); + +/* gridInqXCvals: Get strings from X-axis in case grid is of type GRID_CHARXY */ +int gridInqXCvals(int gridID, char *xcvals[]); + /* gridDefYvals: Define the values of a Y-axis */ void gridDefYvals(int gridID, const double yvals[]); /* gridInqYvals: Get all values of a Y-axis */ int gridInqYvals(int gridID, double yvals[]); +/* gridInqYIsc: Find out whether Y-coordinate is of type CHAR */ +int gridInqYIsc(int gridID); + +/* gridInqYCvals: Get strings from Y-axis in case grid is of type GRID_CHARXY */ +int gridInqYCvals(int gridID, char *ycvals[]); + /* CDI grid string key values */ #define CDI_KEY_XNAME 901 // X-axis name #define CDI_KEY_XDIMNAME 902 // X-axis dimension name @@ -995,6 +1010,9 @@ void zaxisPrint(int zaxisID); /* zaxisDefLevels: Define the levels of a Z-axis */ void zaxisDefLevels(int zaxisID, const double levels[]); +/* zaxisDefCvals: Define area types of a Z-axis */ +void zaxisDefCvals(int zaxisID, const char *cvals[]); + /* zaxisInqLevels: Get all levels of a Z-axis */ int zaxisInqLevels(int zaxisID, double levels[]); diff --git a/src/cdi.inc b/src/cdi.inc index 8be02f8d6909863013733aebd4e5b31068d6f6cf..43f9758e15198ca6e7ee10fd8d59871f2d2b5d3c 100644 --- a/src/cdi.inc +++ b/src/cdi.inc @@ -4,7 +4,7 @@ ! ! Author: ! ------- -! Uwe Schulzweida, MPI-MET, Hamburg, April 2017 +! Uwe Schulzweida, MPI-MET, Hamburg, May 2017 ! INTEGER CDI_MAX_NAME @@ -47,6 +47,8 @@ PARAMETER (CDI_EUFSTRUCT = -23) INTEGER CDI_EUNC4 PARAMETER (CDI_EUNC4 = -24) + INTEGER CDI_EDIMSIZE + PARAMETER (CDI_EDIMSIZE = -25) INTEGER CDI_ELIMIT PARAMETER (CDI_ELIMIT = -99) ! @@ -269,6 +271,8 @@ PARAMETER (GRID_LCC = 11) INTEGER GRID_PROJECTION PARAMETER (GRID_PROJECTION = 12) + INTEGER GRID_CHARXY + PARAMETER (GRID_CHARXY = 13) INTEGER CDI_PROJ_RLL PARAMETER (CDI_PROJ_RLL = 21) INTEGER CDI_PROJ_LCC @@ -332,6 +336,8 @@ PARAMETER (ZAXIS_MIX_LAYER = 24) INTEGER ZAXIS_REFERENCE PARAMETER (ZAXIS_REFERENCE = 25) + INTEGER ZAXIS_CHAR + PARAMETER (ZAXIS_CHAR = 26) ! ! SUBTYPE types ! @@ -1576,6 +1582,10 @@ ! DOUBLEPRECISION xvals(*)) EXTERNAL gridInqXvals + INTEGER gridInqXIsc +! (INTEGER gridID) + EXTERNAL gridInqXIsc + ! gridDefYvals ! (INTEGER gridID, ! DOUBLEPRECISION yvals(*)) @@ -1586,6 +1596,10 @@ ! DOUBLEPRECISION yvals(*)) EXTERNAL gridInqYvals + INTEGER gridInqYIsc +! (INTEGER gridID) + EXTERNAL gridInqYIsc + ! ! CDI grid string key values ! diff --git a/src/cdiFortran.c b/src/cdiFortran.c index de7943ec468bd9e5e97f84a32b5692516ad14898..0308b0f1edff9a5d25e665142fe3d113941d782c 100644 --- a/src/cdiFortran.c +++ b/src/cdiFortran.c @@ -338,8 +338,10 @@ FCALLSCSUB2 (gridDefNP, GRIDDEFNP, griddefnp, INT, INT) FCALLSCFUN1 (INT, gridInqNP, GRIDINQNP, gridinqnp, INT) FCALLSCSUB2 (gridDefXvals, GRIDDEFXVALS, griddefxvals, INT, DOUBLEV) FCALLSCFUN2 (INT, gridInqXvals, GRIDINQXVALS, gridinqxvals, INT, DOUBLEV) +FCALLSCFUN1 (INT, gridInqXIsc, GRIDINQXISC, gridinqxisc, INT) FCALLSCSUB2 (gridDefYvals, GRIDDEFYVALS, griddefyvals, INT, DOUBLEV) FCALLSCFUN2 (INT, gridInqYvals, GRIDINQYVALS, gridinqyvals, INT, DOUBLEV) +FCALLSCFUN1 (INT, gridInqYIsc, GRIDINQYISC, gridinqyisc, INT) /* CDI grid string key values */ diff --git a/src/cdi_error.c b/src/cdi_error.c index d0fd6037fd24f04b4768c0405dd9d80769ea25f9..786e1ba628f0dab56b08518e4ba7702c5013940a 100644 --- a/src/cdi_error.c +++ b/src/cdi_error.c @@ -14,6 +14,7 @@ const char *cdiStringError(int cdiErrno) static const char _ELIBNAVAIL[] = "Unsupported file type (library support not compiled in)"; static const char _EUFSTRUCT[] = "Unsupported file structure"; static const char _EUNC4[] = "Unsupported NetCDF4 structure"; + static const char _EDIMSIZE[] = "Invalid dimension size"; static const char _ELIMIT[] = "Internal limits exceeded"; switch (cdiErrno) { @@ -27,6 +28,7 @@ const char *cdiStringError(int cdiErrno) case CDI_ELIBNAVAIL: return _ELIBNAVAIL; case CDI_EUFSTRUCT: return _EUFSTRUCT; case CDI_EUNC4: return _EUNC4; + case CDI_EDIMSIZE: return _EDIMSIZE; case CDI_ELIMIT: return _ELIMIT; } diff --git a/src/cdi_int.c b/src/cdi_int.c index db3b0922c0d712804f1c741f51d478a0644e2774..0bc2ee398453010a922888836980d599dcd75f1f 100644 --- a/src/cdi_int.c +++ b/src/cdi_int.c @@ -33,6 +33,7 @@ int cdiChunkType = CDI_CHUNK_GRID; int cdiSplitLtype105 = CDI_UNDEFID; int cdiIgnoreAttCoordinates = FALSE; +int cdiCoordinatesLonLat = FALSE; int cdiIgnoreValidRange = FALSE; int cdiSkipRecords = 0; int cdiConvention = CDI_CONVENTION_ECHAM; @@ -371,6 +372,9 @@ void cdiInitialize(void) envstr = getenv("IGNORE_ATT_COORDINATES"); if ( envstr ) cdiIgnoreAttCoordinates = atoi(envstr); + envstr = getenv("CDI_COORDINATES_LONLAT"); + if ( envstr ) cdiCoordinatesLonLat = atoi(envstr); + envstr = getenv("IGNORE_VALID_RANGE"); if ( envstr ) cdiIgnoreValidRange = atoi(envstr); diff --git a/src/cdi_int.h b/src/cdi_int.h index 728487fe1fe1c5f2954ae727787c3baaa71ef7e9..3b77c5dace86f5c9702931f6d8de2e0584ac1f1a 100644 --- a/src/cdi_int.h +++ b/src/cdi_int.h @@ -217,13 +217,17 @@ typedef struct { VCT; #ifdef HAVE_LIBNETCDF +enum { + CDF_DIMID_X, + CDF_DIMID_Y, + CDF_VARID_X, + CDF_VARID_Y, + CDF_VARID_A, + CDF_SIZE_ncIDs, +}; typedef struct { int gridID; - int xdimID; - int ydimID; - int xvarID; - int yvarID; - int avarID; + int ncIDs[CDF_SIZE_ncIDs]; } ncgrid_t; #endif @@ -330,6 +334,7 @@ extern int cdiSortName; extern int cdiSortParam; extern int cdiHaveMissval; extern int cdiIgnoreAttCoordinates; +extern int cdiCoordinatesLonLat; extern int cdiIgnoreValidRange; extern int cdiSkipRecords; extern int cdiConvention; diff --git a/src/cdipio.inc b/src/cdipio.inc index f44a62c3411cb1d47cd480cc65d934ff0466683b..75005982bdb3832771d7df9156c424716b65739d 100644 --- a/src/cdipio.inc +++ b/src/cdipio.inc @@ -1,10 +1,10 @@ ! This file was automatically generated, don't edit! ! -! Fortran interface for CDI library version 1.8.0 +! Fortran interface for CDI library version 1.8.1 ! ! Author: ! ------- -! Uwe Schulzweida, MPI-MET, Hamburg, March 2017 +! Uwe Schulzweida, MPI-MET, Hamburg, April 2017 ! ! diff --git a/src/gribapi_utilities.c b/src/gribapi_utilities.c index 5619f4d4a0cc04be975aeb5964b3acbf4cf00319..b333723d877c3570009b0c296c639e6ce98b9018 100644 --- a/src/gribapi_utilities.c +++ b/src/gribapi_utilities.c @@ -349,6 +349,21 @@ int gribapiTimeIsFC(grib_handle *gh) return sigofrtime != 3; } +struct cdiGribAPI_ts_str_map_elem cdiGribAPI_ts_str_map[] = { + [TSTEP_INSTANT] = { 0, "instant" }, + [TSTEP_AVG] = { 8, "avg" }, + [TSTEP_ACCUM] = { 8, "accum" }, + [TSTEP_MAX] = { 8, "max" }, + [TSTEP_MIN] = { 8, "min" }, + [TSTEP_DIFF] = { 8, "diff" }, + [TSTEP_RMS] = { 8, "rms" }, + [TSTEP_SD] = { 8, "sd" }, + [TSTEP_COV] = { 8, "cov" }, + [TSTEP_RATIO] = { 8, "ratio" }, + { 0, "" } +}; + + //Fetches the value of the "stepType" key and converts it into a constant in the TSTEP_* range. int gribapiGetTsteptype(grib_handle *gh) { @@ -364,22 +379,18 @@ int gribapiGetTsteptype(grib_handle *gh) status = grib_get_string(gh, "stepType", stepType, &len); if ( status == 0 && len > 1 && len < 256 ) { - if ( strncmp("instant", stepType, len) == 0 ) tsteptype = TSTEP_INSTANT; - else if ( strncmp("avg", stepType, len) == 0 ) tsteptype = TSTEP_AVG; - else if ( strncmp("accum", stepType, len) == 0 ) tsteptype = TSTEP_ACCUM; - else if ( strncmp("max", stepType, len) == 0 ) tsteptype = TSTEP_MAX; - else if ( strncmp("min", stepType, len) == 0 ) tsteptype = TSTEP_MIN; - else if ( strncmp("diff", stepType, len) == 0 ) tsteptype = TSTEP_DIFF; - else if ( strncmp("rms", stepType, len) == 0 ) tsteptype = TSTEP_RMS; - else if ( strncmp("sd", stepType, len) == 0 ) tsteptype = TSTEP_SD; - else if ( strncmp("cov", stepType, len) == 0 ) tsteptype = TSTEP_COV; - else if ( strncmp("ratio", stepType, len) == 0 ) tsteptype = TSTEP_RATIO; - else if ( lprint ) + for (int i = TSTEP_INSTANT; cdiGribAPI_ts_str_map[i].sname[0]; ++i) + if ( strncmp(cdiGribAPI_ts_str_map[i].sname, stepType, len) == 0 ) + { + tsteptype = i; + goto tsteptypeFound; + } + + if ( lprint ) { Message("Time stepType %s unsupported, set to instant!", stepType); lprint = false; } - // printf("stepType: %s %ld %d\n", stepType, len, tsteptype); } #ifdef HIRLAM_EXTENSIONS @@ -425,7 +436,7 @@ int gribapiGetTsteptype(grib_handle *gh) } #endif // HIRLAM_EXTENSIONS } - + tsteptypeFound: return tsteptype; } diff --git a/src/gribapi_utilities.h b/src/gribapi_utilities.h index 2495f8315f6480ca8ee6548e0bd30c47145013e6..82021f5cc2ed6bbe05297800255ef1a2cd16c72c 100644 --- a/src/gribapi_utilities.h +++ b/src/gribapi_utilities.h @@ -38,6 +38,11 @@ void gribapiSetDataTimeRangeIndicator(grib_handle *gh, int timeRangeIndicator); void gribapiGetDataTimeRangeIndicator(grib_handle *gh, int *timeRangeIndicator); #endif // #ifdef HIRLAM_EXTENSIONS +extern struct cdiGribAPI_ts_str_map_elem { + long productionTemplate; + const char sname[8]; +} cdiGribAPI_ts_str_map[]; + #endif #endif diff --git a/src/grid.c b/src/grid.c index c2b77ecf42570685f0b13c44f65c2c6301d5fc8d..82b77d1bf147d6bcd4053a19c92e54e695e95e19 100644 --- a/src/grid.c +++ b/src/grid.c @@ -40,6 +40,7 @@ static const char Grids[][17] = { /* 10 */ "curvilinear", /* 11 */ "lcc", /* 12 */ "projection", + /* 13 */ "characterXY", }; /* must match table below */ @@ -47,6 +48,7 @@ enum xystdname_idx { grid_xystdname_grid_latlon, grid_xystdname_latlon, grid_xystdname_projection, + grid_xystdname_char, }; static const char xystdname_tab[][2][24] = { [grid_xystdname_grid_latlon] = { "grid_longitude", @@ -55,7 +57,8 @@ static const char xystdname_tab[][2][24] = { "latitude" }, [grid_xystdname_projection] = { "projection_x_coordinate", "projection_y_coordinate" }, - + [grid_xystdname_char] = { "region", + "region" }, }; @@ -119,7 +122,11 @@ void grid_init(grid_t *gridptr) gridptr->mask = NULL; gridptr->mask_gme = NULL; gridptr->x.vals = NULL; + gridptr->x.cvals = NULL; + gridptr->x.clength = 0; gridptr->y.vals = NULL; + gridptr->y.cvals = NULL; + gridptr->y.clength = 0; gridptr->x.bounds = NULL; gridptr->y.bounds = NULL; gridptr->area = NULL; @@ -191,6 +198,7 @@ void grid_free_components(grid_t *gridptr) { void *p2free[] = { gridptr->mask, gridptr->mask_gme, gridptr->x.vals, gridptr->y.vals, + gridptr->x.cvals, gridptr->y.cvals, gridptr->x.bounds, gridptr->y.bounds, gridptr->rowlon, gridptr->area, gridptr->reference, gridptr->name}; @@ -321,6 +329,13 @@ void cdiGridTypeInit(grid_t *gridptr, int gridtype, int size) break; } + case GRID_CHARXY: + { + if ( gridptr->x.cvals ) + gridptr->x.stdname = xystdname_tab[grid_xystdname_char][0]; + if ( gridptr->y.cvals ) + gridptr->y.stdname = xystdname_tab[grid_xystdname_char][0]; + } case GRID_GENERIC: case GRID_PROJECTION: { @@ -1500,7 +1515,6 @@ void gridDefMaskGME(int gridID, const int *mask) gridMark4Update(gridID); } - static int gridInqXValsSerial(grid_t *gridptr, double *xvals) { @@ -1529,6 +1543,37 @@ int gridInqXValsSerial(grid_t *gridptr, double *xvals) return (int)size; } +static +int gridInqXCvalsSerial(grid_t *gridptr, char **xcvals) +{ + if ( gridptr->type != GRID_CHARXY ) + Error("Function only valid for grid type 'GRID_CHARXY'."); + + int size = gridptr->x.size; + int maxclength = 0; + + const char **gridptr_xcvals = gridptr->vtable->inqXCvalsPtr(gridptr); + if ( gridptr_xcvals && size && xcvals ) + { + maxclength = gridptr->x.clength; + for ( int i = 0; i < size; i++ ) + memcpy(xcvals[i], gridptr_xcvals[i], (size_t)maxclength*sizeof(char)); + } + + return maxclength; +} + +static +int gridInqXIscSerial(grid_t *gridptr) +{ + int clen = gridptr->x.clength; + /* + if ( gridptr->type != GRID_CHARXY ) + Error("Axis type is 'char' but grid is not type 'GRID_CHARXY'."); + */ + return clen; +} + /* @Function gridInqXvals @Title Get all values of a X-axis @@ -1556,6 +1601,19 @@ int gridInqXvals(int gridID, double *xvals) } +int gridInqXCvals(int gridID, char **xcvals) +{ + grid_t *gridptr = grid_to_pointer(gridID); + return gridptr->vtable->inqXCvals(gridptr, xcvals); +} + + +int gridInqXIsc(int gridID) +{ + grid_t *gridptr = grid_to_pointer(gridID); + return gridptr->vtable->inqXIsc(gridptr); +} + static void gridDefXValsSerial(grid_t *gridptr, const double *xvals) { @@ -1579,6 +1637,37 @@ void gridDefXValsSerial(grid_t *gridptr, const double *xvals) memcpy(gridptr->x.vals, xvals, (size_t)size * sizeof (double)); } +static +int gridInqYCvalsSerial(grid_t *gridptr, char **ycvals) +{ + if ( gridptr->type != GRID_CHARXY ) + Error("Function only valid for grid type 'GRID_CHARXY'."); + + int size = gridptr->y.size; + int maxclength = 0; + + const char **gridptr_ycvals = gridptr->vtable->inqYCvalsPtr(gridptr); + if ( gridptr_ycvals && size && ycvals ) + { + maxclength = gridptr->y.clength; + for ( int i = 0; i < size; i++ ) + memcpy(ycvals[i], gridptr_ycvals[i], (size_t)maxclength*sizeof(char)); + } + + return maxclength; +} + +static +int gridInqYIscSerial(grid_t *gridptr) +{ + int clen = gridptr->y.clength; + /* + if ( gridptr->type != GRID_CHARXY ) + Error("Axis type is 'char' but grid is not type 'GRID_CHARXY'."); + */ + return clen; +} + /* @Function gridDefXvals @Title Define the values of a X-axis @@ -1650,6 +1739,20 @@ int gridInqYvals(int gridID, double *yvals) return gridptr->vtable->inqYVals(gridptr, yvals); } + +int gridInqYCvals(int gridID, char **ycvals) +{ + grid_t *gridptr = grid_to_pointer(gridID); + return gridptr->vtable->inqYCvals(gridptr, ycvals); +} + + +int gridInqYIsc(int gridID) +{ + grid_t *gridptr = grid_to_pointer(gridID); + return gridptr->vtable->inqYIsc(gridptr); +} + static void gridDefYValsSerial(grid_t *gridptr, const double *yvals) { @@ -2468,6 +2571,7 @@ void gridComplete(grid_t *grid) case GRID_CURVILINEAR: case GRID_GENERIC: case GRID_PROJECTION: + case GRID_CHARXY: { if ( grid->x.size > 0 ) gridDefXsize(gridID, grid->x.size); if ( grid->y.size > 0 ) gridDefYsize(gridID, grid->y.size); @@ -3267,6 +3371,8 @@ void gridPrintKernel(int gridID, int opt, FILE *fp) char attstr[CDI_MAX_NAME]; char attstr2[CDI_MAX_NAME]; unsigned char uuidOfHGrid[CDI_UUID_SIZE]; + const char **xcvals = gridInqXCvalsPtr(gridID); + const char **ycvals = gridInqYCvalsPtr(gridID); size_t nxvals = (size_t) gridInqXvals(gridID, NULL); size_t nyvals = (size_t) gridInqYvals(gridID, NULL); size_t nxbounds = (size_t) gridInqXbounds(gridID, NULL); @@ -3276,6 +3382,8 @@ void gridPrintKernel(int gridID, int opt, FILE *fp) int gridsize = gridInqSize(gridID); int xsize = gridInqXsize(gridID); int ysize = gridInqYsize(gridID); + int xstrlen = gridInqXIsc(gridID); + int ystrlen = gridInqYIsc(gridID); int nvertex = gridInqNvertex(gridID); int prec = gridInqPrec(gridID); @@ -3291,8 +3399,9 @@ void gridPrintKernel(int gridID, int opt, FILE *fp) if ( ysize > 0 ) fprintf(fp, "ysize = %d\n", ysize); } - if ( nxvals > 0 ) + if ( nxvals > 0 || xcvals ) { + if ( xstrlen ) fprintf(fp, "xstringlen= %d\n", xstrlen); attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, attstr); if ( attstr[0] ) fprintf(fp, "xname = %s\n", attstr); attstr2[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, attstr2); @@ -3303,8 +3412,9 @@ void gridPrintKernel(int gridID, int opt, FILE *fp) if ( attstr[0] ) fprintf(fp, "xunits = %s\n", attstr); } - if ( nyvals > 0 ) + if ( nyvals > 0 || ycvals ) { + if ( ystrlen ) fprintf(fp, "ystringlen= %d\n", ystrlen); attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, attstr); if ( attstr[0] ) fprintf(fp, "yname = %s\n", attstr); attstr2[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_YDIMNAME, CDI_MAX_NAME, attstr2); @@ -3332,6 +3442,7 @@ void gridPrintKernel(int gridID, int opt, FILE *fp) case GRID_PROJECTION: case GRID_CURVILINEAR: case GRID_UNSTRUCTURED: + case GRID_CHARXY: { if ( type == GRID_GAUSSIAN || type == GRID_GAUSSIAN_REDUCED ) fprintf(fp, "np = %d\n", gridInqNP(gridID)); @@ -3402,6 +3513,17 @@ void gridPrintKernel(int gridID, int opt, FILE *fp) } } + if ( xcvals ) + { + attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, attstr); + if ( attstr[0] ) + fprintf(fp, "x%ss = %.*s\n", attstr, xstrlen, xcvals[0]); + else + fprintf(fp, "xstrings = %.*s\n", xstrlen, xcvals[0]); + for ( int i = 1; i < xsize; i++ ) + fprintf(fp, " = %.*s\n", xstrlen, xcvals[i]); + } + if ( nxbounds ) { double *xbounds = (double*) Malloc(nxbounds*sizeof(double)); @@ -3437,6 +3559,17 @@ void gridPrintKernel(int gridID, int opt, FILE *fp) } } + if ( ycvals ) + { + attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, attstr); + if ( attstr[0] ) + fprintf(fp, "x%ss = %.*s\n", attstr, ystrlen, ycvals[0]); + else + fprintf(fp, "ystrings = %.*s\n", ystrlen, ycvals[0]); + for ( int i = 1; i < ysize; i++ ) + fprintf(fp, " = %.*s\n", ystrlen, ycvals[i]); + } + if ( nybounds ) { double *ybounds = (double*) Malloc(nybounds*sizeof(double)); @@ -3570,6 +3703,12 @@ static const double *gridInqXValsPtrSerial(grid_t *gridptr) return gridptr->x.vals; } +static const char **gridInqXCvalsPtrSerial(grid_t *gridptr) +{ + return (const char **) gridptr->x.cvals; +} + + const double *gridInqXvalsPtr(int gridID) { grid_t *gridptr = grid_to_pointer(gridID); @@ -3577,17 +3716,34 @@ const double *gridInqXvalsPtr(int gridID) } +const char **gridInqXCvalsPtr(int gridID) +{ + grid_t *gridptr = grid_to_pointer(gridID); + return gridptr->vtable->inqXCvalsPtr(gridptr); +} + static const double *gridInqYValsPtrSerial(grid_t *gridptr) { return gridptr->y.vals; } +static const char **gridInqYCvalsPtrSerial(grid_t *gridptr) +{ + return (const char **) gridptr->y.cvals; +} + const double *gridInqYvalsPtr(int gridID) { grid_t *gridptr = grid_to_pointer(gridID); return gridptr->vtable->inqYValsPtr(gridptr); } +const char **gridInqYCvalsPtr(int gridID) +{ + grid_t *gridptr = grid_to_pointer(gridID); + return gridptr->vtable->inqYCvalsPtr(gridptr); +} + /* @Function gridDefParamLCC @Title Define the parameter of a Lambert Conformal Conic grid @@ -3615,11 +3771,12 @@ The function @func{gridDefParamLCC} defines the parameter of a Lambert Conformal void gridDefParamLCC(int gridID, double missval, double lon_0, double lat_0, double lat_1, double lat_2, double a, double rf, double xval_0, double yval_0, double x_0, double y_0) { + (void)lat_0; cdiGridDefKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, "Lambert_Conformal"); const char *mapname = "lambert_conformal_conic"; cdiGridDefKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapname); - cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", strlen(mapname), mapname); + cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", (int)(strlen(mapname)), mapname); int nlats = 0; double lats[2]; lats[nlats++] = lat_1; @@ -3717,7 +3874,7 @@ int gridInqParamLCC(int gridID, double missval, double *lon_0, double *lat_0, do } -int gridVerifyGribParamLCC(int gridID, double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2, +int gridVerifyGribParamLCC(double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2, double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0) { static bool lwarn = true; @@ -4729,9 +4886,15 @@ const struct gridVirtTable cdiGridVtable .inqXVal = gridInqXValSerial, .inqYVal = gridInqYValSerial, .inqXVals = gridInqXValsSerial, + .inqXCvals = gridInqXCvalsSerial, + .inqXIsc = gridInqXIscSerial, .inqYVals = gridInqYValsSerial, + .inqYCvals = gridInqYCvalsSerial, + .inqYIsc = gridInqYIscSerial, .inqXValsPtr = gridInqXValsPtrSerial, .inqYValsPtr = gridInqYValsPtrSerial, + .inqXCvalsPtr = gridInqXCvalsPtrSerial, + .inqYCvalsPtr = gridInqYCvalsPtrSerial, .compareXYFull = compareXYvals, .compareXYAO = compareXYvals2, .inqArea = gridInqAreaSerial, diff --git a/src/grid.h b/src/grid.h index d301ab9254a70c9ce1f2da45bb8ebb7134bf3318..40da2ecba47377d730f9a9c714983f025e340e05 100644 --- a/src/grid.h +++ b/src/grid.h @@ -30,9 +30,15 @@ struct gridVirtTable double (*inqXVal)(grid_t *gridptr, int index); double (*inqYVal)(grid_t *gridptr, int index); int (*inqXVals)(grid_t *gridptr, double *xvals); + int (*inqXCvals)(grid_t *gridptr, char **xcvals); + int (*inqXIsc)(grid_t *gridptr); int (*inqYVals)(grid_t *gridptr, double *yvals); + int (*inqYCvals)(grid_t *gridptr, char **ycvals); + int (*inqYIsc)(grid_t *gridptr); const double *(*inqXValsPtr)(grid_t *gridptr); + const char **(*inqXCvalsPtr)(grid_t *gridptr); const double *(*inqYValsPtr)(grid_t *gridptr); + const char **(*inqYCvalsPtr)(grid_t *gridptr); /* return if for both grids, all xval and all yval are equal */ bool (*compareXYFull)(grid_t *gridRef, grid_t *gridTest); /* return if for both grids, x[0], y[0], x[size-1] and y[size-1] are @@ -59,6 +65,8 @@ struct gridaxis_t { short flag; // 0: undefined 1:vals 2:first+inc double first, last, inc; double *vals; + int clength; + char **cvals; double *bounds; }; @@ -126,6 +134,9 @@ void gridVerifyProj(int gridID); const double *gridInqXvalsPtr(int gridID); const double *gridInqYvalsPtr(int gridID); +const char **gridInqXCvalsPtr(int gridID); +const char **gridInqYCvalsPtr(int gridID); + const double *gridInqXboundsPtr(int gridID); const double *gridInqYboundsPtr(int gridID); const double *gridInqAreaPtr(int gridID); @@ -151,7 +162,7 @@ struct addIfNewRes struct addIfNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode); -int gridVerifyGribParamLCC(int gridID, double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2, +int gridVerifyGribParamLCC(double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2, double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0); #endif diff --git a/src/make_cdilib b/src/make_cdilib index a936a802cc01df1f7be8ff1989811ee2e045c252..1a9deae7608a321a4fbb112d1de047f3bbe9df84 100755 --- a/src/make_cdilib +++ b/src/make_cdilib @@ -127,6 +127,7 @@ files="basetime.c \ stream_read.c \ stream_cdf_i.c \ stream_cdf_o.c \ + stream_cdf_time.c \ stream_cgribex.c \ stream_ext.c \ stream_grb.c \ diff --git a/src/mo_cdi.f90 b/src/mo_cdi.f90 index 8e7757537a0d326acc85d7e6717e1a19dcccd89f..b6f4057281ec467012e1b4177ebffdad17d03400 100644 --- a/src/mo_cdi.f90 +++ b/src/mo_cdi.f90 @@ -2102,37 +2102,43 @@ module mo_cdi integer(c_int), intent(inout) :: ni3_dummy end subroutine gridInqParamGME - subroutine gridDefParamLCC(gridID_dummy, originLon_dummy, originLat_dummy,& - & lonParY_dummy, lat1_dummy, lat2_dummy, xinc_dummy, yinc_dummy,& - & projflag_dummy, scanflag_dummy) bind(c, name = 'gridDefParamLCC') + subroutine gridDefParamLCC(gridID_dummy, missval_dummy, lon_0_dummy,& + & lat_0_dummy, lat_1_dummy, lat_2_dummy, a_dummy, rf_dummy, xval_0_dummy,& + & yval_0_dummy, x_0_dummy, y_0_dummy) bind(c, name = 'gridDefParamLCC') import c_double, c_int integer(c_int), value :: gridID_dummy - real(c_double), value :: originLon_dummy - real(c_double), value :: originLat_dummy - real(c_double), value :: lonParY_dummy - real(c_double), value :: lat1_dummy - real(c_double), value :: lat2_dummy - real(c_double), value :: xinc_dummy - real(c_double), value :: yinc_dummy - integer(c_int), value :: projflag_dummy - integer(c_int), value :: scanflag_dummy + real(c_double), value :: missval_dummy + real(c_double), value :: lon_0_dummy + real(c_double), value :: lat_0_dummy + real(c_double), value :: lat_1_dummy + real(c_double), value :: lat_2_dummy + real(c_double), value :: a_dummy + real(c_double), value :: rf_dummy + real(c_double), value :: xval_0_dummy + real(c_double), value :: yval_0_dummy + real(c_double), value :: x_0_dummy + real(c_double), value :: y_0_dummy end subroutine gridDefParamLCC - subroutine gridInqParamLCC(gridID_dummy, originLon_dummy, originLat_dummy,& - & lonParY_dummy, lat1_dummy, lat2_dummy, xinc_dummy, yinc_dummy,& - & projflag_dummy, scanflag_dummy) bind(c, name = 'gridInqParamLCC') + function gridInqParamLCC(gridID_dummy, missval_dummy, lon_0_dummy,& + & lat_0_dummy, lat_1_dummy, lat_2_dummy, a_dummy, rf_dummy, xval_0_dummy,& + & yval_0_dummy, x_0_dummy, y_0_dummy) bind(c, name = 'gridInqParamLCC')& + & result(f_result) import c_double, c_int integer(c_int), value :: gridID_dummy - real(c_double), intent(inout) :: originLon_dummy - real(c_double), intent(inout) :: originLat_dummy - real(c_double), intent(inout) :: lonParY_dummy - real(c_double), intent(inout) :: lat1_dummy - real(c_double), intent(inout) :: lat2_dummy - real(c_double), intent(inout) :: xinc_dummy - real(c_double), intent(inout) :: yinc_dummy - integer(c_int), intent(inout) :: projflag_dummy - integer(c_int), intent(inout) :: scanflag_dummy - end subroutine gridInqParamLCC + real(c_double), value :: missval_dummy + real(c_double), intent(inout) :: lon_0_dummy + real(c_double), intent(inout) :: lat_0_dummy + real(c_double), intent(inout) :: lat_1_dummy + real(c_double), intent(inout) :: lat_2_dummy + real(c_double), intent(inout) :: a_dummy + real(c_double), intent(inout) :: rf_dummy + real(c_double), intent(inout) :: xval_0_dummy + real(c_double), intent(inout) :: yval_0_dummy + real(c_double), intent(inout) :: x_0_dummy + real(c_double), intent(inout) :: y_0_dummy + integer(c_int) :: f_result + end function gridInqParamLCC subroutine gridDefArea(gridID_dummy, area_dummy) bind(c, name =& & 'gridDefArea') diff --git a/src/stream.c b/src/stream.c index b4020ca719c9e075262bda0c38115dd04c05f276..49e84111aabba0b0c84dd65957781b84935311de 100644 --- a/src/stream.c +++ b/src/stream.c @@ -892,11 +892,8 @@ void streamDefaultValue ( stream_t * streamptr ) for ( int i = 0; i < MAX_GRIDS_PS; i++ ) { streamptr->ncgrid[i].gridID = CDI_UNDEFID; - streamptr->ncgrid[i].xdimID = CDI_UNDEFID; - streamptr->ncgrid[i].ydimID = CDI_UNDEFID; - streamptr->ncgrid[i].xvarID = CDI_UNDEFID; - streamptr->ncgrid[i].yvarID = CDI_UNDEFID; - streamptr->ncgrid[i].avarID = CDI_UNDEFID; + for (size_t j = 0; j < CDF_SIZE_ncIDs; ++j) + streamptr->ncgrid[i].ncIDs[j] = CDI_UNDEFID; } streamptr->vct.ilev = 0; @@ -1607,6 +1604,9 @@ void cdiStreamSetupVlist_(stream_t *streamptr, int vlistID) case CDI_FILETYPE_NC4: case CDI_FILETYPE_NC4C: { + /* calls cdfDefVars in serial mode but + * cdiPioClientStreamNOP (i.e. nothing) on client ranks + * and cdiPioServerCdfDefVars on server ranks in parallel mode*/ void (*myCdfDefVars)(stream_t *streamptr) = (void (*)(stream_t *)) namespaceSwitchGet(NSSWITCH_CDF_STREAM_SETUP).func; myCdfDefVars(streamptr); diff --git a/src/stream_cdf_i.c b/src/stream_cdf_i.c index 1421164115ecc2fe5153d22d7a5e447c5f513bdb..8e28e92280a7f7fb0e7e9c5eea0c31ae73758d1a 100644 --- a/src/stream_cdf_i.c +++ b/src/stream_cdf_i.c @@ -45,6 +45,7 @@ typedef struct { bool ignore; bool isx; bool isy; + bool isc; bool islon; bool islat; bool islev; @@ -68,6 +69,7 @@ typedef struct { int xvarid; int yvarid; int zvarid; + int cvarids[MAX_COORDVARS]; int tvarid; int psvarid; int p0varid; @@ -183,17 +185,11 @@ int scanTimeUnit(const char *unitstr) static void setForecastTime(const char *timestr, taxis_t *taxis) { - (*taxis).fdate = 0; - (*taxis).ftime = 0; - - int len = (int) strlen(timestr); - if ( len == 0 ) return; - - int fdate = 0, ftime = 0; - scanTimeString(timestr, &fdate, &ftime); - - (*taxis).fdate = fdate; - (*taxis).ftime = ftime; + size_t len = strlen(timestr); + if ( len != 0 ) + scanTimeString(timestr, &taxis->fdate, &taxis->ftime); + else + taxis->fdate = taxis->ftime = 0; } static @@ -216,7 +212,7 @@ int setBaseTime(const char *timeunits, taxis_t *taxis) } size_t pos = 0; - while ( ! isspace(tu[pos]) && tu[pos] != 0 ) ++pos; + while ( pos < len && !isspace(tu[pos]) ) ++pos; if ( tu[pos] ) { while ( isspace(tu[pos]) ) ++pos; @@ -224,30 +220,36 @@ int setBaseTime(const char *timeunits, taxis_t *taxis) if ( str_is_equal(tu+pos, "since") ) timetype = TAXIS_RELATIVE; - while ( ! isspace(tu[pos]) && tu[pos] != 0 ) ++pos; + while ( pos < len && !isspace(tu[pos]) ) ++pos; if ( tu[pos] ) { while ( isspace(tu[pos]) ) ++pos; if ( timetype == TAXIS_ABSOLUTE ) { - if ( !str_is_equal(tu+pos, "%y%m%d.%f") && timeunit == TUNIT_DAY ) + if ( timeunit == TUNIT_DAY ) { - Message("Unsupported format %s for TIMEUNIT day!", tu+pos); - timeunit = -1; + if ( !str_is_equal(tu+pos, "%y%m%d.%f") ) + { + Message("Unsupported format %s for TIMEUNIT day!", tu+pos); + timeunit = -1; + } } - else if ( !str_is_equal(tu+pos, "%y%m.%f") && timeunit == TUNIT_MONTH ) + else if ( timeunit == TUNIT_MONTH ) { - Message("Unsupported format %s for TIMEUNIT month!", tu+pos); - timeunit = -1; + if ( !str_is_equal(tu+pos, "%y%m.%f") ) + { + Message("Unsupported format %s for TIMEUNIT month!", tu+pos); + timeunit = -1; + } } } else if ( timetype == TAXIS_RELATIVE ) { scanTimeString(tu+pos, &rdate, &rtime); - (*taxis).rdate = rdate; - (*taxis).rtime = rtime; + taxis->rdate = rdate; + taxis->rtime = rtime; if ( CDI_Debug ) Message("rdate = %d rtime = %d", rdate, rtime); @@ -255,8 +257,8 @@ int setBaseTime(const char *timeunits, taxis_t *taxis) } } - (*taxis).type = timetype; - (*taxis).unit = timeunit; + taxis->type = timetype; + taxis->unit = timeunit; Free(tu); @@ -267,56 +269,106 @@ int setBaseTime(const char *timeunits, taxis_t *taxis) } static -void cdfGetAttInt(int fileID, int ncvarid, const char *attname, int attlen, int *attint) +bool xtypeIsText(int xtype) { - nc_type atttype; - size_t nc_attlen; + bool isText = ( xtype == NC_CHAR ) +#if defined (HAVE_NETCDF4) + || ( xtype == NC_STRING ) +#endif + ; + return isText; +} + +static +bool xtypeIsFloat(nc_type xtype) +{ + bool isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE; + + return isFloat; +} +static +bool xtypeIsInt(nc_type xtype) +{ + bool isInt = xtype == NC_SHORT || xtype == NC_INT + || xtype == NC_BYTE +#if defined (HAVE_NETCDF4) + || xtype == NC_USHORT || xtype == NC_UINT + || xtype == NC_UBYTE +#endif + ; + + return isInt; +} + +static +int cdfInqDatatype(int xtype, bool lunsigned) +{ + int datatype = -1; + +#if defined (HAVE_NETCDF4) + if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE; +#endif + + if ( xtype == NC_BYTE ) datatype = CDI_DATATYPE_INT8; + else if ( xtype == NC_CHAR ) datatype = CDI_DATATYPE_UINT8; + else if ( xtype == NC_SHORT ) datatype = CDI_DATATYPE_INT16; + else if ( xtype == NC_INT ) datatype = CDI_DATATYPE_INT32; + else if ( xtype == NC_FLOAT ) datatype = CDI_DATATYPE_FLT32; + else if ( xtype == NC_DOUBLE ) datatype = CDI_DATATYPE_FLT64; +#if defined (HAVE_NETCDF4) + else if ( xtype == NC_UBYTE ) datatype = CDI_DATATYPE_UINT8; + else if ( xtype == NC_LONG ) datatype = CDI_DATATYPE_INT32; + else if ( xtype == NC_USHORT ) datatype = CDI_DATATYPE_UINT16; + else if ( xtype == NC_UINT ) datatype = CDI_DATATYPE_UINT32; + else if ( xtype == NC_INT64 ) datatype = CDI_DATATYPE_FLT64; + else if ( xtype == NC_UINT64 ) datatype = CDI_DATATYPE_FLT64; +#endif + + return datatype; +} + +static +void cdfGetAttInt(int fileID, int ncvarid, const char *attname, size_t attlen, int *attint) +{ *attint = 0; + nc_type atttype; + size_t nc_attlen; cdf_inq_atttype(fileID, ncvarid, attname, &atttype); cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen); - if ( atttype != NC_CHAR ) + if ( xtypeIsFloat(atttype) || xtypeIsInt(atttype) ) { - int *pintatt = (int)nc_attlen > attlen - ? (int *)(Malloc(nc_attlen * sizeof (int))) : attint; - + bool lalloc = nc_attlen > attlen; + int *pintatt = lalloc ? (int *)(Malloc(nc_attlen*sizeof(int))) : attint; cdf_get_att_int(fileID, ncvarid, attname, pintatt); - - if ( (int)nc_attlen > attlen ) + if ( lalloc ) { - memcpy(attint, pintatt, (size_t)attlen * sizeof (int)); + memcpy(attint, pintatt, attlen*sizeof(int)); Free(pintatt); } } } static -void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble) +void cdfGetAttDouble(int fileID, int ncvarid, char *attname, size_t attlen, double *attdouble) { - nc_type atttype; - size_t nc_attlen; - *attdouble = 0; + nc_type atttype; + size_t nc_attlen; cdf_inq_atttype(fileID, ncvarid, attname, &atttype); cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen); - if ( atttype != NC_CHAR ) + if ( xtypeIsFloat(atttype) || xtypeIsInt(atttype) ) { - double *pdoubleatt = NULL; - - if ( (int)nc_attlen > attlen ) - pdoubleatt = (double *) Malloc(nc_attlen * sizeof (double)); - else - pdoubleatt = attdouble; - + bool lalloc = nc_attlen > attlen; + double *pdoubleatt = lalloc ? (double*)Malloc(nc_attlen*sizeof(double)) : attdouble; cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt); - - if ( (int)nc_attlen > attlen ) + if ( lalloc ) { - memcpy(attdouble, pdoubleatt, (size_t)attlen * sizeof (double)); + memcpy(attdouble, pdoubleatt, attlen*sizeof(double)); Free(pdoubleatt); } } @@ -392,66 +444,6 @@ void cdfGetAttText(int fileID, int ncvarid, const char *attname, size_t attlen, #endif } -static -bool xtypeIsText(int xtype) -{ - bool isText = ( xtype == NC_CHAR ) -#if defined (HAVE_NETCDF4) - || ( xtype == NC_STRING ) -#endif - ; - return isText; -} - -static -bool xtypeIsFloat(nc_type xtype) -{ - bool isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE; - - return isFloat; -} - -static -bool xtypeIsInt(nc_type xtype) -{ - bool isInt = xtype == NC_SHORT || xtype == NC_INT - || xtype == NC_BYTE -#if defined (HAVE_NETCDF4) - || xtype == NC_USHORT || xtype == NC_UINT - || xtype == NC_UBYTE -#endif - ; - - return isInt; -} - -static -int cdfInqDatatype(int xtype, bool lunsigned) -{ - int datatype = -1; - -#if defined (HAVE_NETCDF4) - if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE; -#endif - - if ( xtype == NC_BYTE ) datatype = CDI_DATATYPE_INT8; - /* else if ( xtype == NC_CHAR ) datatype = CDI_DATATYPE_UINT8; */ - else if ( xtype == NC_SHORT ) datatype = CDI_DATATYPE_INT16; - else if ( xtype == NC_INT ) datatype = CDI_DATATYPE_INT32; - else if ( xtype == NC_FLOAT ) datatype = CDI_DATATYPE_FLT32; - else if ( xtype == NC_DOUBLE ) datatype = CDI_DATATYPE_FLT64; -#if defined (HAVE_NETCDF4) - else if ( xtype == NC_UBYTE ) datatype = CDI_DATATYPE_UINT8; - else if ( xtype == NC_LONG ) datatype = CDI_DATATYPE_INT32; - else if ( xtype == NC_USHORT ) datatype = CDI_DATATYPE_UINT16; - else if ( xtype == NC_UINT ) datatype = CDI_DATATYPE_UINT32; - else if ( xtype == NC_INT64 ) datatype = CDI_DATATYPE_FLT64; - else if ( xtype == NC_UINT64 ) datatype = CDI_DATATYPE_FLT64; -#endif - - return datatype; -} - void cdf_scale_add(size_t size, double *data, double addoffset, double scalefactor) { @@ -637,6 +629,7 @@ void init_ncvars(long nvars, ncvar_t *ncvars) ncvars[ncvarid].ignore = false; ncvars[ncvarid].isx = false; ncvars[ncvarid].isy = false; + ncvars[ncvarid].isc = false; ncvars[ncvarid].islon = false; ncvars[ncvarid].islat = false; ncvars[ncvarid].islev = false; @@ -665,7 +658,10 @@ void init_ncvars(long nvars, ncvar_t *ncvars) ncvars[ncvarid].p0varid = CDI_UNDEFID; ncvars[ncvarid].ncoordvars = 0; for ( int i = 0; i < MAX_COORDVARS; ++i ) - ncvars[ncvarid].coordvarids[i] = CDI_UNDEFID; + { + ncvars[ncvarid].coordvarids[i] = CDI_UNDEFID; + ncvars[ncvarid].cvarids[i] = CDI_UNDEFID; + } ncvars[ncvarid].nauxvars = 0; for ( int i = 0; i < MAX_AUXVARS; ++i ) ncvars[ncvarid].auxvarids[i] = CDI_UNDEFID; @@ -880,7 +876,7 @@ void cdf_set_cdi_attr(int ncid, int ncvarid, int attnum, int cdiID, int varID) if ( xtypeIsInt(atttype) ) { int attint[attlen]; - cdfGetAttInt(ncid, ncvarid, attname, (int)attlen, attint); + cdfGetAttInt(ncid, ncvarid, attname, attlen, attint); int datatype = (atttype == NC_SHORT) ? CDI_DATATYPE_INT16 : (atttype == NC_BYTE) ? CDI_DATATYPE_INT8 : #if defined (HAVE_NETCDF4) @@ -894,7 +890,7 @@ void cdf_set_cdi_attr(int ncid, int ncvarid, int attnum, int cdiID, int varID) else if ( xtypeIsFloat(atttype) ) { double attflt[attlen]; - cdfGetAttDouble(ncid, ncvarid, attname, (int)attlen, attflt); + cdfGetAttDouble(ncid, ncvarid, attname, attlen, attflt); int datatype = (atttype == NC_FLOAT) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64; cdiDefAttFlt(cdiID, varID, attname, datatype, (int)attlen, attflt); } @@ -1156,6 +1152,7 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi size_t attstringsize = sizeof(attstring); bool isText = xtypeIsText(atttype); + bool isNumber = xtypeIsFloat(atttype) || xtypeIsInt(atttype); if ( isText ) { cdfGetAttText(ncid, ncvarid, attname, sizeof(attstring), attstring); @@ -1186,12 +1183,12 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi ncvars[ncvarid].param = cdiEncodeParam(pnum, pcat, pdis); cdf_set_var(ncvars, ncvarid, TRUE); } - else if ( !isText && strcmp(attname, "code") == 0 ) + else if ( isNumber && strcmp(attname, "code") == 0 ) { cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].code); cdf_set_var(ncvars, ncvarid, TRUE); } - else if ( !isText && strcmp(attname, "table") == 0 ) + else if ( isNumber && strcmp(attname, "table") == 0 ) { int tablenum; cdfGetAttInt(ncid, ncvarid, attname, 1, &tablenum); @@ -1221,19 +1218,19 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi set_zaxistype(attstring, &ncvars[ncvarid].zaxistype); cdf_set_var(ncvars, ncvarid, TRUE); } - else if ( !isText && strcmp(attname, "trunc_count") == 0 ) + else if ( isNumber && strcmp(attname, "trunc_count") == 0 ) { cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation); } - else if ( !isText && strcmp(attname, "truncation") == 0 ) + else if ( isNumber && strcmp(attname, "truncation") == 0 ) { cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation); } - else if ( !isText && strcmp(attname, "number_of_grid_in_reference") == 0 ) + else if ( isNumber && strcmp(attname, "number_of_grid_in_reference") == 0 ) { cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].position); } - else if ( !isText && strcmp(attname, "add_offset") == 0 ) + else if ( isNumber && strcmp(attname, "add_offset") == 0 ) { cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].addoffset); /* @@ -1243,7 +1240,7 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi */ /* (also used for lon/lat) cdf_set_var(ncvars, ncvarid, TRUE); */ } - else if ( !isText && strcmp(attname, "scale_factor") == 0 ) + else if ( isNumber && strcmp(attname, "scale_factor") == 0 ) { cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].scalefactor); /* @@ -1417,19 +1414,19 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS; } } - else if ( !isText && strcmp(attname, "_FillValue") == 0 ) + else if ( isNumber && strcmp(attname, "_FillValue") == 0 ) { cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].fillval); ncvars[ncvarid].deffillval = true; /* cdf_set_var(ncvars, ncvarid, TRUE); */ } - else if ( !isText && strcmp(attname, "missing_value") == 0 ) + else if ( isNumber && strcmp(attname, "missing_value") == 0 ) { cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].missval); ncvars[ncvarid].defmissval = true; /* cdf_set_var(ncvars, ncvarid, TRUE); */ } - else if ( strcmp(attname, "valid_range") == 0 && attlen == 2 ) + else if ( isNumber && strcmp(attname, "valid_range") == 0 && attlen == 2 ) { if ( ncvars[ncvarid].lvalidrange == false ) { @@ -1449,7 +1446,7 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi } } } - else if ( strcmp(attname, "valid_min") == 0 && attlen == 1 ) + else if ( isNumber && strcmp(attname, "valid_min") == 0 && attlen == 1 ) { if ( ncvars[ncvarid].lvalidrange == false ) { @@ -1466,7 +1463,7 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi } } } - else if ( strcmp(attname, "valid_max") == 0 && attlen == 1 ) + else if ( isNumber && strcmp(attname, "valid_max") == 0 && attlen == 1 ) { if ( ncvars[ncvarid].lvalidrange == false ) { @@ -1530,9 +1527,10 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi cdf_scan_attr_axis(ncvars, ncdims, ncvarid, attstring, attlen, nvdims, dimidsp, name); } } - else if ( ( strcmp(attname, "realization") == 0 ) || - ( strcmp(attname, "ensemble_members") == 0 ) || - ( strcmp(attname, "forecast_init_type") == 0 ) ) + else if ( isNumber && + (strcmp(attname, "realization") == 0 || + strcmp(attname, "ensemble_members") == 0 || + strcmp(attname, "forecast_init_type") == 0) ) { int temp; @@ -1618,6 +1616,7 @@ void cdf_set_dimtype(int nvars, ncvar_t *ncvars, ncdim_t *ncdims) if ( ncvars[ncvarid].isvar == TRUE ) { bool lxdim = false, lydim = false, lzdim = false/* , ltdim = false */; + int lcdim = 0; int ndims = ncvars[ncvarid].ndims; for ( int i = 0; i < ndims; i++ ) { @@ -1625,9 +1624,12 @@ void cdf_set_dimtype(int nvars, ncvar_t *ncvars, ncdim_t *ncdims) lxdim = lxdim | (dimtype == X_AXIS); lydim = lydim | (dimtype == Y_AXIS); lzdim = lzdim | (dimtype == Z_AXIS); + if ( ncvars[ncvarid].cvarids[i] != CDI_UNDEFID ) lcdim++; /* else if ( ncvars[ncvarid].dimtype[i] == T_AXIS ) ltdim = true; */ } + int allcdims = lcdim; + if ( !lxdim && ncvars[ncvarid].xvarid != CDI_UNDEFID ) { if ( ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = true; @@ -1645,6 +1647,13 @@ void cdf_set_dimtype(int nvars, ncvar_t *ncvars, ncdim_t *ncdims) { if ( !lzdim ) { + if ( lcdim ) + { + int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim]; + ncvars[ncvarid].zvarid = cdimvar; + lcdim--; + ncvars[cdimvar].zaxistype = ZAXIS_CHAR; + } cdf_set_dim(ncvars, ncvarid, i, Z_AXIS); lzdim = true; int ncdimid = ncvars[ncvarid].dimids[i]; @@ -1678,15 +1687,19 @@ void cdf_set_dimtype(int nvars, ncvar_t *ncvars, ncdim_t *ncdims) if ( ncvars[ncvarid].isvar == TRUE ) { bool lxdim = false, lydim = false, lzdim = false/* , ltdim = false */; + int lcdim = 0; int ndims = ncvars[ncvarid].ndims; for ( int i = 0; i < ndims; i++ ) { if ( ncvars[ncvarid].dimtype[i] == X_AXIS ) lxdim = true; else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) lydim = true; else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) lzdim = true; + else if ( ncvars[ncvarid].cvarids[i] != CDI_UNDEFID ) lcdim++; /* else if ( ncvars[ncvarid].dimtype[i] == T_AXIS ) ltdim = true; */ } + int allcdims = lcdim; + if ( !lxdim && ncvars[ncvarid].xvarid != CDI_UNDEFID ) { if ( ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = true; @@ -1704,16 +1717,35 @@ void cdf_set_dimtype(int nvars, ncvar_t *ncvars, ncdim_t *ncdims) { if ( !lxdim ) { + if ( lcdim && ncvars[ncvarid].xvarid == CDI_UNDEFID ) + { + int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim]; + ncvars[ncvarid].xvarid = cdimvar; + lcdim--; + } cdf_set_dim(ncvars, ncvarid, i, X_AXIS); lxdim = true; } else if ( !lydim && ncvars[ncvarid].gridtype != GRID_UNSTRUCTURED ) { + if ( lcdim && ncvars[ncvarid].yvarid == CDI_UNDEFID ) + { + int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim]; + ncvars[ncvarid].yvarid = cdimvar; + lcdim--; + } cdf_set_dim(ncvars, ncvarid, i, Y_AXIS); lydim = true; } else if ( !lzdim ) { + if ( lcdim > 0 ) + { + int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim]; + ncvars[ncvarid].zvarid = cdimvar; + lcdim--; + ncvars[cdimvar].zaxistype = ZAXIS_CHAR; + } cdf_set_dim(ncvars, ncvarid, i, Z_AXIS); lzdim = true; } @@ -1907,6 +1939,12 @@ void verify_coordinate_vars_2(int nvars, ncvar_t *ncvars) continue; } } + else if ( strcmp(ncvars[ncvarid].stdname, "region") == 0 || + strcmp(ncvars[ncvarid].stdname, "area_type") == 0 || + cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned) == CDI_DATATYPE_UINT8 ) + { + ncvars[ncvarid].isc = true; + } /* not needed anymore for rotated grids */ if ( !ncvars[ncvarid].islon && ncvars[ncvarid].longname[0] != 0 && @@ -1983,6 +2021,20 @@ void cdf_load_vals(size_t size, int ndims, int varid, ncvar_t *ncvar, double **g } } +static +void cdf_load_cvals(size_t size, int varid, ncvar_t *ncvar, char ***gridvals, size_t dimlength) +{ + size_t startc[] = {0, 0}; + size_t countc[] = {1, size/dimlength}; + *gridvals = (char **) Malloc(dimlength * sizeof(char *)); + for ( size_t i = 0; i < dimlength; i++ ) + { + (*gridvals)[i] = (char*) Malloc((size/dimlength) * sizeof(char)); + cdf_get_vara_text(ncvar->ncid, varid, startc, countc, (*gridvals)[i]); + startc[0] = i+1; + } +} + static void cdf_load_bounds(size_t size, ncvar_t *ncvar, double **gridbounds, struct cdfLazyGridIds *cellBoundsGet) { @@ -2021,6 +2073,8 @@ void cdf_copy_axis_attr(ncvar_t *ncvar, struct gridaxis_t *gridaxis) strcpy(gridaxis->name, ncvar->name); strcpy(gridaxis->longname, ncvar->longname); strcpy(gridaxis->units, ncvar->units); + if ( gridaxis->cvals ) + gridaxis->stdname = ncvar->stdname; } static @@ -2103,16 +2157,28 @@ bool cdf_read_xcoord(struct cdfLazyGrid *restrict lazyGrid, ncdim_t *ncdims, ncv *islon = axisvar->islon; int ndims = axisvar->ndims; size_t size = 0; + int prec = cdfInqDatatype(axisvar->xtype, axisvar->lunsigned); + if ( (ndims - ntdims) == 2 ) { - ncvar->gridtype = GRID_CURVILINEAR; - size = (*xsize)*ysize; /* Check size of 2 dimensional coordinate variables */ int dimid = axisvar->dimids[ndims-2]; size_t dimsize1 = ncdims[dimid].len; dimid = axisvar->dimids[ndims-1]; size_t dimsize2 = ncdims[dimid].len; - skipvar = dimsize1*dimsize2 != size; + + if ( prec == CDI_DATATYPE_UINT8 ) + { + ncvar->gridtype = GRID_CHARXY; + size = dimsize1*dimsize2; + skipvar = dimsize1 != *xsize; + } + else + { + ncvar->gridtype = GRID_CURVILINEAR; + size = (*xsize)*ysize; + skipvar = dimsize1*dimsize2 != size; + } } else if ( (ndims - ntdims) == 1 ) { @@ -2135,10 +2201,15 @@ bool cdf_read_xcoord(struct cdfLazyGrid *restrict lazyGrid, ncdim_t *ncdims, ncv return true; } - int prec = cdfInqDatatype(axisvar->xtype, axisvar->lunsigned); if ( prec != -1 ) grid->prec = prec; - cdf_load_vals(size, ndims, xvarid, axisvar, &grid->x.vals, &lazyGrid->xValsGet, ntdims, start, count); + if ( prec == CDI_DATATYPE_UINT8 && !CDI_netcdf_lazy_grid_load ) + { + cdf_load_cvals(size, xvarid, axisvar, &grid->x.cvals, *xsize); + grid->x.clength = size / (*xsize) ; + } + else + cdf_load_vals(size, ndims, xvarid, axisvar, &grid->x.vals, &lazyGrid->xValsGet, ntdims, start, count); cdf_copy_axis_attr(axisvar, &grid->x); @@ -2154,16 +2225,28 @@ bool cdf_read_ycoord(struct cdfLazyGrid *restrict lazyGrid, ncdim_t *ncdims, ncv *islat = axisvar->islat; int ndims = axisvar->ndims; size_t size = 0; + int prec = cdfInqDatatype(axisvar->xtype, axisvar->lunsigned); + if ( (ndims - ntdims) == 2 ) { - ncvar->gridtype = GRID_CURVILINEAR; - size = xsize*(*ysize); /* Check size of 2 dimensional coordinate variables */ int dimid = axisvar->dimids[ndims-2]; size_t dimsize1 = ncdims[dimid].len; dimid = axisvar->dimids[ndims-1]; size_t dimsize2 = ncdims[dimid].len; - skipvar = dimsize1*dimsize2 != size; + + if ( prec == CDI_DATATYPE_UINT8 ) + { + ncvar->gridtype = GRID_CHARXY; + size = dimsize1*dimsize2; + skipvar = dimsize1 != *ysize; + } + else + { + ncvar->gridtype = GRID_CURVILINEAR; + size = xsize*(*ysize); + skipvar = dimsize1*dimsize2 != size; + } } else if ( (ndims - ntdims) == 1 ) { @@ -2187,10 +2270,15 @@ bool cdf_read_ycoord(struct cdfLazyGrid *restrict lazyGrid, ncdim_t *ncdims, ncv return true; } - int prec = cdfInqDatatype(axisvar->xtype, axisvar->lunsigned); if ( prec != -1 ) grid->prec = prec; - cdf_load_vals(size, ndims, yvarid, axisvar, &grid->y.vals, &lazyGrid->yValsGet, ntdims, start, count); + if ( prec == CDI_DATATYPE_UINT8 && !CDI_netcdf_lazy_grid_load ) + { + cdf_load_cvals(size, yvarid, axisvar, &grid->y.cvals, *ysize); + grid->y.clength = size / (*ysize) ; + } + else + cdf_load_vals(size, ndims, yvarid, axisvar, &grid->y.vals, &lazyGrid->yValsGet, ntdims, start, count); cdf_copy_axis_attr(axisvar, &grid->y); @@ -2220,7 +2308,7 @@ bool cdf_read_coordinates(struct cdfLazyGrid *restrict lazyGrid, ncvar_t *ncvar, if ( xvarid != CDI_UNDEFID && yvarid != CDI_UNDEFID ) { int ndims = ncvars[xvarid].ndims; - if ( ndims != ncvars[yvarid].ndims ) + if ( ndims != ncvars[yvarid].ndims && !ncvars[xvarid].isc && !ncvars[yvarid].isc ) { Warning("Inconsistent grid structure for variable %s!", ncvar->name); ncvar->xvarid = xvarid = CDI_UNDEFID; @@ -2373,6 +2461,13 @@ bool cdf_read_coordinates(struct cdfLazyGrid *restrict lazyGrid, ncvar_t *ncvar, grid->size = 1; break; } + case GRID_CHARXY: + { + grid->size = (int)size; + grid->x.size = (int)xsize; + grid->y.size = (int)ysize; + break; + } } // if ( grid->type != GRID_PROJECTION && grid->type != ncvar->gridtype ) @@ -2398,7 +2493,7 @@ bool cdf_read_coordinates(struct cdfLazyGrid *restrict lazyGrid, ncvar_t *ncvar, } else { - Warning("Variable %s has an unsupported grid, skipped!", ncvar->name); + Warning("Unsupported grid, skipped variable %s!", ncvar->name); ncvar->isvar = -1; return true; } @@ -2535,8 +2630,8 @@ void cdf_set_grid_to_similar_vars(ncvar_t *ncvar1, ncvar_t *ncvar2, int gridtype } static -void cdf_define_all_grids(ncgrid_t *ncgrid, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars, - int timedimid, unsigned char *uuidOfHGrid, char *gridfile, int number_of_grid_used) +int cdf_define_all_grids(ncgrid_t *ncgrid, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars, + int timedimid, unsigned char *uuidOfHGrid, char *gridfile, int number_of_grid_used) { for ( int ncvarid = 0; ncvarid < nvars; ++ncvarid ) { @@ -2568,6 +2663,17 @@ void cdf_define_all_grids(ncgrid_t *ncgrid, int vlistID, ncdim_t *ncdims, int nv } } + if ( xsize > INT_MAX ) + { + Warning("Size limit exceeded for x-axis dimension (limit=%d)!", INT_MAX); + return CDI_EDIMSIZE; + } + if ( ysize > INT_MAX ) + { + Warning("Size limit exceeded for y-axis dimension (limit=%d)!", INT_MAX); + return CDI_EDIMSIZE; + } + int gmapvarid = ncvar->gmapid; bool lproj = gmapvarid != CDI_UNDEFID; @@ -2662,8 +2768,8 @@ void cdf_define_all_grids(ncgrid_t *ncgrid, int vlistID, ncdim_t *ncdims, int nv int gridindex = vlistGridIndex(vlistID, gridID); ncgrid[gridindex].gridID = gridID; - ncgrid[gridindex].xdimID = xdimid; - ncgrid[gridindex].ydimID = ydimid; + ncgrid[gridindex].ncIDs[CDF_DIMID_X] = xdimid; + ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = ydimid; if ( xdimid == CDI_UNDEFID && ydimid == CDI_UNDEFID && grid->size == 1 ) gridDefHasDims(gridID, FALSE); @@ -2693,12 +2799,14 @@ void cdf_define_all_grids(ncgrid_t *ncgrid, int vlistID, ncdim_t *ncdims, int nv } } } + + return 0; } /* define all input zaxes */ static -void cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars, - size_t vctsize_echam, double *vct_echam, unsigned char *uuidOfVGrid) +int cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars, + size_t vctsize_echam, double *vct_echam, unsigned char *uuidOfVGrid) { char *pname, *plongname, *punits; size_t vctsize = vctsize_echam; @@ -2716,8 +2824,6 @@ void cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int int zsize = 1; int psvarid = -1; int p0varid = -1; - double *lbounds = NULL; - double *ubounds = NULL; int positive = 0; int ndims = ncvar->ndims; @@ -2737,7 +2843,8 @@ void cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int if ( zdimid != CDI_UNDEFID ) { - zvarid = ncdims[zdimid].ncvarid; + // zvarid = ncdims[zdimid].ncvarid; + zvarid = (ncvar->zvarid != CDI_UNDEFID) ? ncvar->zvarid : ncdims[zdimid].ncvarid; zsize = (int)ncdims[zdimid].len; } } @@ -2745,12 +2852,15 @@ void cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int if ( CDI_Debug ) Message("nlevs = %d", zsize); double *zvar = NULL; + char **zcvals = NULL; int zaxisType = CDI_UNDEFID; if ( zvarid != CDI_UNDEFID ) zaxisType = ncvars[zvarid].zaxistype; if ( zaxisType == CDI_UNDEFID ) zaxisType = ZAXIS_GENERIC; int zprec = CDI_DATATYPE_FLT64; + double *restrict lbounds = NULL; + double *restrict ubounds = NULL; if ( zvarid != CDI_UNDEFID ) { @@ -2765,6 +2875,16 @@ void cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int if ( pname[len-2] == '_' && isdigit((int) pname[len-1]) ) pname[len-2] = 0; */ + if ( zaxisType == ZAXIS_CHAR ) + { + if ( ncvars[zvarid].ndims == 2 ) + { + zprec = CDI_DATATYPE_UINT8; + size_t strlength = ncdims[ncvars[zvarid].dimids[1]].len; + cdf_load_cvals(zsize*strlength, zvarid, ncvar, &zcvals, zsize); + } + } + if ( zaxisType == ZAXIS_HYBRID && ncvars[zvarid].vct ) { vct = ncvars[zvarid].vct; @@ -2774,8 +2894,11 @@ void cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int if ( ncvars[zvarid].p0varid != -1 ) p0varid = ncvars[zvarid].p0varid; } - zvar = (double*) Malloc((size_t)zsize*sizeof(double)); - cdf_get_var_double(ncvars[zvarid].ncid, zvarid, zvar); + if ( zaxisType != ZAXIS_CHAR ) + { + zvar = (double*) Malloc((size_t)zsize*sizeof(double)); + cdf_get_var_double(ncvars[zvarid].ncid, zvarid, zvar); + } if ( ncvars[zvarid].bounds != CDI_UNDEFID ) { @@ -2787,9 +2910,9 @@ void cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int if ( nlevel == zsize && nvertex == 2 ) { with_bounds = true; - lbounds = (double *) Malloc((size_t)nlevel*sizeof(double)); - ubounds = (double *) Malloc((size_t)nlevel*sizeof(double)); - double zbounds[2*nlevel]; + lbounds = (double *) Malloc(4 * (size_t)nlevel*sizeof(double)); + ubounds = lbounds + nlevel; + double *restrict zbounds = lbounds + 2 * nlevel; cdf_get_var_double(ncvars[zvarid].ncid, ncvars[zvarid].bounds, zbounds); for ( int i = 0; i < nlevel; ++i ) { @@ -2817,7 +2940,13 @@ void cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int } } - ncvar->zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, with_bounds, lbounds, ubounds, + if ( zsize > INT_MAX ) + { + Warning("Size limit exceeded for z-axis dimension (limit=%d)!", INT_MAX); + return CDI_EDIMSIZE; + } + + ncvar->zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, (const char **)zcvals, with_bounds, lbounds, ubounds, (int)vctsize, vct, pname, plongname, punits, zprec, 1, 0); int zaxisID = ncvar->zaxisID; @@ -2851,7 +2980,6 @@ void cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int */ if ( zvar ) Free(zvar); if ( lbounds ) Free(lbounds); - if ( ubounds ) Free(ubounds); if ( zvarid != CDI_UNDEFID ) { @@ -2900,6 +3028,8 @@ void cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int } } } + + return 0; } @@ -3006,8 +3136,8 @@ void cdf_define_all_vars(stream_t *streamptr, int vlistID, int instID, int model vlistInqVarGrid(vlistID, varID), vlistInqVarZaxis(vlistID, varID)); int gridindex = vlistGridIndex(vlistID, gridID); - int xdimid = streamptr->ncgrid[gridindex].xdimID; - int ydimid = streamptr->ncgrid[gridindex].ydimID; + int xdimid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X]; + int ydimid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y]; int zaxisindex = vlistZaxisIndex(vlistID, zaxisID); int zdimid = streamptr->zaxisID[zaxisindex]; @@ -3255,7 +3385,7 @@ void cdf_scan_global_attr(int fileID, int vlistID, stream_t *streamptr, int ngat else { int attint[attlen]; - cdfGetAttInt(fileID, NC_GLOBAL, attname, (int)attlen, attint); + cdfGetAttInt(fileID, NC_GLOBAL, attname, attlen, attint); int datatype = (xtype == NC_SHORT) ? CDI_DATATYPE_INT16 : CDI_DATATYPE_INT32; cdiDefAttInt(vlistID, CDI_GLOBAL, attname, datatype, (int)attlen, attint); } @@ -3263,7 +3393,7 @@ void cdf_scan_global_attr(int fileID, int vlistID, stream_t *streamptr, int ngat else if ( xtype == NC_FLOAT || xtype == NC_DOUBLE ) { double attflt[attlen]; - cdfGetAttDouble(fileID, NC_GLOBAL, attname, (int)attlen, attflt); + cdfGetAttDouble(fileID, NC_GLOBAL, attname, attlen, attflt); int datatype = (xtype == NC_FLOAT) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64; cdiDefAttFlt(vlistID, CDI_GLOBAL, attname, datatype, (int)attlen, attflt); } @@ -3508,7 +3638,7 @@ int cdf_check_vars(int nvars, ncvar_t *ncvars, size_t ntsteps, int timedimid) if ( cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned) == -1 ) { ncvars[ncvarid].isvar = 0; - Warning("Variable %s has an unsupported data type, skipped!", ncvars[ncvarid].name); + Warning("Unsupported data type, skipped variable %s!", ncvars[ncvarid].name); continue; } @@ -3532,7 +3662,6 @@ int cdfInqContents(stream_t *streamptr) int ndims, nvars, ngatts, unlimdimid; int ncvarid; int ncdimid; - int timedimid = -1; int *varids; int nvarids; bool time_has_units = false; @@ -3625,15 +3754,17 @@ int cdfInqContents(stream_t *streamptr) uuidOfHGrid, uuidOfVGrid, gridfile, &number_of_grid_used); /* find time dim */ - if ( unlimdimid >= 0 ) - timedimid = unlimdimid; - else - timedimid = cdf_time_dimid(fileID, ndims, nvars); + int timedimid = (unlimdimid >= 0) ? unlimdimid : cdf_time_dimid(fileID, ndims, nvars); streamptr->basetime.ncdimid = timedimid; size_t ntsteps = 0; if ( timedimid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, timedimid, &ntsteps); + if ( ntsteps > INT_MAX ) + { + Warning("Size limit exceeded for time dimension (limit=%d)!", INT_MAX); + return CDI_EDIMSIZE; + } if ( CDI_Debug ) Message("Number of timesteps = %zu", ntsteps); if ( CDI_Debug ) Message("Time dimid = %d", streamptr->basetime.ncdimid); @@ -3742,6 +3873,7 @@ int cdfInqContents(stream_t *streamptr) else if ( ncvars[ncvar->coordvarids[i]].islat || ncvars[ncvar->coordvarids[i]].isy ) ncvar->yvarid = ncvar->coordvarids[i]; else if ( ncvars[ncvar->coordvarids[i]].islev ) ncvar->zvarid = ncvar->coordvarids[i]; + else if ( ncvars[ncvar->coordvarids[i]].isc ) ncvar->cvarids[i] = ncvar->coordvarids[i]; } } } @@ -3758,12 +3890,14 @@ int cdfInqContents(stream_t *streamptr) if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "cdf_define_all_grids"); /* define all grids */ - cdf_define_all_grids(streamptr->ncgrid, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used); - + int status; + status = cdf_define_all_grids(streamptr->ncgrid, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used); + if ( status < 0 ) return status; /* define all zaxes */ - cdf_define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid); + status = cdf_define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid); if ( vct ) Free(vct); + if ( status < 0 ) return status; /* select vars */ diff --git a/src/stream_cdf_o.c b/src/stream_cdf_o.c index 91e612bac17010be8cecbfad09fd1c389938fc7e..04c11add4a59392b9734833a6c9efcd1bd8f9134 100644 --- a/src/stream_cdf_o.c +++ b/src/stream_cdf_o.c @@ -95,235 +95,6 @@ void cdfDefTimeValue(stream_t *streamptr, int tsID) } } -static -int cdfDefTimeBounds(int fileID, int nctimevarid, int nctimedimid, const char *taxis_name, taxis_t* taxis) -{ - int time_bndsid = -1; - int dims[2]; - - dims[0] = nctimedimid; - - /* fprintf(stderr, "time has bounds\n"); */ - - if ( nc_inq_dimid(fileID, bndsName, &dims[1]) != NC_NOERR ) - cdf_def_dim(fileID, bndsName, 2, &dims[1]); - - const char *bndsAttName, *bndsAttVal; - size_t bndsAttValLen; - char tmpstr[CDI_MAX_NAME]; - if ( taxis->climatology ) - { - static const char climatology_bndsName[] = "climatology_bnds", - climatology_bndsAttName[] = "climatology"; - bndsAttName = climatology_bndsAttName; - bndsAttValLen = sizeof (climatology_bndsName) - 1; - bndsAttVal = climatology_bndsName; - } - else - { - size_t taxisnameLen = strlen(taxis_name); - memcpy(tmpstr, taxis_name, taxisnameLen); - tmpstr[taxisnameLen] = '_'; - memcpy(tmpstr + taxisnameLen + 1, bndsName, sizeof (bndsName)); - size_t tmpstrLen = taxisnameLen + sizeof (bndsName); - static const char generic_bndsAttName[] = "bounds"; - bndsAttName = generic_bndsAttName; - bndsAttValLen = tmpstrLen; - bndsAttVal = tmpstr; - } - cdf_def_var(fileID, bndsAttVal, NC_DOUBLE, 2, dims, &time_bndsid); - cdf_put_att_text(fileID, nctimevarid, bndsAttName, bndsAttValLen, bndsAttVal); - - return time_bndsid; -} - -static -void cdfDefTimeUnits(char *unitstr, taxis_t *taxis0, taxis_t *taxis) -{ - if ( taxis->units && taxis->units[0] ) - { - strcpy(unitstr, taxis->units); - } - else - { - unitstr[0] = 0; - - if ( taxis0->type == TAXIS_ABSOLUTE ) - { - if ( taxis0->unit == TUNIT_YEAR ) sprintf(unitstr, "year as %s", "%Y.%f"); - else if ( taxis0->unit == TUNIT_MONTH ) sprintf(unitstr, "month as %s", "%Y%m.%f"); - else sprintf(unitstr, "day as %s", "%Y%m%d.%f"); - } - else - { - int timeunit = taxis->unit != -1 ? taxis->unit : TUNIT_HOUR; - int rdate = taxis->rdate; - int rtime = taxis->rtime; - if ( rdate == -1 ) - { - rdate = taxis->vdate; - rtime = taxis->vtime; - } - - int year, month, day, hour, minute, second; - cdiDecodeDate(rdate, &year, &month, &day); - cdiDecodeTime(rtime, &hour, &minute, &second); - - if ( timeunit == TUNIT_QUARTER ) timeunit = TUNIT_MINUTE; - if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE; - if ( timeunit == TUNIT_3HOURS || - timeunit == TUNIT_6HOURS || - timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR; - - sprintf(unitstr, "%s since %d-%d-%d %02d:%02d:%02d", - tunitNamePtr(timeunit), year, month, day, hour, minute, second); - } - } -} - -static -void cdfDefForecastTimeUnits(char *unitstr, int timeunit) -{ - unitstr[0] = 0; - - if ( timeunit == -1 ) timeunit = TUNIT_HOUR; - - if ( timeunit == TUNIT_QUARTER ) timeunit = TUNIT_MINUTE; - if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE; - if ( timeunit == TUNIT_3HOURS || - timeunit == TUNIT_6HOURS || - timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR; - - strcpy(unitstr, tunitNamePtr(timeunit)); -} - -static -void cdfDefCalendar(int fileID, int ncvarid, int calendar) -{ - static const struct { int calCode; const char *calStr; } calTab[] = { - { CALENDAR_STANDARD, "standard" }, - { CALENDAR_PROLEPTIC, "proleptic_gregorian" }, - { CALENDAR_NONE, "none" }, - { CALENDAR_360DAYS, "360_day" }, - { CALENDAR_365DAYS, "365_day" }, - { CALENDAR_366DAYS, "366_day" }, - }; - enum { calTabSize = sizeof calTab / sizeof calTab[0] }; - - for ( size_t i = 0; i < calTabSize; ++i ) - if ( calTab[i].calCode == calendar ) - { - const char *calstr = calTab[i].calStr; - size_t len = strlen(calstr); - cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr); - break; - } -} - - -void cdfDefTime(stream_t* streamptr) -{ - int time_varid; - int time_dimid; - int time_bndsid = -1; - static const char default_name[] = "time"; - - if ( streamptr->basetime.ncvarid != CDI_UNDEFID ) return; - - int fileID = streamptr->fileID; - - if ( streamptr->ncmode == 0 ) streamptr->ncmode = 1; - if ( streamptr->ncmode == 2 ) cdf_redef(fileID); - - taxis_t *taxis = &streamptr->tsteps[0].taxis; - - const char *taxis_name = (taxis->name && taxis->name[0]) ? taxis->name : default_name ; - - cdf_def_dim(fileID, taxis_name, NC_UNLIMITED, &time_dimid); - streamptr->basetime.ncdimid = time_dimid; - - nc_type xtype = (taxis->datatype == CDI_DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE; - - cdf_def_var(fileID, taxis_name, xtype, 1, &time_dimid, &time_varid); - - streamptr->basetime.ncvarid = time_varid; - -#if defined (HAVE_NETCDF4) - if ( streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C ) - { - size_t chunk = 512; - cdf_def_var_chunking(fileID, time_varid, NC_CHUNKED, &chunk); - } -#endif - - { - static const char timeStr[] = "time"; - cdf_put_att_text(fileID, time_varid, "standard_name", sizeof(timeStr) - 1, timeStr); - } - - if ( taxis->longname && taxis->longname[0] ) - cdf_put_att_text(fileID, time_varid, "long_name", strlen(taxis->longname), taxis->longname); - - if ( taxis->has_bounds ) - { - time_bndsid = cdfDefTimeBounds(fileID, time_varid, time_dimid, taxis_name, taxis); - streamptr->basetime.ncvarboundsid = time_bndsid; - } - - { - char unitstr[CDI_MAX_NAME]; - cdfDefTimeUnits(unitstr, &streamptr->tsteps[0].taxis, taxis); - size_t len = strlen(unitstr); - if ( len ) - { - cdf_put_att_text(fileID, time_varid, "units", len, unitstr); - /* - if ( taxis->has_bounds ) - cdf_put_att_text(fileID, time_bndsid, "units", len, unitstr); - */ - } - } - - if ( taxis->calendar != -1 ) - { - cdfDefCalendar(fileID, time_varid, taxis->calendar); - /* - if ( taxis->has_bounds ) - cdfDefCalendar(fileID, time_bndsid, taxis->calendar); - */ - } - - if ( taxis->type == TAXIS_FORECAST ) - { - int leadtimeid; - cdf_def_var(fileID, "leadtime", xtype, 1, &time_dimid, &leadtimeid); - streamptr->basetime.leadtimeid = leadtimeid; - - { - static const char stdname[] = "forecast_period"; - cdf_put_att_text(fileID, leadtimeid, "standard_name", sizeof(stdname) - 1, stdname); - } - - { - static const char lname[] = "Time elapsed since the start of the forecast"; - cdf_put_att_text(fileID, leadtimeid, "long_name", sizeof(lname) - 1, lname); - } - - { - char unitstr[CDI_MAX_NAME]; - cdfDefForecastTimeUnits(unitstr, taxis->fc_unit); - size_t len = strlen(unitstr); - if ( len ) - cdf_put_att_text(fileID, leadtimeid, "units", len, unitstr); - } - } - - cdf_put_att_text(fileID, time_varid, "axis", 1, "T"); - - if ( streamptr->ncmode == 2 ) cdf_enddef(fileID); -} - - void cdfDefTimestep(stream_t *streamptr, int tsID) { int vlistID = streamptr->vlistID; @@ -336,69 +107,100 @@ void cdfDefTimestep(stream_t *streamptr, int tsID) static void cdfDefComplex(stream_t *streamptr, int gridID, int gridindex) { - int dimID = CDI_UNDEFID; - int fileID = streamptr->fileID; + int dimID; ncgrid_t *ncgrid = streamptr->ncgrid; for ( int index = 0; index < gridindex; ++index ) { - if ( ncgrid[index].xdimID != CDI_UNDEFID ) + if ( ncgrid[index].ncIDs[CDF_DIMID_X] != CDI_UNDEFID ) { int gridID0 = ncgrid[index].gridID; int gridtype0 = gridInqType(gridID0); if ( gridtype0 == GRID_SPECTRAL || gridtype0 == GRID_FOURIER ) { - dimID = ncgrid[index].xdimID; - break; + dimID = ncgrid[index].ncIDs[CDF_DIMID_X]; + goto dimIDEstablished; } } } - if ( dimID == CDI_UNDEFID ) - { - static const char axisname[] = "nc2"; - size_t dimlen = 2; - - if ( streamptr->ncmode == 2 ) cdf_redef(fileID); - cdf_def_dim(fileID, axisname, dimlen, &dimID); - cdf_enddef(fileID); - - streamptr->ncmode = 2; - } - + { + static const char axisname[] = "nc2"; + size_t dimlen = 2; + int fileID = streamptr->fileID; + + if ( streamptr->ncmode == 2 ) cdf_redef(fileID); + cdf_def_dim(fileID, axisname, dimlen, &dimID); + cdf_enddef(fileID); + streamptr->ncmode = 2; + } + dimIDEstablished: ncgrid[gridindex].gridID = gridID; - ncgrid[gridindex].xdimID = dimID; + ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID; } -static void -cdfDefSPorFC(stream_t *streamptr, int gridID, int gridindex, - char *restrict axisname, int gridRefType) +struct idSearch { - int iz = 0; - int dimID = CDI_UNDEFID; - ncgrid_t *ncgrid = streamptr->ncgrid; - - size_t dimlen = (size_t)gridInqSize(gridID)/2; + int numNonMatching, foundID; + size_t foundIdx; +}; - for ( int index = 0; index < gridindex; index++ ) +static inline struct idSearch +cdfSearchIDBySize(size_t startIdx, size_t numIDs, const ncgrid_t ncgrid[numIDs], + int ncIDType, int searchType, int searchSize, + int (*typeInq)(int id), int (*sizeInq)(int id)) +{ + int numNonMatching = 0, + foundID = CDI_UNDEFID; + size_t foundIdx = SIZE_MAX; + for ( size_t index = startIdx; index < numIDs; index++ ) { - if ( ncgrid[index].ydimID != CDI_UNDEFID ) + if ( ncgrid[index].ncIDs[ncIDType] != CDI_UNDEFID ) { - int gridID0 = ncgrid[index].gridID; - int gridtype0 = gridInqType(gridID0); - if ( gridtype0 == gridRefType ) + int id0 = ncgrid[index].gridID, + id0Type = typeInq(id0); + if ( id0Type == searchType ) { - size_t dimlen0 = (size_t)gridInqSize(gridID0)/2; - if ( dimlen == dimlen0 ) + int size0 = sizeInq(id0); + if ( searchSize == size0 ) { - dimID = ncgrid[index].ydimID; + foundID = ncgrid[index].ncIDs[ncIDType]; + foundIdx = index; break; } - else - iz++; + numNonMatching++; } } } + return (struct idSearch){ .numNonMatching = numNonMatching, + .foundID = foundID, .foundIdx = foundIdx }; +} + +static int +cdfGridInqHalfSize(int gridID) +{ + return gridInqSize(gridID)/2; +} + + +static void +cdfDefSPorFC(stream_t *streamptr, int gridID, int gridindex, + char *restrict axisname, int gridRefType) +{ + ncgrid_t *ncgrid = streamptr->ncgrid; + + size_t dimlen = (size_t)(gridInqSize(gridID))/2; + + int iz; + int dimID; + { + struct idSearch search + = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_Y, + gridRefType, (int)dimlen, + gridInqType, cdfGridInqHalfSize); + dimID = search.foundID; + iz = search.numNonMatching; + } if ( dimID == CDI_UNDEFID ) { @@ -415,7 +217,7 @@ cdfDefSPorFC(stream_t *streamptr, int gridID, int gridindex, } ncgrid[gridindex].gridID = gridID; - ncgrid[gridindex].ydimID = dimID; + ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = dimID; } static @@ -506,11 +308,8 @@ cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridindex, if ( dimlen != 1 ) Error("%c size isn't 1 for %s grid!", dimtype, gridNamePtr(gridInqType(gridID))); - int ncvarid = CDI_UNDEFID; - if ( dimtype == 'X' ) - ncvarid = ncgrid[gridindex].xdimID; - else - ncvarid = ncgrid[gridindex].ydimID; + int ncvarid + = ncgrid[gridindex].ncIDs[dimtype == 'X' ? CDF_DIMID_X : CDF_DIMID_Y]; if ( ncvarid == CDI_UNDEFID ) { @@ -528,10 +327,8 @@ cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridindex, } ncgrid[gridindex].gridID = gridID; - if ( dimtype == 'X' ) - ncgrid[gridindex].xdimID = ncvarid; /* var ID for trajectory !!! */ - else - ncgrid[gridindex].ydimID = ncvarid; /* var ID for trajectory !!! */ + /* var ID for trajectory !!! */ + ncgrid[gridindex].ncIDs[dimtype == 'X' ? CDF_DIMID_X : CDF_DIMID_Y] = ncvarid; } static @@ -690,7 +487,8 @@ cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims, if ( IS_EQUAL(inqVal(gridID0, 0), inqVal(gridID, 0)) && IS_EQUAL(inqVal(gridID0, (int)dimlen-1), inqVal(gridID, (int)dimlen-1)) ) { - dimID = (dimKey == CDI_KEY_XDIMNAME) ? ncgrid[index].xdimID : ncgrid[index].ydimID; + dimID = ncgrid[index].ncIDs[dimKey == CDI_KEY_XDIMNAME + ? CDF_DIMID_X : CDF_DIMID_Y]; break; } } @@ -773,19 +571,13 @@ cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims, if ( gen_bounds ) Free(pbounds); if ( ndims == 0 ) - { - if ( dimKey == CDI_KEY_XDIMNAME ) - ncgrid[gridindex].xvarID = ncvarid; - else - ncgrid[gridindex].yvarID = ncvarid; - } + ncgrid[gridindex].ncIDs[dimKey == CDI_KEY_XDIMNAME + ? CDF_VARID_X : CDF_VARID_Y] = ncvarid; } ncgrid[gridindex].gridID = gridID; - if ( dimKey == CDI_KEY_XDIMNAME ) - ncgrid[gridindex].xdimID = dimID; - else - ncgrid[gridindex].ydimID = dimID; + ncgrid[gridindex].ncIDs[dimKey == CDI_KEY_XDIMNAME + ? CDF_DIMID_X : CDF_DIMID_Y] = dimID; } static @@ -828,301 +620,16 @@ void cdfGridCompress(int fileID, int ncvarid, int gridsize, int filetype, int co #endif } -static -void cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex) -{ - int xdimID = CDI_UNDEFID; - int ydimID = CDI_UNDEFID; - int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID; - nc_type xtype = (nc_type)cdfDefDatatype(gridInqPrec(gridID), streamptr->filetype); - ncgrid_t *ncgrid = streamptr->ncgrid; - - int fileID = streamptr->fileID; - - size_t dimlen = (size_t)gridInqSize(gridID); - size_t xdimlen = (size_t)gridInqXsize(gridID); - size_t ydimlen = (size_t)gridInqYsize(gridID); - - for ( int index = 0; index < gridindex; index++ ) - { - if ( ncgrid[index].xdimID != CDI_UNDEFID ) - { - int gridID0 = ncgrid[index].gridID; - int gridtype0 = gridInqType(gridID0); - if ( gridtype0 == GRID_CURVILINEAR ) - { - size_t dimlen0 = (size_t)gridInqSize(gridID0); - if ( dimlen == dimlen0 ) - if ( IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0)) && - IS_EQUAL(gridInqXval(gridID0, (int)dimlen-1), gridInqXval(gridID, (int)dimlen-1)) && - IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0)) && - IS_EQUAL(gridInqYval(gridID0, (int)dimlen-1), gridInqYval(gridID, (int)dimlen-1)) ) - { - xdimID = ncgrid[index].xdimID; - ydimID = ncgrid[index].ydimID; - ncxvarid = ncgrid[index].xvarID; - ncyvarid = ncgrid[index].yvarID; - break; - } - } - } - } - - int ncbxvarid = CDI_UNDEFID, ncbyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID; - if ( xdimID == CDI_UNDEFID || ydimID == CDI_UNDEFID ) - { - if ( streamptr->ncmode == 2 ) cdf_redef(fileID); - { - char xdimname[CDI_MAX_NAME+3]; - xdimname[0] = 0; - cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, xdimname); - if ( xdimname[0] == 0 ) { xdimname[0] = 'x'; xdimname[1] = 0; } - xdimID = checkDimName(fileID, xdimlen, xdimname); - if ( xdimID == CDI_UNDEFID ) cdf_def_dim(fileID, xdimname, xdimlen, &xdimID); - } - { - char ydimname[CDI_MAX_NAME+3]; - ydimname[0] = 0; - cdiGridInqKeyStr(gridID, CDI_KEY_YDIMNAME, CDI_MAX_NAME, ydimname); - if ( ydimname[0] == 0 ) { ydimname[0] = 'y'; ydimname[1] = 0; } - ydimID = checkDimName(fileID, ydimlen, ydimname); - if ( ydimID == CDI_UNDEFID ) cdf_def_dim(fileID, ydimname, ydimlen, &ydimID); - } - - int nvdimID = CDI_UNDEFID; - int dimIDs[3]; - if ( gridInqXboundsPtr(gridID) || gridInqYboundsPtr(gridID) ) - { - char vdimname[CDI_MAX_NAME+3]; vdimname[0] = 0; - cdiGridInqKeyStr(gridID, CDI_KEY_VDIMNAME, CDI_MAX_NAME, vdimname); - if ( vdimname[0] == 0 ) strcpy(vdimname, "nv4"); - size_t nvertex = 4; - nvdimID = checkDimName(fileID, nvertex, vdimname); - if ( nvdimID == CDI_UNDEFID ) cdf_def_dim(fileID, vdimname, nvertex, &nvdimID); - } - - dimIDs[0] = ydimID; - dimIDs[1] = xdimID; - dimIDs[2] = nvdimID; - - if ( gridInqXvalsPtr(gridID) ) - { - char xaxisname[CDI_MAX_NAME]; xaxisname[0] = 0; - cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xaxisname); - checkGridName(xaxisname, fileID); - - cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncxvarid); - cdfGridCompress(fileID, ncxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype); - - cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X', &gridInqsX); - - /* attribute for Panoply */ - cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon"); - - if ( gridInqXboundsPtr(gridID) && nvdimID != CDI_UNDEFID ) - { - size_t xaxisnameLen = strlen(xaxisname); - xaxisname[xaxisnameLen] = '_'; - memcpy(xaxisname + xaxisnameLen + 1, bndsName, sizeof (bndsName)); - cdf_def_var(fileID, xaxisname, xtype, 3, dimIDs, &ncbxvarid); - cdfGridCompress(fileID, ncbxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype); - - cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname); - } - } - - if ( gridInqYvalsPtr(gridID) ) - { - char yaxisname[CDI_MAX_NAME]; - gridInqYname(gridID, yaxisname); - checkGridName(yaxisname, fileID); - - cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncyvarid); - cdfGridCompress(fileID, ncyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype); - - cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y', &gridInqsY); - - /* attribute for Panoply */ - cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat"); - - if ( gridInqYboundsPtr(gridID) && nvdimID != CDI_UNDEFID ) - { - size_t yaxisnameLen = strlen(yaxisname); - yaxisname[yaxisnameLen] = '_'; - memcpy(yaxisname + yaxisnameLen + 1, bndsName, sizeof (bndsName)); - cdf_def_var(fileID, yaxisname, xtype, 3, dimIDs, &ncbyvarid); - cdfGridCompress(fileID, ncbyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype); - - cdf_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname); - } - } - - if ( gridInqAreaPtr(gridID) ) - { - static const char yaxisname_[] = "cell_area"; - static const char units[] = "m2"; - static const char longname[] = "area of grid cell"; - static const char stdname[] = "cell_area"; - - cdf_def_var(fileID, yaxisname_, xtype, 2, dimIDs, &ncavarid); - - cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname); - cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname); - cdf_put_att_text(fileID, ncavarid, "units", sizeof (units) - 1, units); - } - - cdf_enddef(fileID); - streamptr->ncmode = 2; - - if ( ncxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncxvarid, gridInqXvalsPtr(gridID)); - if ( ncbxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, gridInqXboundsPtr(gridID)); - if ( ncyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncyvarid, gridInqYvalsPtr(gridID)); - if ( ncbyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, gridInqYboundsPtr(gridID)); - if ( ncavarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncavarid, gridInqAreaPtr(gridID)); - } - - ncgrid[gridindex].gridID = gridID; - ncgrid[gridindex].xdimID = xdimID; - ncgrid[gridindex].ydimID = ydimID; - ncgrid[gridindex].xvarID = ncxvarid; - ncgrid[gridindex].yvarID = ncyvarid; - ncgrid[gridindex].avarID = ncavarid; -} - -static -void cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex) -{ - ncgrid_t *ncgrid = streamptr->ncgrid; - int dimID = CDI_UNDEFID; - - size_t dimlen = (size_t)gridInqSize(gridID); - - int iz = 0; - for ( int index = 0; index < gridindex; index++ ) - { - if ( ncgrid[index].xdimID != CDI_UNDEFID ) - { - int gridID0 = ncgrid[index].gridID; - int gridtype0 = gridInqType(gridID0); - if ( gridtype0 == GRID_GAUSSIAN_REDUCED ) - { - size_t dimlen0 = (size_t)gridInqSize(gridID0); - - if ( dimlen == dimlen0 ) - { - dimID = ncgrid[index].xdimID; - break; - } - iz++; - } - } - } - - if ( dimID == CDI_UNDEFID ) - { - int fileID = streamptr->fileID; - static bool lwarn = true; - if ( lwarn ) - { - Warning("Creating a NetCDF file with data on a gaussian reduced grid."); - Warning("The further processing of the resulting file is unsupported!"); - lwarn = false; - } - - char axisname[7] = "rgridX"; - if ( iz == 0 ) axisname[5] = '\0'; - else sprintf(&axisname[5], "%1d", iz+1); - - if ( streamptr->ncmode == 2 ) cdf_redef(fileID); - - cdf_def_dim(fileID, axisname, dimlen, &dimID); - - cdf_enddef(fileID); - streamptr->ncmode = 2; - } - - ncgrid[gridindex].gridID = gridID; - ncgrid[gridindex].xdimID = dimID; -} - -static -void cdfDefGdim(stream_t *streamptr, int gridID, int gridindex) -{ - ncgrid_t *ncgrid = streamptr->ncgrid; - int iz = 0; - int dimID = CDI_UNDEFID; - - size_t dimlen = (size_t)gridInqSize(gridID); - - if ( gridInqYsize(gridID) == 0 ) - for ( int index = 0; index < gridindex; index++ ) - { - if ( ncgrid[index].xdimID != CDI_UNDEFID ) - { - int gridID0 = ncgrid[index].gridID; - int gridtype0 = gridInqType(gridID0); - if ( gridtype0 == GRID_GENERIC ) - { - size_t dimlen0 = (size_t)gridInqSize(gridID0); - if ( dimlen == dimlen0 ) - { - dimID = ncgrid[index].xdimID; - break; - } - else - iz++; - } - } - } - - if ( gridInqXsize(gridID) == 0 ) - for ( int index = 0; index < gridindex; index++ ) - { - if ( ncgrid[index].ydimID != CDI_UNDEFID ) - { - int gridID0 = ncgrid[index].gridID; - int gridtype0 = gridInqType(gridID0); - if ( gridtype0 == GRID_GENERIC ) - { - size_t dimlen0 = (size_t)gridInqSize(gridID0); - if ( dimlen == dimlen0 ) - { - dimID = ncgrid[index].ydimID; - break; - } - else - iz++; - } - } - } - - if ( dimID == CDI_UNDEFID ) - { - int fileID = streamptr->fileID; - char dimname[CDI_MAX_NAME]; - strcpy(dimname, "gsize"); - - dimID = checkDimName(fileID, dimlen, dimname); - - if ( streamptr->ncmode == 2 ) cdf_redef(fileID); - - if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID); - - cdf_enddef(fileID); - streamptr->ncmode = 2; - } - - ncgrid[gridindex].gridID = gridID; - ncgrid[gridindex].xdimID = dimID; -} - static void cdfDefGridReference(stream_t *streamptr, int gridID) { int fileID = streamptr->fileID; int number = gridInqNumber(gridID); + if ( number > 0 ) - cdf_put_att_int(fileID, NC_GLOBAL, "number_of_grid_used", NC_INT, 1, &number); + { + cdf_put_att_int(fileID, NC_GLOBAL, "number_of_grid_used", NC_INT, 1, &number); + } const char *gridfile = gridInqReferencePtr(gridID); if ( gridfile && gridfile[0] != 0 ) @@ -1149,174 +656,284 @@ void cdfDefGridUUID(stream_t *streamptr, int gridID) } } -static -void cdfDefZaxisUUID(stream_t *streamptr, int zaxisID) +struct cdfDefIrregularGridCommonIDs { - unsigned char uuidOfVGrid[CDI_UUID_SIZE]; - zaxisInqUUID(zaxisID, uuidOfVGrid); + int xdimID, ydimID, ncxvarid, ncyvarid, ncavarid; +}; - if ( uuidOfVGrid[0] != 0 ) +static struct cdfDefIrregularGridCommonIDs +cdfDefIrregularGridCommon(stream_t *streamptr, int gridID, + size_t xdimlen, size_t ydimlen, + int ndims, const char *xdimname_default, + size_t nvertex, const char *vdimname_default, + bool setVdimname) +{ + nc_type xtype = (nc_type)cdfDefDatatype(gridInqPrec(gridID), streamptr->filetype); + int xdimID = CDI_UNDEFID; + int ydimID = CDI_UNDEFID; + int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID; + int ncbxvarid = CDI_UNDEFID, ncbyvarid = CDI_UNDEFID; + int fileID = streamptr->fileID; + if ( streamptr->ncmode == 2 ) cdf_redef(fileID); + + { + char xdimname[CDI_MAX_NAME+3]; + xdimname[0] = 0; + cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, xdimname); + if ( xdimname[0] == 0 ) strcpy(xdimname, xdimname_default); + xdimID = checkDimName(fileID, xdimlen, xdimname); + if ( xdimID == CDI_UNDEFID ) cdf_def_dim(fileID, xdimname, xdimlen, &xdimID); + } + + if ( ndims == 3 ) + { + char ydimname[CDI_MAX_NAME+3]; + ydimname[0] = 0; + cdiGridInqKeyStr(gridID, CDI_KEY_YDIMNAME, CDI_MAX_NAME, ydimname); + if ( ydimname[0] == 0 ) { ydimname[0] = 'y'; ydimname[1] = 0; } + ydimID = checkDimName(fileID, ydimlen, ydimname); + if ( ydimID == CDI_UNDEFID ) cdf_def_dim(fileID, ydimname, ydimlen, &ydimID); + } + + int nvdimID = CDI_UNDEFID; + int dimIDs[3]; + dimIDs[ndims-1] = CDI_UNDEFID; + if ( setVdimname ) { - char uuidOfVGridStr[37]; - cdiUUID2Str(uuidOfVGrid, uuidOfVGridStr); - if ( uuidOfVGridStr[0] != 0 && strlen(uuidOfVGridStr) == 36 ) + char vdimname[CDI_MAX_NAME+3]; vdimname[0] = 0; + cdiGridInqKeyStr(gridID, CDI_KEY_VDIMNAME, CDI_MAX_NAME, vdimname); + if ( vdimname[0] == 0 ) strcpy(vdimname, vdimname_default); + nvdimID = dimIDs[ndims-1] = checkDimName(fileID, nvertex, vdimname); + if ( nvdimID == CDI_UNDEFID ) { - int fileID = streamptr->fileID; - if ( streamptr->ncmode == 2 ) cdf_redef(fileID); - cdf_put_att_text(fileID, NC_GLOBAL, "uuidOfVGrid", 36, uuidOfVGridStr); - if ( streamptr->ncmode == 2 ) cdf_enddef(fileID); + cdf_def_dim(fileID, vdimname, nvertex, dimIDs+ndims-1); + nvdimID = dimIDs[ndims-1]; } } -} -static -void cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex) -{ - int dimID = CDI_UNDEFID; - int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID; - int ncbxvarid = CDI_UNDEFID, ncbyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID; - int nvdimID = CDI_UNDEFID; - nc_type xtype = (nc_type)cdfDefDatatype(gridInqPrec(gridID), streamptr->filetype); - ncgrid_t *ncgrid = streamptr->ncgrid; + if ( ndims == 3 ) + { + dimIDs[0] = ydimID; + dimIDs[1] = xdimID; + } + else /* ndims == 2 */ + { + dimIDs[0] = xdimID; + cdfDefGridReference(streamptr, gridID); + cdfDefGridUUID(streamptr, gridID); + } - int fileID = streamptr->fileID; + const double *xvalsPtr = gridInqXvalsPtr(gridID), + *xboundsPtr = NULL; + if ( xvalsPtr ) + { + char xaxisname[CDI_MAX_NAME]; xaxisname[0] = 0; + cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xaxisname); + checkGridName(xaxisname, fileID); + cdf_def_var(fileID, xaxisname, xtype, ndims-1, dimIDs, &ncxvarid); + cdfGridCompress(fileID, ncxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype); - size_t dimlen = (size_t)gridInqSize(gridID); + cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X', &gridInqsX); - for ( int index = 0; index < gridindex; index++ ) - { - if ( ncgrid[index].xdimID != CDI_UNDEFID ) + /* attribute for Panoply */ + if ( ndims == 3 ) + cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon"); + + if ( (xboundsPtr = gridInqXboundsPtr(gridID)) && nvdimID != CDI_UNDEFID ) { - int gridID0 = ncgrid[index].gridID; - int gridtype0 = gridInqType(gridID0); - if ( gridtype0 == GRID_UNSTRUCTURED ) - { - size_t dimlen0 = (size_t)gridInqSize(gridID0); - if ( dimlen == dimlen0 ) - if ( gridInqNvertex(gridID0) == gridInqNvertex(gridID) && - IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0)) && - IS_EQUAL(gridInqXval(gridID0, (int)dimlen-1), gridInqXval(gridID, (int)dimlen-1)) && - IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0)) && - IS_EQUAL(gridInqYval(gridID0, (int)dimlen-1), gridInqYval(gridID, (int)dimlen-1)) ) - { - dimID = ncgrid[index].xdimID; - ncxvarid = ncgrid[index].xvarID; - ncyvarid = ncgrid[index].yvarID; - ncavarid = ncgrid[index].avarID; - break; - } - } + size_t xaxisnameLen = strlen(xaxisname); + xaxisname[xaxisnameLen] = '_'; + memcpy(xaxisname + xaxisnameLen + 1, bndsName, sizeof (bndsName)); + cdf_def_var(fileID, xaxisname, xtype, ndims, dimIDs, &ncbxvarid); + cdfGridCompress(fileID, ncbxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype); + + cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname); } } - if ( dimID == CDI_UNDEFID ) + const double *yvalsPtr = gridInqYvalsPtr(gridID), + *yboundsPtr = NULL; + if ( yvalsPtr ) { - if ( streamptr->ncmode == 2 ) cdf_redef(fileID); - { - char xdimname[CDI_MAX_NAME+3]; - xdimname[0] = 0; - cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, xdimname); - if ( xdimname[0] == 0 ) strcpy(xdimname, "ncells"); - dimID = checkDimName(fileID, dimlen, xdimname); - if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, xdimname, dimlen, &dimID); - } + char yaxisname[CDI_MAX_NAME]; + gridInqYname(gridID, yaxisname); + checkGridName(yaxisname, fileID); - size_t nvertex = (size_t)gridInqNvertex(gridID); - if ( nvertex > 0 ) + cdf_def_var(fileID, yaxisname, xtype, ndims - 1, dimIDs, &ncyvarid); + cdfGridCompress(fileID, ncyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype); + + cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y', &gridInqsY); + + /* attribute for Panoply */ + if ( ndims == 3 ) + cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat"); + + if ( (yboundsPtr = gridInqYboundsPtr(gridID)) && nvdimID != CDI_UNDEFID ) { - char vdimname[CDI_MAX_NAME+3]; - vdimname[0] = 0; - cdiGridInqKeyStr(gridID, CDI_KEY_VDIMNAME, CDI_MAX_NAME, vdimname); - if ( vdimname[0] == 0 ) strcpy(vdimname, "vertices"); - nvdimID = checkDimName(fileID, nvertex, vdimname); - if ( nvdimID == CDI_UNDEFID ) cdf_def_dim(fileID, vdimname, nvertex, &nvdimID); + size_t yaxisnameLen = strlen(yaxisname); + yaxisname[yaxisnameLen] = '_'; + memcpy(yaxisname + yaxisnameLen + 1, bndsName, sizeof (bndsName)); + cdf_def_var(fileID, yaxisname, xtype, ndims, dimIDs, &ncbyvarid); + cdfGridCompress(fileID, ncbyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype); + + cdf_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname); } + } - cdfDefGridReference(streamptr, gridID); + const double *areaPtr = gridInqAreaPtr(gridID); + if ( areaPtr ) + { + static const char yaxisname_[] = "cell_area"; + static const char units[] = "m2"; + static const char longname[] = "area of grid cell"; + static const char stdname[] = "cell_area"; - cdfDefGridUUID(streamptr, gridID); + cdf_def_var(fileID, yaxisname_, xtype, ndims-1, dimIDs, &ncavarid); - const double *xvalsPtr = gridInqXvalsPtr(gridID), - *xboundsPtr = NULL; - if ( xvalsPtr ) - { - char xaxisname[CDI_MAX_NAME]; xaxisname[0] = 0; - cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xaxisname); - checkGridName(xaxisname, fileID); - cdf_def_var(fileID, xaxisname, xtype, 1, &dimID, &ncxvarid); - cdfGridCompress(fileID, ncxvarid, (int)dimlen, streamptr->filetype, streamptr->comptype); + cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname); + cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname); + cdf_put_att_text(fileID, ncavarid, "units", sizeof (units) - 1, units); + } - cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X', &gridInqsX); + cdf_enddef(fileID); + streamptr->ncmode = 2; - if ( (xboundsPtr = gridInqXboundsPtr(gridID)) && nvdimID != CDI_UNDEFID ) - { - int dimIDs[2] = { dimID, nvdimID }; - size_t xaxisnameLen = strlen(xaxisname); - xaxisname[xaxisnameLen] = '_'; - memcpy(xaxisname + xaxisnameLen + 1, bndsName, sizeof (bndsName)); - cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncbxvarid); - cdfGridCompress(fileID, ncbxvarid, (int)dimlen, streamptr->filetype, streamptr->comptype); + if ( ncxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncxvarid, xvalsPtr); + if ( ncbxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, xboundsPtr); + if ( ncyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncyvarid, yvalsPtr); + if ( ncbyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, yboundsPtr); + if ( ncavarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncavarid, areaPtr); - cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname); - } - } + return (struct cdfDefIrregularGridCommonIDs) { + .xdimID=xdimID, .ydimID = ydimID, + .ncxvarid=ncxvarid, .ncyvarid=ncyvarid, .ncavarid=ncavarid + }; +} - const double *yvalsPtr = gridInqYvalsPtr(gridID), - *yboundsPtr = NULL; - if ( yvalsPtr ) - { - char yaxisname[CDI_MAX_NAME]; - gridInqYname(gridID, yaxisname); - checkGridName(yaxisname, fileID); - cdf_def_var(fileID, yaxisname, xtype, 1, &dimID, &ncyvarid); - cdfGridCompress(fileID, ncyvarid, (int)dimlen, streamptr->filetype, streamptr->comptype); +static +void cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex) +{ + ncgrid_t *ncgrid = streamptr->ncgrid; - cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y', &gridInqsY); + size_t dimlen = (size_t)gridInqSize(gridID); + size_t xdimlen = (size_t)gridInqXsize(gridID); + size_t ydimlen = (size_t)gridInqYsize(gridID); - if ( (yboundsPtr = gridInqYboundsPtr(gridID)) - && nvdimID != CDI_UNDEFID ) + int xdimID = CDI_UNDEFID, ydimID = CDI_UNDEFID; + int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID; + { + size_t ofs = 0; + do { + struct idSearch search + = cdfSearchIDBySize(ofs, (size_t)gridindex, ncgrid, CDF_DIMID_X, + GRID_CURVILINEAR, (int)dimlen, + gridInqType, gridInqSize); + size_t index = search.foundIdx; + if ( index != SIZE_MAX ) + { + int gridID0 = ncgrid[index].gridID; + if ( IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0)) + && IS_EQUAL(gridInqXval(gridID0, (int)dimlen-1), + gridInqXval(gridID, (int)dimlen-1)) + && IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0)) + && IS_EQUAL(gridInqYval(gridID0, (int)dimlen-1), + gridInqYval(gridID, (int)dimlen-1)) ) { - int dimIDs[2] = { dimID, nvdimID }; - size_t yaxisnameLen = strlen(yaxisname); - yaxisname[yaxisnameLen] = '_'; - memcpy(yaxisname + yaxisnameLen + 1, bndsName, sizeof (bndsName)); - cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncbyvarid); - cdfGridCompress(fileID, ncbyvarid, (int)dimlen, streamptr->filetype, streamptr->comptype); - - cdf_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname); + xdimID = ncgrid[index].ncIDs[CDF_DIMID_X]; + ydimID = ncgrid[index].ncIDs[CDF_DIMID_Y]; + ncxvarid = ncgrid[index].ncIDs[CDF_VARID_X]; + ncyvarid = ncgrid[index].ncIDs[CDF_VARID_Y]; + break; } + ofs = search.foundIdx; + if ( ofs < (size_t)gridindex ) + continue; } + } while (false); + } - const double *areaPtr = gridInqAreaPtr(gridID); - if ( areaPtr ) - { - static const char yaxisname_[] = "cell_area"; - static const char units[] = "m2"; - static const char longname[] = "area of grid cell"; - static const char stdname[] = "cell_area"; + if ( xdimID == CDI_UNDEFID || ydimID == CDI_UNDEFID ) + { + struct cdfDefIrregularGridCommonIDs createdIDs + = cdfDefIrregularGridCommon(streamptr, gridID, + xdimlen, ydimlen, 3, "x", 4, "nv4", + gridInqXboundsPtr(gridID) + || gridInqYboundsPtr(gridID)); + xdimID = createdIDs.xdimID; + ydimID = createdIDs.ydimID; + ncxvarid = createdIDs.ncxvarid; + ncyvarid = createdIDs.ncyvarid; + ncavarid = createdIDs.ncavarid; + } - cdf_def_var(fileID, yaxisname_, xtype, 1, &dimID, &ncavarid); + ncgrid[gridindex].gridID = gridID; + ncgrid[gridindex].ncIDs[CDF_DIMID_X] = xdimID; + ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = ydimID; + ncgrid[gridindex].ncIDs[CDF_VARID_X] = ncxvarid; + ncgrid[gridindex].ncIDs[CDF_VARID_Y] = ncyvarid; + ncgrid[gridindex].ncIDs[CDF_VARID_A] = ncavarid; +} - cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname); - cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname); - cdf_put_att_text(fileID, ncavarid, "units", sizeof (units) - 1, units); - } - cdf_enddef(fileID); - streamptr->ncmode = 2; +static +void cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex) +{ + ncgrid_t *ncgrid = streamptr->ncgrid; + + size_t dimlen = (size_t)gridInqSize(gridID); + + int dimID = CDI_UNDEFID; + int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID; + { + size_t ofs = 0; + do { + struct idSearch search + = cdfSearchIDBySize(ofs, (size_t)gridindex, ncgrid, CDF_DIMID_X, + GRID_UNSTRUCTURED, (int)dimlen, + gridInqType, gridInqSize); + size_t index = search.foundIdx; + if ( index != SIZE_MAX ) + { + int gridID0 = ncgrid[index].gridID; + if ( gridInqNvertex(gridID0) == gridInqNvertex(gridID) && + IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0)) && + IS_EQUAL(gridInqXval(gridID0, (int)dimlen-1), + gridInqXval(gridID, (int)dimlen-1)) && + IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0)) && + IS_EQUAL(gridInqYval(gridID0, (int)dimlen-1), + gridInqYval(gridID, (int)dimlen-1)) ) + { + dimID = ncgrid[index].ncIDs[CDF_DIMID_X]; + ncxvarid = ncgrid[index].ncIDs[CDF_VARID_X]; + ncyvarid = ncgrid[index].ncIDs[CDF_VARID_Y]; + ncavarid = ncgrid[index].ncIDs[CDF_VARID_A]; + break; + } + ofs = search.foundIdx; + if ( ofs < (size_t)gridindex ) + continue; + } + } while (false); + } - if ( ncxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncxvarid, xvalsPtr); - if ( ncbxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, xboundsPtr); - if ( ncyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncyvarid, yvalsPtr); - if ( ncbyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, yboundsPtr); - if ( ncavarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncavarid, areaPtr); + if ( dimID == CDI_UNDEFID ) + { + size_t nvertex = (size_t)gridInqNvertex(gridID); + struct cdfDefIrregularGridCommonIDs createdIDs + = cdfDefIrregularGridCommon(streamptr, gridID, + dimlen, 1, 2, "ncells", + nvertex, "vertices", nvertex > 0); + dimID = createdIDs.xdimID; + ncxvarid = createdIDs.ncxvarid; + ncyvarid = createdIDs.ncyvarid; + ncavarid = createdIDs.ncavarid; } ncgrid[gridindex].gridID = gridID; - ncgrid[gridindex].xdimID = dimID; - ncgrid[gridindex].xvarID = ncxvarid; - ncgrid[gridindex].yvarID = ncyvarid; - ncgrid[gridindex].avarID = ncavarid; + ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID; + ncgrid[gridindex].ncIDs[CDF_VARID_X] = ncxvarid; + ncgrid[gridindex].ncIDs[CDF_VARID_Y] = ncyvarid; + ncgrid[gridindex].ncIDs[CDF_VARID_A] = ncavarid; } struct attTxtTab2 @@ -1557,10 +1174,9 @@ void cdf_def_zaxis_hybrid_echam(stream_t *streamptr, int type, int *ncvaridp, in if ( streamptr->ncmode == 2 ) cdf_redef(fileID); - int ncvarid; cdf_def_dim(fileID, axisname, dimlen, dimID); - cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID, &ncvarid); - *ncvaridp = ncvarid; + cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID, ncvaridp); + int ncvarid = *ncvaridp; { static const char sname[] = "hybrid_sigma_pressure"; @@ -1615,12 +1231,8 @@ void cdf_def_zaxis_hybrid_echam(stream_t *streamptr, int type, int *ncvaridp, in cdf_def_vct_echam(streamptr, zaxisID); if ( *dimID == CDI_UNDEFID ) - { - if ( type == ZAXIS_HYBRID ) - streamptr->zaxisID[zaxisindex] = streamptr->vct.mlevID; - else - streamptr->zaxisID[zaxisindex] = streamptr->vct.ilevID; - } + streamptr->zaxisID[zaxisindex] = type == ZAXIS_HYBRID + ? streamptr->vct.mlevID : streamptr->vct.ilevID; } static @@ -1658,10 +1270,9 @@ void cdf_def_zaxis_hybrid_cf(stream_t *streamptr, int type, int *ncvaridp, int z if ( zlongname[0] == 0 ) strcpy(zlongname, "hybrid sigma pressure coordinate"); if ( zunits[0] == 0 ) strcpy(zunits, "1"); - int ncvarid; cdf_def_dim(fileID, axisname, dimlen, dimID); - cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID, &ncvarid); - *ncvaridp = ncvarid; + cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID, ncvaridp); + int ncvarid = *ncvaridp; { static const char sname[] = "standard_name", @@ -1769,21 +1380,38 @@ void cdf_def_zaxis_hybrid_cf(stream_t *streamptr, int type, int *ncvaridp, int z cdf_def_vct_cf(streamptr, zaxisID, *dimID, nvdimID, p0status, p0value); if ( *dimID == CDI_UNDEFID ) - { - if ( type == ZAXIS_HYBRID ) - streamptr->zaxisID[zaxisindex] = streamptr->vct.mlevID; - else - streamptr->zaxisID[zaxisindex] = streamptr->vct.ilevID; - } + streamptr->zaxisID[zaxisindex] = type == ZAXIS_HYBRID + ? streamptr->vct.mlevID : streamptr->vct.ilevID; } static void cdf_def_zaxis_hybrid(stream_t *streamptr, int type, int *ncvarid, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname) { - if ( (!CDI_cmor_mode && cdiConvention == CDI_CONVENTION_ECHAM) || type == ZAXIS_HYBRID_HALF ) - cdf_def_zaxis_hybrid_echam(streamptr, type, ncvarid, zaxisID, zaxisindex, xtype, dimlen, dimID, axisname); - else - cdf_def_zaxis_hybrid_cf(streamptr, type, ncvarid, zaxisID, zaxisindex, xtype, dimlen, dimID, axisname); + void (*def_zaxis_hybrid_delegate)(stream_t *streamptr, int type, int *ncvarid, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname) + = ( (!CDI_cmor_mode && cdiConvention == CDI_CONVENTION_ECHAM) + || type == ZAXIS_HYBRID_HALF ) + ? cdf_def_zaxis_hybrid_echam : cdf_def_zaxis_hybrid_cf; + def_zaxis_hybrid_delegate(streamptr, type, ncvarid, zaxisID, zaxisindex, xtype, dimlen, dimID, axisname); +} + +static +void cdfDefZaxisUUID(stream_t *streamptr, int zaxisID) +{ + unsigned char uuidOfVGrid[CDI_UUID_SIZE]; + zaxisInqUUID(zaxisID, uuidOfVGrid); + + if ( uuidOfVGrid[0] != 0 ) + { + char uuidOfVGridStr[37]; + cdiUUID2Str(uuidOfVGrid, uuidOfVGridStr); + if ( uuidOfVGridStr[0] != 0 && strlen(uuidOfVGridStr) == 36 ) + { + int fileID = streamptr->fileID; + if ( streamptr->ncmode == 2 ) cdf_redef(fileID); + cdf_put_att_text(fileID, NC_GLOBAL, "uuidOfVGrid", 36, uuidOfVGridStr); + if ( streamptr->ncmode == 2 ) cdf_enddef(fileID); + } + } } static @@ -1792,12 +1420,8 @@ void cdfDefZaxis(stream_t *streamptr, int zaxisID) /* char zaxisname0[CDI_MAX_NAME]; */ char axisname[CDI_MAX_NAME]; int dimID = CDI_UNDEFID; - int dimIDs[2]; int ncvarid = CDI_UNDEFID, ncbvarid = CDI_UNDEFID; - int nvdimID = CDI_UNDEFID; - int xtype = NC_DOUBLE; - - if ( zaxisInqPrec(zaxisID) == CDI_DATATYPE_FLT32 ) xtype = NC_FLOAT; + int xtype = zaxisInqPrec(zaxisID) == CDI_DATATYPE_FLT32 ? NC_FLOAT : NC_DOUBLE; int vlistID = streamptr->vlistID; int fileID = streamptr->fileID; @@ -1820,8 +1444,7 @@ void cdfDefZaxis(stream_t *streamptr, int zaxisID) } } - int ndims = 1; - if ( is_scalar ) ndims = 0; + int ndims = is_scalar ? 0 : 1; if ( dimlen == 1 ) switch (type) @@ -1896,6 +1519,7 @@ void cdfDefZaxis(stream_t *streamptr, int zaxisID) if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) ) { + int nvdimID = CDI_UNDEFID; size_t nvertex = 2; if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR ) cdf_def_dim(fileID, bndsName, nvertex, &nvdimID); @@ -1905,6 +1529,7 @@ void cdfDefZaxis(stream_t *streamptr, int zaxisID) size_t axisnameLen = strlen(axisname); axisname[axisnameLen] = '_'; memcpy(axisname + axisnameLen + 1, bndsName, sizeof (bndsName)); + int dimIDs[2]; dimIDs[0] = dimID; dimIDs[ndims] = nvdimID; cdf_def_var(fileID, axisname, (nc_type) xtype, ndims+1, dimIDs, &ncbvarid); @@ -1973,10 +1598,212 @@ void cdf_def_mapping(stream_t *streamptr, int gridID) } } +static +void cdfDefCharacter(stream_t *streamptr, int gridID, int gridindex, int xory, int strlen) +{ + if ( streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID ) return; + + int dimlen = ( xory == 0 ) ? gridInqXsize(gridID) : gridInqYsize(gridID); + int dimID, strlenID; + ncgrid_t *ncgrid = streamptr->ncgrid; + + /* Check for all grids up to gridindex whether it already is defined */ + + for ( int index = 0; index < gridindex; index++ ) + { + int gridID0 = ncgrid[index].gridID; + int gridtype0 = gridInqType(gridID0); + if ( gridtype0 == GRID_CHARXY ) + { + if ( gridInqXIsc(gridID0) == strlen && + gridInqXsize(gridID0) == dimlen ) + return; + else if ( gridInqYIsc(gridID0) == strlen && + gridInqYsize(gridID0) == dimlen ) + return; + } + } + + int fileID = streamptr->fileID; + + if ( streamptr->ncmode == 2 ) cdf_redef(fileID); + +/* Define Dims */ + + char dimname[CDI_MAX_NAME+3]; + dimname[0] = 0; + if ( xory == 0 ) + cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, dimname); + else + cdiGridInqKeyStr(gridID, CDI_KEY_YDIMNAME, CDI_MAX_NAME, dimname); + if ( dimname[0] == 0 ) { memcpy(dimname, "region", 7); dimname[6] = 0; } + dimID = checkDimName(fileID, dimlen, dimname); + if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID); + +/* Define strlength dim */ + + strcpy(dimname, "strlen"); + strlenID = checkDimName(fileID, strlen, dimname); + if ( strlenID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, strlen, &strlenID); + +/* Define Variable */ + + int dimIDs[2]; + dimIDs[0] = dimID; + dimIDs[1] = strlenID; + + char axisname[CDI_MAX_NAME]; axisname[0] = 0; + char **cvals = (char **) Malloc(dimlen * sizeof(char *)); + for ( int i = 0; i < dimlen; i++ ) + cvals[i] = Malloc(strlen * sizeof(char) ); + int ncaxisid; + if ( xory == 0 ) + { + cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, axisname); + gridInqXCvals(gridID, cvals); + } + else + { + cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, axisname); + gridInqXCvals(gridID, cvals); + } + int status = nc_inq_varid(fileID, axisname, &ncaxisid); + if ( status != NC_NOERR ) + { + cdf_def_var(fileID, axisname, NC_CHAR, 2, dimIDs, &ncaxisid); + if ( xory == 0 ) + cdfPutGridStdAtts(fileID, ncaxisid, gridID, 'X', &gridInqsX); + else + cdfPutGridStdAtts(fileID, ncaxisid, gridID, 'Y', &gridInqsY); + } + else + return; + cdf_enddef(fileID); + +/* Write Var */ + + size_t start[2], count[2]; + start[1] = 0; + count[0] = 1; + count[1] = strlen; + for (int i = 0; i < dimlen; i++) + { + start[0] = i; + status = nc_put_vara_text(fileID, ncaxisid, start, count, cvals[i]); + } + + ncgrid[gridindex].gridID = gridID; + if ( xory == 0 ) + { + ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID; + ncgrid[gridindex].ncIDs[CDF_VARID_X] = ncaxisid; + } + else + { + ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = dimID; + ncgrid[gridindex].ncIDs[CDF_VARID_Y] = ncaxisid; + } + streamptr->ncmode = 2; +} + +static +void cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex) +{ + ncgrid_t *ncgrid = streamptr->ncgrid; + + size_t dimlen = (size_t)gridInqSize(gridID); + + int iz; + int dimID; + { + struct idSearch search + = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_X, + GRID_GAUSSIAN_REDUCED, (int)dimlen, + gridInqType, gridInqSize); + iz = search.numNonMatching; + dimID = search.foundID; + } + + if ( dimID == CDI_UNDEFID ) + { + int fileID = streamptr->fileID; + static bool lwarn = true; + if ( lwarn ) + { + Warning("Creating a NetCDF file with data on a gaussian reduced grid."); + Warning("The further processing of the resulting file is unsupported!"); + lwarn = false; + } + + char axisname[7] = "rgridX"; + if ( iz == 0 ) axisname[5] = '\0'; + else sprintf(&axisname[5], "%1d", iz+1); + + if ( streamptr->ncmode == 2 ) cdf_redef(fileID); + + cdf_def_dim(fileID, axisname, dimlen, &dimID); + + cdf_enddef(fileID); + streamptr->ncmode = 2; + } + + ncgrid[gridindex].gridID = gridID; + ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID; +} + +static +void cdfDefGdim(stream_t *streamptr, int gridID, int gridindex) +{ + ncgrid_t *ncgrid = streamptr->ncgrid; + int iz = 0; + int dimID = CDI_UNDEFID; + + size_t dimlen = (size_t)gridInqSize(gridID); + + if ( gridInqYsize(gridID) == 0 ) + { + struct idSearch search + = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_X, + GRID_GENERIC, (int)dimlen, + gridInqType, gridInqSize); + iz = search.numNonMatching; + dimID = search.foundID; + } + + if ( gridInqXsize(gridID) == 0 ) + { + struct idSearch search + = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_Y, + GRID_GENERIC, (int)dimlen, + gridInqType, gridInqSize); + iz += search.numNonMatching; + dimID = search.foundID; + } + + if ( dimID == CDI_UNDEFID ) + { + int fileID = streamptr->fileID; + char dimname[CDI_MAX_NAME]; + strcpy(dimname, "gsize"); + + dimID = checkDimName(fileID, dimlen, dimname); + + if ( streamptr->ncmode == 2 ) cdf_redef(fileID); + + if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID); + + cdf_enddef(fileID); + streamptr->ncmode = 2; + } + + ncgrid[gridindex].gridID = gridID; + ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID; +} + static void cdfDefGrid(stream_t *streamptr, int gridID, int gridindex) { - if ( streamptr->ncgrid[gridindex].xdimID != CDI_UNDEFID ) return; + if ( streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID ) return; int gridtype = gridInqType(gridID); int size = gridInqSize(gridID); @@ -2016,9 +1843,8 @@ void cdfDefGrid(stream_t *streamptr, int gridID, int gridindex) } else { - int ndims = 1; - if ( gridtype == GRID_LONLAT && size == 1 && gridInqHasDims(gridID) == FALSE ) - ndims = 0; + int ndims = !( gridtype == GRID_LONLAT && size == 1 + && gridInqHasDims(gridID) == FALSE ); if ( gridInqXsize(gridID) > 0 ) cdfDefXaxis(streamptr, gridID, gridindex, ndims); if ( gridInqYsize(gridID) > 0 ) cdfDefYaxis(streamptr, gridID, gridindex, ndims); @@ -2053,6 +1879,18 @@ void cdfDefGrid(stream_t *streamptr, int gridID, int gridindex) cdfDefTrajLon(streamptr, gridID, gridindex); cdfDefTrajLat(streamptr, gridID, gridindex); } + else if ( gridtype == GRID_CHARXY ) + { + int strlen = 0; + if ( (strlen = gridInqXIsc(gridID)) ) + cdfDefCharacter(streamptr, gridID, gridindex, 0, strlen); + else + if ( gridInqXsize(gridID) > 0 ) cdfDefXaxis(streamptr, gridID, gridindex, 1); + if ( (strlen = gridInqYIsc(gridID)) ) + cdfDefCharacter(streamptr, gridID, gridindex, 1, strlen); + else + if ( gridInqYsize(gridID) > 0 ) cdfDefYaxis(streamptr, gridID, gridindex, 1); + } else { Error("Unsupported grid type: %s", gridNamePtr(gridtype)); @@ -2078,11 +1916,8 @@ void cdfDefVars(stream_t *streamptr) for ( int index = 0; index < 2*ngrids; ++index ) { streamptr->ncgrid[index].gridID = CDI_UNDEFID; - streamptr->ncgrid[index].xdimID = CDI_UNDEFID; - streamptr->ncgrid[index].ydimID = CDI_UNDEFID; - streamptr->ncgrid[index].xvarID = CDI_UNDEFID; - streamptr->ncgrid[index].yvarID = CDI_UNDEFID; - streamptr->ncgrid[index].avarID = CDI_UNDEFID; + for (size_t i = 0; i < CDF_SIZE_ncIDs; ++i) + streamptr->ncgrid[index].ncIDs[i] = CDI_UNDEFID; } for ( int index = 0; index < ngrids; ++index ) diff --git a/src/stream_cdf_time.c b/src/stream_cdf_time.c new file mode 100644 index 0000000000000000000000000000000000000000..dd9d35bd33d61b7654b7936500068bcaa2167d91 --- /dev/null +++ b/src/stream_cdf_time.c @@ -0,0 +1,253 @@ +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#ifdef HAVE_LIBNETCDF + +# include <stdio.h> +# include <string.h> + +# include <netcdf.h> + +# include "cdi.h" +# include "cdi_int.h" +# include "stream_cdf.h" +# include "cdf_int.h" + +static +int cdfDefTimeBounds(int fileID, int nctimevarid, int nctimedimid, const char *taxis_name, taxis_t* taxis) +{ + int time_bndsid = -1; + int dims[2]; + + dims[0] = nctimedimid; + + /* fprintf(stderr, "time has bounds\n"); */ + static const char bndsName[] = "bnds"; + if ( nc_inq_dimid(fileID, bndsName, &dims[1]) != NC_NOERR ) + cdf_def_dim(fileID, bndsName, 2, &dims[1]); + + const char *bndsAttName, *bndsAttVal; + size_t bndsAttValLen; + char tmpstr[CDI_MAX_NAME]; + if ( taxis->climatology ) + { + static const char climatology_bndsName[] = "climatology_bnds", + climatology_bndsAttName[] = "climatology"; + bndsAttName = climatology_bndsAttName; + bndsAttValLen = sizeof (climatology_bndsName) - 1; + bndsAttVal = climatology_bndsName; + } + else + { + size_t taxisnameLen = strlen(taxis_name); + memcpy(tmpstr, taxis_name, taxisnameLen); + tmpstr[taxisnameLen] = '_'; + memcpy(tmpstr + taxisnameLen + 1, bndsName, sizeof (bndsName)); + size_t tmpstrLen = taxisnameLen + sizeof (bndsName); + static const char generic_bndsAttName[] = "bounds"; + bndsAttName = generic_bndsAttName; + bndsAttValLen = tmpstrLen; + bndsAttVal = tmpstr; + } + cdf_def_var(fileID, bndsAttVal, NC_DOUBLE, 2, dims, &time_bndsid); + cdf_put_att_text(fileID, nctimevarid, bndsAttName, bndsAttValLen, bndsAttVal); + + return time_bndsid; +} + +static +void cdfDefTimeUnits(char *unitstr, taxis_t* taxis0, taxis_t* taxis) +{ + if ( taxis->units && taxis->units[0] ) + { + strcpy(unitstr, taxis->units); + } + else + { + unitstr[0] = 0; + + if ( taxis0->type == TAXIS_ABSOLUTE ) + { + static const char *const unitstrfmt[3] + = { "year as %Y.%f", + "month as %Y%m.%f", + "day as %Y%m%d.%f" }; + size_t fmtidx = (taxis0->unit == TUNIT_YEAR ? 0 + : (taxis0->unit == TUNIT_MONTH ? 1 + : 2)); + strcpy(unitstr, unitstrfmt[fmtidx]); + } + else + { + int timeunit = taxis->unit != -1 ? taxis->unit : TUNIT_HOUR; + int rdate = taxis->rdate != -1 ? taxis->rdate : taxis->vdate; + int rtime = taxis->rdate != -1 ? taxis->rtime : taxis->vtime; + int year, month, day, hour, minute, second; + cdiDecodeDate(rdate, &year, &month, &day); + cdiDecodeTime(rtime, &hour, &minute, &second); + + if ( timeunit == TUNIT_QUARTER ) timeunit = TUNIT_MINUTE; + else if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE; + else if ( timeunit == TUNIT_3HOURS + || timeunit == TUNIT_6HOURS + || timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR; + + sprintf(unitstr, "%s since %d-%d-%d %02d:%02d:%02d", + tunitNamePtr(timeunit), year, month, day, hour, minute, second); + } + } +} + +static +void cdfDefForecastTimeUnits(char *unitstr, int timeunit) +{ + unitstr[0] = 0; + + if ( timeunit == -1 ) timeunit = TUNIT_HOUR; + else if ( timeunit == TUNIT_QUARTER ) timeunit = TUNIT_MINUTE; + else if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE; + else if ( timeunit == TUNIT_3HOURS + || timeunit == TUNIT_6HOURS + || timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR; + + strcpy(unitstr, tunitNamePtr(timeunit)); +} + +static +void cdfDefCalendar(int fileID, int ncvarid, int calendar) +{ + static const struct { int calCode; const char *calStr; } calTab[] = { + { CALENDAR_STANDARD, "standard" }, + { CALENDAR_PROLEPTIC, "proleptic_gregorian" }, + { CALENDAR_NONE, "none" }, + { CALENDAR_360DAYS, "360_day" }, + { CALENDAR_365DAYS, "365_day" }, + { CALENDAR_366DAYS, "366_day" }, + }; + enum { calTabSize = sizeof calTab / sizeof calTab[0] }; + + for ( size_t i = 0; i < calTabSize; ++i ) + if ( calTab[i].calCode == calendar ) + { + const char *calstr = calTab[i].calStr; + size_t len = strlen(calstr); + cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr); + break; + } +} + + +void cdfDefTime(stream_t* streamptr) +{ + int time_varid; + int time_dimid; + int time_bndsid = -1; + static const char default_name[] = "time"; + + if ( streamptr->basetime.ncvarid != CDI_UNDEFID ) return; + + int fileID = streamptr->fileID; + + if ( streamptr->ncmode == 0 ) streamptr->ncmode = 1; + if ( streamptr->ncmode == 2 ) cdf_redef(fileID); + + taxis_t *taxis = &streamptr->tsteps[0].taxis; + + const char *taxis_name = (taxis->name && taxis->name[0]) ? taxis->name : default_name ; + + cdf_def_dim(fileID, taxis_name, NC_UNLIMITED, &time_dimid); + streamptr->basetime.ncdimid = time_dimid; + + nc_type xtype = (taxis->datatype == CDI_DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE; + + cdf_def_var(fileID, taxis_name, xtype, 1, &time_dimid, &time_varid); + + streamptr->basetime.ncvarid = time_varid; + +#if defined (HAVE_NETCDF4) + if ( streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C ) + { + size_t chunk = 512; + cdf_def_var_chunking(fileID, time_varid, NC_CHUNKED, &chunk); + } +#endif + + { + static const char timeStr[] = "time"; + cdf_put_att_text(fileID, time_varid, "standard_name", sizeof(timeStr) - 1, timeStr); + } + + if ( taxis->longname && taxis->longname[0] ) + cdf_put_att_text(fileID, time_varid, "long_name", strlen(taxis->longname), taxis->longname); + + if ( taxis->has_bounds ) + { + time_bndsid = cdfDefTimeBounds(fileID, time_varid, time_dimid, taxis_name, taxis); + streamptr->basetime.ncvarboundsid = time_bndsid; + } + + { + char unitstr[CDI_MAX_NAME]; + cdfDefTimeUnits(unitstr, &streamptr->tsteps[0].taxis, taxis); + size_t len = strlen(unitstr); + if ( len ) + { + cdf_put_att_text(fileID, time_varid, "units", len, unitstr); + /* + if ( taxis->has_bounds ) + cdf_put_att_text(fileID, time_bndsid, "units", len, unitstr); + */ + } + } + + if ( taxis->calendar != -1 ) + { + cdfDefCalendar(fileID, time_varid, taxis->calendar); + /* + if ( taxis->has_bounds ) + cdfDefCalendar(fileID, time_bndsid, taxis->calendar); + */ + } + + if ( taxis->type == TAXIS_FORECAST ) + { + int leadtimeid; + cdf_def_var(fileID, "leadtime", xtype, 1, &time_dimid, &leadtimeid); + streamptr->basetime.leadtimeid = leadtimeid; + + { + static const char stdname[] = "forecast_period"; + cdf_put_att_text(fileID, leadtimeid, "standard_name", sizeof(stdname) - 1, stdname); + } + + { + static const char lname[] = "Time elapsed since the start of the forecast"; + cdf_put_att_text(fileID, leadtimeid, "long_name", sizeof(lname) - 1, lname); + } + + { + char unitstr[CDI_MAX_NAME]; + cdfDefForecastTimeUnits(unitstr, taxis->fc_unit); + size_t len = strlen(unitstr); + if ( len ) + cdf_put_att_text(fileID, leadtimeid, "units", len, unitstr); + } + } + + cdf_put_att_text(fileID, time_varid, "axis", 1, "T"); + + if ( streamptr->ncmode == 2 ) cdf_enddef(fileID); +} + + +#endif +/* + * Local Variables: + * c-file-style: "Java" + * c-basic-offset: 2 + * indent-tabs-mode: nil + * show-trailing-whitespace: t + * require-trailing-newline: t + * End: + */ diff --git a/src/stream_cgribex.c b/src/stream_cgribex.c index d963571939a5b9ffc15d23c1bcc6328b5b6618ae..c1166cc42e5ca99e0111ead5b1135fce9a969cd8 100644 --- a/src/stream_cgribex.c +++ b/src/stream_cgribex.c @@ -1782,7 +1782,7 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI double lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0; gridInqParamLCC(gridID, grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0); - gridVerifyGribParamLCC(gridID, grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0); + gridVerifyGribParamLCC(grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0); bool lsouth = (lat_1 < 0); if ( lsouth ) { lat_1 = -lat_2; lat_2 = -lat_2; } diff --git a/src/stream_gribapi.c b/src/stream_gribapi.c index e5de73385f63852cfa5273e8325ee6d5a995a0ac..dc09b5a26c8ffbf1b4cb3c2b8f7b9acf2cb23da6 100644 --- a/src/stream_gribapi.c +++ b/src/stream_gribapi.c @@ -500,7 +500,7 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh, grib_get_double(gh, "Latin1InDegrees", &lat_1); grib_get_double(gh, "Latin2InDegrees", &lat_2); grib_get_long(gh, "projectionCentreFlag", &projflag); - bool lsouth = gribbyte_get_bit(projflag, 1); + bool lsouth = gribbyte_get_bit((int)projflag, 1); if ( lsouth ) { lat_1 = -lat_1; lat_2 = -lat_2; } double lat_0 = lat_2; @@ -723,10 +723,26 @@ void ensureBufferSize(size_t requiredSize, size_t *curSize, void **buffer) static grib_handle *gribapiGetDiskRepresentation(size_t recsize, size_t *buffersize, void **gribbuffer, int *outDatatype, int *outCompressionType, size_t *outUnzipsize) { - bool lieee = false; + int gribversion = (int)((char*)*gribbuffer)[7]; + + if ( gribversion <= 1 ) + { + if ( gribGetZip(recsize, *gribbuffer, outUnzipsize) > 0 ) + { + *outCompressionType = CDI_COMPRESS_SZIP; + ensureBufferSize(*outUnzipsize + 100, buffersize, gribbuffer); + } + else + { + *outCompressionType = CDI_COMPRESS_NONE; + } + } grib_handle *gh = grib_handle_new_from_message(NULL, *gribbuffer, recsize); - if(gribEditionNumber(gh) > 1) + + bool lieee = false; + + if ( gribversion > 1 ) { size_t len = 256; char typeOfPacking[256]; @@ -739,18 +755,6 @@ grib_handle *gribapiGetDiskRepresentation(size_t recsize, size_t *buffersize, vo else if ( strncmp(typeOfPacking, "grid_ieee", len) == 0 ) lieee = true; } } - else - { - if( gribGetZip(recsize, *gribbuffer, outUnzipsize) > 0 ) - { - *outCompressionType = CDI_COMPRESS_SZIP; - ensureBufferSize(*outUnzipsize + 100, buffersize, gribbuffer); - } - else - { - *outCompressionType = CDI_COMPRESS_NONE; - } - } if ( lieee ) { @@ -768,6 +772,7 @@ grib_handle *gribapiGetDiskRepresentation(size_t recsize, size_t *buffersize, vo if ( bitsPerValue > 0 && bitsPerValue <= 32 ) *outDatatype = (int)bitsPerValue; } } + return gh; } @@ -1722,25 +1727,10 @@ int gribapiDefSteptype(int editionNumber, grib_handle *gh, int productDefinition size_t len = 64; const char *stepType; - static struct { - long productionTemplate; - const char sname[8]; - } ts_tab[] = { - [TSTEP_INSTANT] = { 0, "instant" }, - [TSTEP_AVG] = { 8, "avg" }, - [TSTEP_ACCUM] = { 8, "accum" }, - [TSTEP_MAX] = { 8, "max" }, - [TSTEP_MIN] = { 8, "min" }, - [TSTEP_DIFF] = { 8, "diff" }, - [TSTEP_RMS] = { 8, "rms" }, - [TSTEP_SD] = { 8, "sd" }, - [TSTEP_COV] = { 8, "cov" }, - [TSTEP_RATIO] = { 8, "ratio" } - }; if (tsteptype >= TSTEP_INSTANT && tsteptype <= TSTEP_RATIO) { - stepType = ts_tab[tsteptype].sname; - proDefTempNum = ts_tab[tsteptype].productionTemplate; + stepType = cdiGribAPI_ts_str_map[tsteptype].sname; + proDefTempNum = cdiGribAPI_ts_str_map[tsteptype].productionTemplate; } else { @@ -2146,7 +2136,7 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype double lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0; gridInqParamLCC(gridID, grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0); - gridVerifyGribParamLCC(gridID, grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0); + gridVerifyGribParamLCC(grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0); if ( xval_0 < 0 ) xval_0 += 360; bool lsouth = (lat_1 < 0); if ( lsouth ) { lat_1 = -lat_2; lat_2 = -lat_2; } diff --git a/src/taxis.c b/src/taxis.c index b54e4f4297f7b64adc62912dc16e591c1c57bffe..de0016005a43a94a3713f3733bfd6ceeaeae7210 100644 --- a/src/taxis.c +++ b/src/taxis.c @@ -299,7 +299,11 @@ void taxisDefType(int taxisID, int type) if ( taxisptr->type != type ) { taxisptr->type = type; - if ( taxisptr->units ) delete_refcount_string(taxisptr->units); + if ( taxisptr->units ) + { + delete_refcount_string(taxisptr->units); + taxisptr->units = NULL; + } reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE); } } @@ -375,7 +379,11 @@ void taxisDefRdate(int taxisID, int rdate) if (taxisptr->rdate != rdate) { taxisptr->rdate = rdate; - if ( taxisptr->units ) delete_refcount_string(taxisptr->units); + if ( taxisptr->units ) + { + delete_refcount_string(taxisptr->units); + taxisptr->units = NULL; + } reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE); } } @@ -401,7 +409,11 @@ void taxisDefRtime(int taxisID, int rtime) if (taxisptr->rtime != rtime) { taxisptr->rtime = rtime; - if ( taxisptr->units ) delete_refcount_string(taxisptr->units); + if ( taxisptr->units ) + { + delete_refcount_string(taxisptr->units); + taxisptr->units = NULL; + } reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE); } } @@ -491,7 +503,11 @@ void taxisDefTunit(int taxisID, int unit) if (taxisptr->unit != unit) { taxisptr->unit = unit; - if ( taxisptr->units ) delete_refcount_string(taxisptr->units); + if ( taxisptr->units ) + { + delete_refcount_string(taxisptr->units); + taxisptr->units = NULL; + } reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE); } } diff --git a/src/varscan.c b/src/varscan.c index e1749679991f72977734a0f55c9d141bd2a6036d..c39850896e39207209180fde828eddddf280f25c 100644 --- a/src/varscan.c +++ b/src/varscan.c @@ -732,8 +732,9 @@ void cdi_generate_vars(stream_t *streamptr) dlevels2[levelID] = level_sf*levelTable[levelID].level2; } + const char **cvals = NULL; const char *unitptr = cdiUnitNamePtr(vartable[varid].level_unit); - int zaxisID = varDefZaxis(vlistID, zaxistype, (int)nlevels, dlevels, lbounds, dlevels1, dlevels2, + int zaxisID = varDefZaxis(vlistID, zaxistype, (int)nlevels, dlevels, cvals, lbounds, dlevels1, dlevels2, (int)Vctsize, Vct, NULL, NULL, unitptr, 0, 0, ltype1); if ( CDI_cmor_mode && nlevels == 1 && zaxistype != ZAXIS_HYBRID ) zaxisDefScalar(zaxisID); @@ -954,7 +955,7 @@ varDefZAxisSearch(int id, void *res, void *data) } -int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, bool lbounds, +int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, const char **cvals, bool lbounds, const double *levels1, const double *levels2, int vctsize, const double *vct, char *name, const char *longname, const char *units, int prec, int mode, int ltype1) { @@ -1017,6 +1018,8 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, b zaxisDefUbounds(zaxisID, levels2); } + if ( cvals ) zaxisDefCvals(zaxisID, cvals); + if ( (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) && vctsize > 0 ) zaxisDefVct(zaxisID, vctsize, vct); diff --git a/src/varscan.h b/src/varscan.h index 54624927f4e3a13bd5b58115b98d1df189ea908a..f837ca1aff021f8f428bb47ce79a3892e9930b83 100644 --- a/src/varscan.h +++ b/src/varscan.h @@ -15,7 +15,7 @@ void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds, void varDefVCT(size_t vctsize, double *vctptr); void varDefZAxisReference(int nlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZE]); -int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, bool lbounds, +int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, const char **cvals, bool lbounds, const double *levels1, const double *levels2, int vctsize, const double *vct, char *name, const char *longname, const char *units, int prec, int mode, int ltype); diff --git a/src/zaxis.c b/src/zaxis.c index 114f6d4d32beaf3cfdc2bb7c447483336fbb29be..fab24c56011dee78d6477c76523ff0e2118b137f 100644 --- a/src/zaxis.c +++ b/src/zaxis.c @@ -57,6 +57,7 @@ ZaxistypeEntry[] = { { /* 23 */ 0, "sedimentbottomtw", "sediment_bottom_tw", "", ""}, { /* 24 */ 0, "mixlayer", "mix_layer", "", ""}, { /* 25 */ 0, "height", "generalized_height", "height", ""}, + { /* 26 */ 0, "character", "area_type", "", ""}, }; enum { @@ -127,6 +128,7 @@ void zaxis_init(zaxis_t *zaxisptr) zaxisptr->p0name[0] = 0; zaxisptr->p0value.defined = false; zaxisptr->vals = NULL; + zaxisptr->cvals = NULL; zaxisptr->ubounds = NULL; zaxisptr->lbounds = NULL; zaxisptr->weights = NULL; @@ -271,6 +273,7 @@ void zaxisDestroyKernel( zaxis_t * zaxisptr ) int id = zaxisptr->self; if ( zaxisptr->vals ) Free( zaxisptr->vals ); + if ( zaxisptr->cvals ) Free( zaxisptr->cvals ); if ( zaxisptr->lbounds ) Free( zaxisptr->lbounds ); if ( zaxisptr->ubounds ) Free( zaxisptr->ubounds ); if ( zaxisptr->weights ) Free( zaxisptr->weights ); @@ -773,6 +776,25 @@ void zaxisDefLevels(int zaxisID, const double *levels) } } + +void zaxisDefCvals(int zaxisID, const char **cvals) +{ + zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID); + size_t size = (size_t)zaxisptr->size; + + if ( cvals ) + { + if ( zaxisptr->cvals != NULL ) + zaxisptr->cvals = NULL; + zaxisptr->cvals = (char**) Malloc(size*sizeof(char *)); + + for ( size_t ilev = 0; ilev < size; ++ilev ) + zaxisptr->cvals[ilev] = strdup(cvals[ilev]); + + reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE); + } +} + /* @Function zaxisDefLevel @Title Define one level of a Z-axis @@ -1368,6 +1390,21 @@ void zaxisPrintKernel(zaxis_t *zaxisptr, FILE *fp) fprintf(fp, "\n"); } + if ( zaxisptr->cvals ) + { + dig = prec; + nbyte0 = fprintf(fp, "types = "); + nbyte = nbyte0; + for ( int levelID = 0; levelID < nlevels; levelID++ ) + { + fprintf(fp, "\n"); + fprintf(fp, "%*s", nbyte0, ""); + nbyte = nbyte0; + nbyte += fprintf(fp, "%.*s [%d]", dig, zaxisptr->cvals[levelID], levelID+1); + } + fprintf(fp, "\n"); + } + if ( zaxisptr->lbounds && zaxisptr->ubounds ) { nbyte0 = fprintf(fp, "lbounds = "); diff --git a/src/zaxis.h b/src/zaxis.h index d6a772e5e34b6a156042029ad76628c42fa62ea8..04cfa0ba39b8a79ee36dca683b597bac78902162 100644 --- a/src/zaxis.h +++ b/src/zaxis.h @@ -20,6 +20,7 @@ typedef struct { char p0name[CDI_MAX_NAME]; zkey_double_t p0value; double *vals; + char **cvals; double *lbounds; double *ubounds; double *weights; diff --git a/tests/Makefile.am b/tests/Makefile.am index 5dd60ce6a891847f968cd8dde410d999077737fc..42ffb51ecbb8ebf8524d21c20d89dd70dfc9d9bb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -11,7 +11,7 @@ TESTS = cksum_verify \ pio_cksum_mpi_fw_at_all \ pio_cksum_mpi_fw_at_reblock \ test_resource_copy pio_write_deco2d_run \ - test_f2003 test_cdf_transformation \ + test_f2003 test_cdf_transformation test_cdf_const \ test_table test_byteswap check_PROGRAMS = cksum_verify test_grib cksum_write cksum_read pio_write \ diff --git a/tests/Makefile.in b/tests/Makefile.in index fdc9c1d559cfc94c35dad37a48a90e29434954bb..2341351f0fa9f01a1b163d61c0af486da70a1a02 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -84,7 +84,7 @@ TESTS = cksum_verify$(EXEEXT) test_cksum_grib test_cksum_nc \ pio_cksum_writer pio_cksum_cdf pio_cksum_mpi_fw_ordered \ pio_cksum_mpi_fw_at_all pio_cksum_mpi_fw_at_reblock \ test_resource_copy$(EXEEXT) pio_write_deco2d_run test_f2003 \ - test_cdf_transformation test_table$(EXEEXT) \ + test_cdf_transformation test_cdf_const test_table$(EXEEXT) \ test_byteswap$(EXEEXT) $(am__append_2) check_PROGRAMS = cksum_verify$(EXEEXT) test_grib$(EXEEXT) \ cksum_write$(EXEEXT) cksum_read$(EXEEXT) pio_write$(EXEEXT) \ @@ -111,7 +111,7 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/pio_cksum_writer.in $(srcdir)/pio_cksum_cdf.in \ $(srcdir)/test_resource_copy_mpi_run.in \ $(srcdir)/test_cdf_transformation.in \ - $(top_srcdir)/config/depcomp + $(srcdir)/test_cdf_const.in $(top_srcdir)/config/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = \ $(top_srcdir)/m4/acx_assert_lang_is_fortran_variant.m4 \ @@ -152,7 +152,7 @@ CONFIG_CLEAN_FILES = test_cksum_grib test_cksum_nc test_cksum_nc2 \ pio_cksum_mpi_fw_ordered pio_cksum_mpi_fw_at_all \ pio_cksum_mpi_fw_at_reblock pio_cksum_fpguard pio_cksum_asynch \ pio_cksum_writer pio_cksum_cdf test_resource_copy_mpi_run \ - test_cdf_transformation + test_cdf_transformation test_cdf_const CONFIG_CLEAN_VPATH_FILES = @ENABLE_NETCDF_TRUE@am__EXEEXT_1 = test_cdf_write$(EXEEXT) \ @ENABLE_NETCDF_TRUE@ test_cdf_read$(EXEEXT) @@ -629,6 +629,8 @@ test_resource_copy_mpi_run: $(top_builddir)/config.status $(srcdir)/test_resourc cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ test_cdf_transformation: $(top_builddir)/config.status $(srcdir)/test_cdf_transformation.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +test_cdf_const: $(top_builddir)/config.status $(srcdir)/test_cdf_const.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ diff --git a/tests/test_cdf_const.in b/tests/test_cdf_const.in new file mode 100644 index 0000000000000000000000000000000000000000..52cffa35c83c93442a2df2e754b4cbc838e32fea --- /dev/null +++ b/tests/test_cdf_const.in @@ -0,0 +1,66 @@ +#! @SHELL@ + +set -e +if [ @ENABLE_NETCDF@ = yes ]; then + exec >test_cdf_const.log 2>&1 + mkdir -p test_cdf_const.d + cd test_cdf_const.d + \rm -f * + @abs_top_builddir@/examples/cdi_write_const + ( @abs_top_builddir@/app/cdi -s example_const.nc \ + && @abs_top_builddir@/app/cdi example_const.nc) >cdi.$$.stdout 2>cdi.$$.stderr + echo "$0" + exec 6<cdi.$$.stdout 7<../"$0" + while read pattern <&7 ; do + [ "$pattern" != "#PATTERNS" ] || break + done + saved_IFS=$IFS + IFS='' + while read line <&6 ; do + read pattern <&7 + pattern=`echo "$pattern" | sed -e 's/^#//'` + echo "$line" | grep "$pattern" + done + if [ -s cdi.$$.stderr ]; then + echo "unexpected error message from @abs_top_builddir@/app/cdi:" + cat cdi.$$.stderr + fi + read pattern <&7 + [ "$pattern" = '#END PATTERNS' ] + exec 5<&- 6<&- + \rm cdi.$$.stdout cdi.$$.stderr example_const.nc + cd .. + rmdir test_cdf_const.d + \rm test_cdf_const.log +else + # skip tests for unsupported formats + exit 77 +fi + +#PATTERNS +#^ File format : NetCDF +#^ Var : Institut Source Ttype Levels Num Gridsize Num Dtype : Parameter ID +#^ 1 : unknown unknown constant 1 1 72 1 F32 : -1 +#^ 2 : unknown unknown constant 5 2 72 1 F32 : -2 +#^ Grid coordinates : +#^ 1 : lonlat : points=72 (12x6) +#^ lon : 0 to 330 by 30 degrees_east circular +#^ lat : -75 to 75 by 30 degrees_north +#^ Vertical coordinates : +#^ 1 : surface : levels=1 +#^ 2 : pressure : levels=5 +#^ plev : 101300 to 20000 Pa +#^ Rec : Date Time Level Gridsize Miss : Minimum Mean Maximum : Parameter ID +#^ 1 : 0000-00-00 00:00:00 0 72 0 : 1.1000 1.1000 1.1000 : -1 +#^ 2 : 0000-00-00 00:00:00 101300 72 0 : 2.2000 2.2000 2.2000 : -2 +#^ 3 : 0000-00-00 00:00:00 92500 72 0 : 2.2000 2.2000 2.2000 : -2 +#^ 4 : 0000-00-00 00:00:00 85000 72 0 : 2.2000 2.2000 2.2000 : -2 +#^ 5 : 0000-00-00 00:00:00 50000 72 0 : 2.2000 2.2000 2.2000 : -2 +#^ 6 : 0000-00-00 00:00:00 20000 72 0 : 2.2000 2.2000 2.2000 : -2 +#END PATTERNS + +# +# Local Variables: +# mode: sh +# End: +#