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:
+#