diff --git a/.ci/bb/breeze-mpim/test.all.clang b/.ci/bb/breeze-mpim/test.all.clang
new file mode 100755
index 0000000000000000000000000000000000000000..5047123ae0923edda3abb004ec63861d24dac3bd
--- /dev/null
+++ b/.ci/bb/breeze-mpim/test.all.clang
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+set -eu
+set -o pipefail
+
+script_dir=$(cd "$(dirname "$0")"; pwd)
+top_srcdir=$(cd "${script_dir}/../../.."; pwd)
+
+. "${script_dir}/utils.sh"
+init_clang1201
+
+# Check the formatting. Note that git-clang-format might keep redundant blank
+# lines. Therefore, we use clang-format:
+find src app \
+  -name '*.h' -o -name '*.hpp' -o -name '*.c' -o -name '*.cpp' | \
+    xargs -n 1 -P 8 clang-format --Werror --dry-run --verbose
+
+test -f "${top_srcdir}/configure" || "${top_srcdir}/autogen.sh"
+
+"${top_srcdir}/configure" \
+--disable-maintainer-mode \
+--enable-cf-interface \
+--enable-iso-c-interface \
+--enable-mpi \
+--enable-option-checking=fatal \
+--with-eccodes="${ECCODES_ROOT}" \
+--with-netcdf="${NETCDF_ROOT}" \
+CC="${MPICC}" \
+CPPFLAGS="-I${UUID_ROOT}/include" \
+FC="${MPIFC}" \
+F77="${MPIFC}" \
+LDFLAGS="-I${UUID_ROOT}/lib" \
+MPI_LAUNCH="${MPI_LAUNCH}" \
+PKG_CONFIG_PATH="${YAXT_ROOT}/lib/pkgconfig:${PPM_ROOT}/lib/pkgconfig"
+
+make -j8
+
+make -j8 check | tee tests/test-suite.log
+
+check_all_tests_passed tests/test-suite.log
diff --git a/.ci/bb/breeze-mpim/test.all.nag b/.ci/bb/breeze-mpim/test.all.nag
new file mode 100755
index 0000000000000000000000000000000000000000..7f467bfdea3be4ce28232e90d4387dff834b6016
--- /dev/null
+++ b/.ci/bb/breeze-mpim/test.all.nag
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+set -eu
+set -o pipefail
+
+script_dir=$(cd "$(dirname "$0")"; pwd)
+top_srcdir=$(cd "${script_dir}/../../.."; pwd)
+
+. "${script_dir}/utils.sh"
+init_nag626223
+
+test -f "${top_srcdir}/configure" || "${top_srcdir}/autogen.sh"
+
+# Create a distribution file with minimalistic configuration:
+"${top_srcdir}/configure"
+make -j1 dist
+
+# Create a subdirectory for further testing and switch to it:
+mkdir check_dist && cd check_dist
+
+# Move the distribution file to the test directory and unpack it:
+mv ../cdi-*.tar.gz ./
+tar xf cdi-*.tar.gz
+
+# Create a subdirectory for building and switch to it:
+mkdir build && cd build
+
+# Use GCC from the path when compiling/linking Fortran code:
+FCFLAGS="-O2 -g -Wc=$(which gcc)"
+
+# Create an out-of-source configuration:
+../cdi-*/configure \
+--disable-maintainer-mode \
+--enable-cf-interface \
+--enable-iso-c-interface \
+--enable-mpi \
+--enable-option-checking=fatal \
+--with-eccodes="${ECCODES_ROOT}" \
+--with-netcdf="${NETCDF_ROOT}" \
+CC="${MPICC}" \
+CPPFLAGS="-I${UUID_ROOT}/include" \
+F77="${MPIFC}" \
+FC="${MPIFC}" \
+FCFLAGS="${FCFLAGS}" \
+FFLAGS="${FCFLAGS}" \
+LDFLAGS="-I${UUID_ROOT}/lib" \
+MPI_LAUNCH="${MPI_LAUNCH}" \
+PKG_CONFIG_PATH="${YAXT_ROOT}/lib/pkgconfig:${PPM_ROOT}/lib/pkgconfig"
+
+make -j8
+
+make -j8 check | tee tests/test-suite.log
+
+check_all_tests_passed tests/test-suite.log
+
+make -j8 distclean
+
+check_no_files_in_cwd
diff --git a/.ci/bb/breeze-mpim/test.all.nv b/.ci/bb/breeze-mpim/test.all.nv
new file mode 100755
index 0000000000000000000000000000000000000000..786ff18324a3a4ba029ffe9b0d9a1039575b23a7
--- /dev/null
+++ b/.ci/bb/breeze-mpim/test.all.nv
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+set -eu
+set -o pipefail
+
+script_dir=$(cd "$(dirname "$0")"; pwd)
+top_srcdir=$(cd "${script_dir}/../../.."; pwd)
+
+. "${script_dir}/utils.sh"
+init_nv2130
+
+# We want to check with the Debian version of Libtool, which is patched to avoid
+# overlinking:
+( export PATH="/usr/bin:${PATH-}"
+  export ACLOCAL_PATH="/usr/share/aclocal:${ACLOCAL_PATH-}"
+  module unload automake/1.16.1
+  module load automake/1.16.1
+  "${top_srcdir}/autogen.sh" )
+
+"${top_srcdir}/configure" \
+--disable-maintainer-mode \
+--enable-cf-interface \
+--enable-iso-c-interface \
+--enable-mpi \
+--enable-option-checking=fatal \
+--with-eccodes="${ECCODES_ROOT}" \
+--with-netcdf="${NETCDF_ROOT}" \
+CC="${MPICC}" \
+CPPFLAGS="-I${UUID_ROOT}/include" \
+F77="${MPIFC}" \
+FC="${MPIFC}" \
+FCFLAGS='-g -fPIC' \
+LDFLAGS="-I${UUID_ROOT}/lib" \
+MPI_LAUNCH="${MPI_LAUNCH}" \
+PKG_CONFIG_PATH="${YAXT_ROOT}/lib/pkgconfig:${PPM_ROOT}/lib/pkgconfig"
+
+make -j8
+
+make -j8 check | tee tests/test-suite.log
+
+check_all_tests_passed tests/test-suite.log
+
+# Check that an executable is not overlinked to libscalesppmcore.so:
+tested_file='./examples/pio/.libs/collectData'
+invalid_needed=`readelf -d "${tested_file}" | sed -E -n '/\(NEEDED\).*libscalesppmcore\.so/p'` || {
+  echo "ERROR: failed to check '${tested_file}' for ELF NEEDED entries" >&2
+  exit 1
+}
+if test -n "${invalid_needed}"; then
+  {
+    echo "ERROR: '${tested_file}' has excessive ELF NEEDED entries:" >&2
+    echo "${invalid_needed}" >&2
+  } >&2
+  exit 1
+fi
diff --git a/.ci/bb/breeze-mpim/test.ru-py.gcc b/.ci/bb/breeze-mpim/test.ru-py.gcc
new file mode 100755
index 0000000000000000000000000000000000000000..20d8a9a4584849af49f5ea271f983a50a39990ad
--- /dev/null
+++ b/.ci/bb/breeze-mpim/test.ru-py.gcc
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -eu
+set -o pipefail
+
+script_dir=$(cd "$(dirname "$0")"; pwd)
+top_srcdir=$(cd "${script_dir}/../../.."; pwd)
+
+. "${script_dir}/utils.sh"
+init_gcc630
+
+test -f "${top_srcdir}/configure" || "${top_srcdir}/autogen.sh"
+
+"${top_srcdir}/configure" \
+--disable-maintainer-mode \
+--enable-option-checking=fatal \
+--enable-python \
+--enable-ruby \
+--enable-swig \
+--with-eccodes="${ECCODES_ROOT}" \
+--with-netcdf="${NETCDF_ROOT}" \
+CC="${CC}" \
+CPPFLAGS="-I${UUID_ROOT}/include" \
+CXX="${CXX}" \
+LDFLAGS="-L${UUID_ROOT}/lib"
+
+make -j8
+
+# Test the interfaces:
+LD_LIBRARY_PATH="${NETCDF_ROOT}/lib:${LD_LIBRARY_PATH}" make -j8 -C interfaces test
+(cd interfaces && ./CdiInfo)
+
+make -j8 check
diff --git a/.ci/bb/breeze-mpim/utils.sh b/.ci/bb/breeze-mpim/utils.sh
new file mode 100644
index 0000000000000000000000000000000000000000..61868dab965ce979be23f8722e117da5b7fad95f
--- /dev/null
+++ b/.ci/bb/breeze-mpim/utils.sh
@@ -0,0 +1,259 @@
+#
+# Accepts a list of environment modules and loads them witch conflict
+# resolution.
+#
+switch_for_module ()
+{
+  for sfm_module in "$@"; do
+    sfm_module_full=
+    sfm_module_short=
+    case $sfm_module in
+      */*)
+        # The module is provided with the version part:
+        sfm_module_full=$sfm_module
+        sfm_module_short=`echo $sfm_module | sed 's%/[^/]*$%%'` ;;
+      *)
+        # Only the name of the module is provided, get the default version:
+        sfm_module_full=`module show $sfm_module 2>&1 | sed -n "s%^[^ \t]*/\\($sfm_module.*\\):%\\1%p"`
+        sfm_module_short=$sfm_module ;;
+    esac
+
+    # A space-separated list of modules that are already loaded:
+    sfm_loaded_full=`module -t list 2>&1 | tr '\n' ' ' | sed 's/^.*Modulefiles://' | sed 's/(default)//g'`
+
+    # Check whether the requested module if already loaded:
+    if test -n "$sfm_module_full"; then
+      case " $sfm_loaded_full " in
+        *" $sfm_module_full "*)
+          echo "module $sfm_module is already loaded"
+          continue ;;
+      esac
+    fi
+
+    # A list of modules in conflict:
+    sfm_conflicts=`module show $sfm_module 2>&1 | sed -n 's/^conflict\(.*\)/\1/p' | tr '\n\t' '  '`
+
+    # A list of loaded modules without version parts:
+    sfm_loaded_short=`echo "$sfm_loaded_full" | sed 's%\([^ ][^ ]*\)/[^ ]*%\1%g'`
+
+    # Add the short name of the module to the list of conflicts:
+    sfm_conflicts="$sfm_conflicts $sfm_module_short"
+
+    # A list of loaded modules that are in conflict with the requested module:
+    sfm_loaded_conflicts=
+    for sfm_conflict in $sfm_conflicts""; do
+      sfm_loaded_list=      
+      case $sfm_conflict in
+        */*)
+          # The conflict is specified with the version part:
+          sfm_loaded_list=$sfm_loaded_full ;;
+        *)
+          # The conflict is specified without the version part:
+          sfm_loaded_list=$sfm_loaded_short ;;
+      esac
+
+      # Check that the conflicted module is loaded:
+      case " $sfm_loaded_list " in
+        *" $sfm_conflict "*)
+          # The conflict is loaded, check whether it is already added to the
+          # list:
+          case " $sfm_loaded_conflicts " in
+            *" $sfm_conflict "*) ;;
+            *)
+              # The conflict is not in the list, append:
+              sfm_loaded_conflicts="$sfm_loaded_conflicts $sfm_conflict" ;;
+          esac
+        ;;
+      esac
+    done
+
+    # Calculate the number of modules that must be unloaded to before loading
+    # the requested module:
+    sfm_loaded_conflicts_count=`echo $sfm_loaded_conflicts | wc -w`
+
+    case $sfm_loaded_conflicts_count in
+      0)
+        # None of the conflicting modules is loaded:
+        sfm_cmd="module load $sfm_module" ;;
+      1)
+        # There is only one module that must be unloaded, use switch command:
+        sfm_cmd="module switch $sfm_loaded_conflicts $sfm_module" ;;
+      *)
+        # There is more than one module that must be unloaded, unload all of
+        # them and then load the requested one:
+        sfm_cmd="module unload $sfm_loaded_conflicts && module load $sfm_module" ;;
+    esac
+
+    echo "$sfm_cmd"
+    eval "$sfm_cmd"
+  done
+}
+
+#
+# Initializes the environment.
+#
+init_env ()
+{
+  saved_set=$-
+  set +eu
+  . /etc/profile.d/mpim.sh
+  set -${saved_set}
+  switch_for_module automake/1.16.1
+
+  # Use non-Debian libtool by default:
+  LIBTOOL_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/libtool-2.4.6-qdyaqqw'
+  export PATH="${LIBTOOL_ROOT}/bin:${PATH-}"
+  export ACLOCAL_PATH="${LIBTOOL_ROOT}/share/aclocal:${ACLOCAL_PATH-}"
+
+  SWIG_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/swig-4.0.2-busrrtn'
+  RUBY_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/ruby-3.0.2-stqm2vj'
+  PYTHON_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/python-2.7.18-zqrnwom'
+
+  export PATH="${RUBY_ROOT}/bin:${PYTHON_ROOT}/bin:${SWIG_ROOT}/bin:${PATH-}"
+}
+
+#
+# Sets variables for tests with GCC 6.3.0.
+#
+init_gcc630 ()
+{
+  init_env
+  switch_for_module gcc/6.3.0
+
+  CC=gcc
+  CXX=g++
+  FC=gfortran
+
+  ECCODES_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/eccodes-2.21.0-3sdngaq'
+  NETCDF_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/netcdf-c-4.8.0-fzupaca'
+  UUID_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/libuuid-1.0.3-rm4kv2o'
+
+  # Here we fix a never-ending story with Libtool overlinkning, absence of
+  # '*.la' files when they could help, and '-Wl,--disable/enable-new-dtags':
+  HDF5_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/hdf5-1.10.7-4l3frcp'
+  export LD_LIBRARY_PATH="${ECCODES_ROOT}/lib:${HDF5_ROOT}/lib:${LD_LIBRARY_PATH-}"
+}
+
+#
+# Sets variables for tests with NVHPC 21.3.0.
+#
+init_nv2130 ()
+{
+  init_env
+  switch_for_module gcc/6.3.0
+
+  export NVHPC='/data/mpi/sclab/sip/m300488/nvhpc'
+  export NVLOCALRC="${NVHPC}/Linux_x86_64/21.3/compilers/bin/localrc.60300"
+  export PATH="${NVHPC}/Linux_x86_64/21.3/compilers/bin:${PATH-}"
+
+  CC=nvc
+  CXX=nvc++
+  FC=nvfortran
+
+  export PATH="/data/mpi/sclab/sip/m300488/libcdi-ci-sw/nvhpc-21.3-sandybridge/mpich-3.4.2-sfxulsj/bin:${PATH-}"
+  MPICC=mpicc
+  MPIFC=mpif90
+  MPI_LAUNCH="$(which mpirun)"
+
+  ECCODES_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/eccodes-2.21.0-3sdngaq'
+  NETCDF_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/nvhpc-21.3-sandybridge/netcdf-c-4.8.0-vjppuov'
+  PPM_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/nvhpc-21.3-sandybridge/scales-ppm-1.0.7-uy4z72r'
+  YAXT_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/nvhpc-21.3-sandybridge/yaxt-0.9.2.1-lbqqemx'
+  UUID_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/libuuid-1.0.3-rm4kv2o'
+
+  # Here we fix a never-ending story with Libtool overlinkning, absence of
+  # '*.la' files when they could help, and '-Wl,--disable/enable-new-dtags':
+  HDF5_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/nvhpc-21.3-sandybridge/hdf5-1.10.7-h7pvthl'
+  export LD_LIBRARY_PATH="${ECCODES_ROOT}/lib:${HDF5_ROOT}/lib:${LD_LIBRARY_PATH-}"
+}
+
+#
+# Sets variables for tests with Clang 12.0.1.
+#
+init_clang1201 ()
+{
+  init_env
+  switch_for_module gcc/6.3.0
+
+  export PATH="/data/mpi/sclab/sip/m300488/clang/12.0.1/bin:${PATH-}"
+  # Clang does not inject RPATHs to the standard library in use:
+  export LD_LIBRARY_PATH="/sw/stretch-x64/gcc/gcc-6.3.0/lib64:${LD_LIBRARY_PATH-}"
+
+  CC=clang
+  CXX=clang++
+  FC=gfortran
+
+  export PATH="/data/mpi/sclab/sip/m300488/libcdi-ci-sw/clang-12.0.1-sandybridge/openmpi-4.1.1-6ydagyy/bin:${PATH-}"
+  MPICC=mpicc
+  MPIFC=mpif90
+  MPI_LAUNCH="$(which mpirun) --oversubscribe"
+
+  ECCODES_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/eccodes-2.21.0-3sdngaq'
+  NETCDF_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/clang-12.0.1-sandybridge/netcdf-c-4.8.0-z6r5guk'
+  PPM_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/clang-12.0.1-sandybridge/scales-ppm-1.0.7-5mhatgx'
+  YAXT_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/clang-12.0.1-sandybridge/yaxt-0.9.2.1-cj2nf5j'
+  UUID_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/libuuid-1.0.3-rm4kv2o'
+
+  # Here we fix a never-ending story with Libtool overlinkning, absence of
+  # '*.la' files when they could help, and '-Wl,--disable/enable-new-dtags':
+  HDF5_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/clang-12.0.1-sandybridge/hdf5-1.10.7-4y54xnh'
+  export LD_LIBRARY_PATH="${ECCODES_ROOT}/lib:${HDF5_ROOT}/lib:${LD_LIBRARY_PATH-}"
+}
+
+#
+# Sets variables for tests with NAG 6.2.6223.
+#
+init_nag626223 ()
+{
+  init_env
+  switch_for_module gcc/6.3.0 nag/6.2
+
+  CC=gcc
+  CXX=g++
+  FC=nagfor
+
+  export PATH="/data/mpi/sclab/sip/m300488/libcdi-ci-sw/nag-6.2-sandybridge/mpich-3.4.2-fzsvtw2/bin:${PATH-}"
+  MPICC=mpicc
+  MPIFC=mpif90
+  MPI_LAUNCH="$(which mpirun)"
+
+  ECCODES_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/eccodes-2.21.0-3sdngaq'
+  NETCDF_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/nag-6.2-sandybridge/netcdf-c-4.8.0-ogawg3w'
+  PPM_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/nag-6.2-sandybridge/scales-ppm-1.0.7-5kdlwzv'
+  YAXT_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/nag-6.2-sandybridge/yaxt-0.9.2.1-rhq2ysn'
+  UUID_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/gcc-6.3.0-sandybridge/libuuid-1.0.3-rm4kv2o'
+
+  # Here we fix a never-ending story with Libtool overlinkning, absence of
+  # '*.la' files when they could help, and '-Wl,--disable/enable-new-dtags':
+  HDF5_ROOT='/data/mpi/sclab/sip/m300488/libcdi-ci-sw/nag-6.2-sandybridge/hdf5-1.10.7-pltg3k4'
+  export LD_LIBRARY_PATH="${ECCODES_ROOT}/lib:${HDF5_ROOT}/lib:${LD_LIBRARY_PATH-}"
+}
+
+#
+# Accepts a path to a file containing the testsuite summary (either the
+# 'test-suite.log' or the standard output of the 'make check' command) and
+# checks whether all tests were run and passed.
+#
+check_all_tests_passed ()
+{
+  awk '/SKIP: /{
+         print "ERROR: the total number of tests is not equal to the number of passed tests";
+         exit 1;
+       }' $1 >&2
+}
+
+#
+# Checks whether the current working directory or any of its subdirectories
+# contain a file and fails with an error message if that is the case.
+#
+check_no_files_in_cwd ()
+{
+  cnfic_files=`find . -type f 2>/dev/null`
+  if test -n "$cnfic_files"; then
+    {
+      echo "ERROR: the current working directory contains undeleted files:"
+      echo "$cnfic_files"
+    } >&2
+    exit 1
+  fi
+}
diff --git a/.ci/bb/daint-cscs/test.all.cray b/.ci/bb/daint-cscs/test.all.cray
new file mode 100755
index 0000000000000000000000000000000000000000..85a961807cafca02e810076cffb4b6c446fd1f68
--- /dev/null
+++ b/.ci/bb/daint-cscs/test.all.cray
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+set -eu
+set -o pipefail
+
+script_dir=$(cd "$(dirname "$0")"; pwd)
+top_srcdir=$(cd "${script_dir}/../../.."; pwd)
+
+. "${script_dir}/utils.sh"
+init_cray1203
+
+# Save time for the person running this script manually:
+if test "x${PE_NETCDF_MODULE_NAME}" = 'xcray-netcdf'; then
+  case $top_srcdir in
+    "${HOME}/"*)
+      echo "ERROR: parallel NetCDF4 tests are known to fail when CDI is built in the user home directory and linked against NetCDF that does not support MPI parallel invocations" >&2
+      exit 1
+  esac
+fi
+
+test -f "${top_srcdir}/configure" || "${top_srcdir}/autogen.sh"
+
+# The configure script does not check the 'lib64' subdirectory, therefore we
+# run it with '--with-eccodes' and the following flags. Note that fixing this
+# in the configure script might be tricky: the 'lib64' subdirectory should be
+# checked first but if it does not exist or does not contain the library, we
+# might end up linking to a library from the linker's default search path
+# (e.g. /usr/lib) instead of the one from "$with_eccodes/lib" because
+# "-L${with_eccodes}/lib64" would be ignored in that case:
+CPPFLAGS="-I${ECCODES_ROOT}/include"
+LDFLAGS="-L${ECCODES_ROOT}/lib64"
+
+"${top_srcdir}/configure" \
+--disable-maintainer-mode \
+--enable-cf-interface \
+--enable-iso-c-interface \
+--enable-mpi \
+--enable-option-checking=fatal \
+--with-eccodes \
+--with-netcdf \
+CC="${CC}" \
+CPPFLAGS="${CPPFLAGS}" \
+F77="${FC}" \
+FC="${FC}" \
+LDFLAGS="${LDFLAGS}" \
+MPI_LAUNCH="${MPI_LAUNCH}" \
+PKG_CONFIG_PATH="${YAXT_ROOT}/lib/pkgconfig:${PPM_ROOT}/lib/pkgconfig:${PKG_CONFIG_PATH}"
+
+make -j8
+
+make -j8 check | tee tests/test-suite.log
+
+check_all_tests_passed tests/test-suite.log
diff --git a/.ci/bb/daint-cscs/test.all.pgi b/.ci/bb/daint-cscs/test.all.pgi
new file mode 100755
index 0000000000000000000000000000000000000000..c6d02c8521a455ba7a41f151a28964cc9b57e8cc
--- /dev/null
+++ b/.ci/bb/daint-cscs/test.all.pgi
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+set -eu
+set -o pipefail
+
+script_dir=$(cd "$(dirname "$0")"; pwd)
+top_srcdir=$(cd "${script_dir}/../../.."; pwd)
+
+. "${script_dir}/utils.sh"
+init_pgi2011
+
+# Save time for the person running this script manually:
+if test "x${PE_NETCDF_MODULE_NAME}" = 'xcray-netcdf'; then
+  case $top_srcdir in
+    "${HOME}/"*)
+      echo "ERROR: parallel NetCDF4 tests are known to fail when CDI is built in the user home directory and linked against NetCDF that does not support MPI parallel invocations" >&2
+      exit 1
+  esac
+fi
+
+test -f "${top_srcdir}/configure" || "${top_srcdir}/autogen.sh"
+
+# The configure script does not check the 'lib64' subdirectory, therefore we
+# run it with '--with-eccodes' and the following flags. Note that fixing this
+# in the configure script might be tricky: the 'lib64' subdirectory should be
+# checked first but if it does not exist or does not contain the library, we
+# might end up linking to a library from the linker's default search path
+# (e.g. /usr/lib) instead of the one from "$with_eccodes/lib" because
+# "-L${with_eccodes}/lib64" would be ignored in that case:
+CPPFLAGS="-I${ECCODES_ROOT}/include"
+LDFLAGS="-L${ECCODES_ROOT}/lib64"
+
+"${top_srcdir}/configure" \
+--disable-maintainer-mode \
+--enable-cf-interface \
+--enable-iso-c-interface \
+--enable-mpi \
+--enable-option-checking=fatal \
+--with-eccodes \
+--with-netcdf \
+CC="${CC}" \
+CFLAGS='-g -O1' \
+CPPFLAGS="${CPPFLAGS}" \
+F77="${FC}" \
+FC="${FC}" \
+FCFLAGS='-g -fPIC' \
+LDFLAGS="${LDFLAGS}" \
+MPI_LAUNCH="${MPI_LAUNCH}" \
+PKG_CONFIG_PATH="${YAXT_ROOT}/lib/pkgconfig:${PPM_ROOT}/lib/pkgconfig:${PKG_CONFIG_PATH}" \
+PTHREAD_LIBS='-lpthread'
+
+make -j8
+
+make -j8 check | tee tests/test-suite.log
+
+check_all_tests_passed tests/test-suite.log
diff --git a/.ci/bb/daint-cscs/utils.sh b/.ci/bb/daint-cscs/utils.sh
new file mode 100644
index 0000000000000000000000000000000000000000..7fa5f17d9036a6016258c28485bb4122dcf60e7c
--- /dev/null
+++ b/.ci/bb/daint-cscs/utils.sh
@@ -0,0 +1,182 @@
+#
+# Accepts a list of environment modules and loads them witch conflict
+# resolution.
+#
+switch_for_module ()
+{
+  for sfm_module in "$@"; do
+    sfm_module_full=
+    sfm_module_short=
+    case $sfm_module in
+      */*)
+        # The module is provided with the version part:
+        sfm_module_full=$sfm_module
+        sfm_module_short=`echo $sfm_module | sed 's%/[^/]*$%%'` ;;
+      *)
+        # Only the name of the module is provided, get the default version:
+        sfm_module_full=`module show $sfm_module 2>&1 | sed -n "s%^[^ \t]*/\\($sfm_module.*\\):%\\1%p"`
+        sfm_module_short=$sfm_module ;;
+    esac
+
+    # A space-separated list of modules that are already loaded:
+    sfm_loaded_full=`module -t list 2>&1 | tr '\n' ' ' | sed 's/^.*Modulefiles://' | sed 's/(default)//g'`
+
+    # Check whether the requested module if already loaded:
+    if test -n "$sfm_module_full"; then
+      case " $sfm_loaded_full " in
+        *" $sfm_module_full "*)
+          echo "module $sfm_module is already loaded"
+          continue ;;
+      esac
+    fi
+
+    # A list of modules in conflict:
+    sfm_conflicts=`module show $sfm_module 2>&1 | sed -n 's/^conflict\(.*\)/\1/p' | tr '\n\t' '  '`
+
+    # A list of loaded modules without version parts:
+    sfm_loaded_short=`echo "$sfm_loaded_full" | sed 's%\([^ ][^ ]*\)/[^ ]*%\1%g'`
+
+    # Add the short name of the module to the list of conflicts:
+    sfm_conflicts="$sfm_conflicts $sfm_module_short"
+
+    # A list of loaded modules that are in conflict with the requested module:
+    sfm_loaded_conflicts=
+    for sfm_conflict in $sfm_conflicts""; do
+      sfm_loaded_list=      
+      case $sfm_conflict in
+        */*)
+          # The conflict is specified with the version part:
+          sfm_loaded_list=$sfm_loaded_full ;;
+        *)
+          # The conflict is specified without the version part:
+          sfm_loaded_list=$sfm_loaded_short ;;
+      esac
+
+      # Check that the conflicted module is loaded:
+      case " $sfm_loaded_list " in
+        *" $sfm_conflict "*)
+          # The conflict is loaded, check whether it is already added to the
+          # list:
+          case " $sfm_loaded_conflicts " in
+            *" $sfm_conflict "*) ;;
+            *)
+              # The conflict is not in the list, append:
+              sfm_loaded_conflicts="$sfm_loaded_conflicts $sfm_conflict" ;;
+          esac
+        ;;
+      esac
+    done
+
+    # Calculate the number of modules that must be unloaded to before loading
+    # the requested module:
+    sfm_loaded_conflicts_count=`echo $sfm_loaded_conflicts | wc -w`
+
+    case $sfm_loaded_conflicts_count in
+      0)
+        # None of the conflicting modules is loaded:
+        sfm_cmd="module load $sfm_module" ;;
+      1)
+        # There is only one module that must be unloaded, use switch command:
+        sfm_cmd="module switch $sfm_loaded_conflicts $sfm_module" ;;
+      *)
+        # There is more than one module that must be unloaded, unload all of
+        # them and then load the requested one:
+        sfm_cmd="module unload $sfm_loaded_conflicts && module load $sfm_module" ;;
+    esac
+
+    echo "$sfm_cmd"
+    eval "$sfm_cmd"
+  done
+}
+
+#
+# Initializes the environment.
+#
+init_env ()
+{
+  AUTOMAKE_ROOT='/project/d56/libcdi-ci-sw/gcc-11.2.0-haswell/automake-1.16.3-46gthis'
+  export PATH="${AUTOMAKE_ROOT}/bin:${PATH-}"
+  # Tell the custom installation of Automake where the libtool macros are:
+  export ACLOCAL_PATH="/usr/share/aclocal:${ACLOCAL_PATH-}"
+}
+
+#
+# Sets variables for tests with Cray 12.0.3.
+#
+init_cray1203 ()
+{
+  init_env
+  switch_for_module craype PrgEnv-cray cce/12.0.3 cray-mpich
+
+  # Build and test against NetCDF that does not support MPI parallel invocations
+  # (parallel NetCDF4 tests are known to fail in this case when run from the
+  # user home directory on Daint):
+  switch_for_module cray-netcdf
+
+  # Uncomment the following line to test against MPI-capable NetCDF:
+  # switch_for_module cray-netcdf-hdf5parallel cray-hdf5-parallel
+
+  CC=cc
+  CXX=CC
+  FC=ftn
+  MPI_LAUNCH="$(which srun) -p cscsci -C gpu -A d56 -t 05:00"
+
+  ECCODES_ROOT='/project/d56/libcdi-ci-sw/cce-12.0.3-haswell/eccodes-2.24.2-o2a4fw3'
+  PPM_ROOT='/project/d56/libcdi-ci-sw/cce-12.0.3-haswell/scales-ppm-1.0.8-44zlrlu'
+  YAXT_ROOT='/project/d56/libcdi-ci-sw/cce-12.0.3-haswell/yaxt-0.9.2.1-enz3pcz'
+
+  # Here we fix a never-ending story with Libtool overlinkning, absence of
+  # '*.la' files when they could help, and '-Wl,--disable/enable-new-dtags':
+  export LD_LIBRARY_PATH="${ECCODES_ROOT}/lib64:${PPM_ROOT}/lib:${YAXT_ROOT}/lib:${LD_LIBRARY_PATH-}"
+}
+
+#
+# Sets variables for tests with PGI 20.1.1.
+#
+init_pgi2011 ()
+{
+  init_env
+  # We use deprecated versions (the most recent compatible with PGI though) of
+  # the Cray packages and have to make sure that the default versions are
+  # unloaded (otherwise, we get various warnings and errors):
+  module unload cray-mpich cray-netcdf cray-netcdf-hdf5parallel cray-hdf5 cray-hdf5-parallel
+  switch_for_module craype PrgEnv-pgi/6.0.8 pgi/20.1.1 cray-mpich/7.7.15
+
+  # Build and test against NetCDF that does not support MPI parallel invocations
+  # (parallel NetCDF4 tests are known to fail in this case when run from the
+  # user home directory on Daint):
+  switch_for_module cray-netcdf/4.7.4.0 cray-hdf5/1.12.0.0
+
+  # Uncomment the following line to test against MPI-capable NetCDF:
+  # switch_for_module cray-netcdf-hdf5parallel/4.7.4.0 cray-hdf5-parallel/1.12.0.0
+
+  CC=cc
+  CXX=CC
+  FC=ftn
+  MPI_LAUNCH="$(which srun) -p cscsci -C gpu -A d56 -t 05:00"
+
+  ECCODES_ROOT='/project/d56/libcdi-ci-sw/pgi-20.1.1-haswell/eccodes-2.24.2-hwtl5nr'
+  PPM_ROOT='/project/d56/libcdi-ci-sw/pgi-20.1.1-haswell/scales-ppm-1.0.8-z2nxqya'
+  YAXT_ROOT='/project/d56/libcdi-ci-sw/pgi-20.1.1-haswell/yaxt-0.9.2.1-3orop7g'
+
+  # The deprecated versions of the Cray packages are not in the default linker
+  # search path:
+  export LD_LIBRARY_PATH="${MPICH_DIR}/lib:${NETCDF_DIR}/lib:${HDF5_DIR}/lib:${LD_LIBRARY_PATH-}"
+
+  # Here we fix a never-ending story with Libtool overlinkning, absence of
+  # '*.la' files when they could help, and '-Wl,--disable/enable-new-dtags':
+  export LD_LIBRARY_PATH="${ECCODES_ROOT}/lib64:${PPM_ROOT}/lib:${YAXT_ROOT}/lib:${LD_LIBRARY_PATH-}"
+}
+
+#
+# Accepts a path to a file containing the testsuite summary (either the
+# 'test-suite.log' or the standard output of the 'make check' command) and
+# checks whether all tests were run and passed.
+#
+check_all_tests_passed ()
+{
+  awk '/SKIP: /{
+         print "ERROR: the total number of tests is not equal to the number of passed tests";
+         exit 1;
+       }' $1 >&2
+}
diff --git a/.ci/bb/levante-dkrz/install_prerequisites.sh b/.ci/bb/levante-dkrz/install_prerequisites.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7b9d22858ab02f3e3299a8454c80fd514c43250e
--- /dev/null
+++ b/.ci/bb/levante-dkrz/install_prerequisites.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+
+set -eu
+unset CDPATH
+
+module purge
+module load git
+
+install_dir='/work/mh0287/m300488/libcdi-ci-sw/install'
+work_dir="$(pwd)/build"
+make_cmd='make -j22'
+
+mkdir -p "${work_dir}" && cd "${work_dir}"
+
+# Get PPM 1.0.8:
+wget https://swprojects.dkrz.de/redmine/attachments/download/517/ppm-1.0.8.tar.gz
+tar xvf ppm-1.0.8.tar.gz
+ppm_src_dir="${work_dir}/ppm-1.0.8"
+ppm_name_tag='ppm-1.0.8'
+ppm_config_args='--enable-MPI --disable-netcdf --disable-hdf5 --disable-parmetis --disable-metis --disable-crypto'
+
+# Get YAXT 0.9.3:
+git clone --depth=1 -b release-0.9.3 https://gitlab.dkrz.de/dkrz-sw/yaxt.git
+yaxt_src_dir="${work_dir}/yaxt"
+yaxt_name_tag='yaxt-0.9.3'
+yaxt_config_args=''
+
+export CC='mpicc'
+export FC='mpif90'
+
+# Install for GCC 11.2.0:
+compiler_name_tag='gcc-11.2.0'
+module load openmpi/4.1.2-gcc-11.2.0
+
+# Install PPM:
+build_dir="${ppm_name_tag}-${compiler_name_tag}"
+mkdir "${build_dir}"
+( cd "${build_dir}"
+  "${ppm_src_dir}/configure" ${ppm_config_args} --prefix="${install_dir}/${ppm_name_tag}-${compiler_name_tag}"
+  $make_cmd
+  $make_cmd check
+  $make_cmd install )
+
+# Install YAXT:
+build_dir="${yaxt_name_tag}-${compiler_name_tag}"
+mkdir "${build_dir}"
+( cd "${build_dir}"
+  "${yaxt_src_dir}/configure" ${yaxt_config_args} --prefix="${install_dir}/${yaxt_name_tag}-${compiler_name_tag}"
+  $make_cmd
+  $make_cmd check
+  $make_cmd install )
+
+module unload openmpi/4.1.2-gcc-11.2.0
+
+# Install for Intel Classic 2021.5.0:
+compiler_name_tag='intel-classic-2021.5.0'
+module load openmpi/4.1.2-intel-2021.5.0
+
+# Install PPM:
+build_dir="${ppm_name_tag}-${compiler_name_tag}"
+mkdir "${build_dir}"
+( cd "${build_dir}"
+  "${ppm_src_dir}/configure" ${ppm_config_args} --prefix="${install_dir}/${ppm_name_tag}-${compiler_name_tag}"
+  $make_cmd
+  $make_cmd check
+  $make_cmd install )
+
+# Install YAXT:
+build_dir="${yaxt_name_tag}-${compiler_name_tag}"
+mkdir "${build_dir}"
+( cd "${build_dir}"
+  "${yaxt_src_dir}/configure" ${yaxt_config_args} --prefix="${install_dir}/${yaxt_name_tag}-${compiler_name_tag}"
+  $make_cmd
+  $make_cmd check
+  $make_cmd install )
+
+module unload openmpi/4.1.2-intel-2021.5.0
diff --git a/.ci/bb/levante-dkrz/test.all.gcc b/.ci/bb/levante-dkrz/test.all.gcc
new file mode 100755
index 0000000000000000000000000000000000000000..a114e52c7f04cbc7978957a774498ab6acbd6238
--- /dev/null
+++ b/.ci/bb/levante-dkrz/test.all.gcc
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+set -eu
+set -o pipefail
+
+script_dir=$(cd "$(dirname "$0")"; pwd)
+top_srcdir=$(cd "${script_dir}/../../.."; pwd)
+
+. "${script_dir}/utils.sh"
+init_gcc1120
+
+test -f "${top_srcdir}/configure" || "${top_srcdir}/autogen.sh"
+
+# The configure script does not check the 'lib64' subdirectory, therefore we
+# run it with '--with-eccodes' and the following flags. Note that fixing this
+# in the configure script might be tricky: the 'lib64' subdirectory should be
+# checked first but if it does not exist or does not contain the library, we
+# might end up linking to a library from the linker's default search path
+# (e.g. /usr/lib) instead of the one from "$with_eccodes/lib" because
+# "-L${with_eccodes}/lib64" would be ignored in that case:
+CPPFLAGS="-I${ECCODES_ROOT}/include"
+LDFLAGS="-L${ECCODES_ROOT}/lib64"
+
+# We expect --enable-cf-interface and --enable-ppm-dist-array to be set to
+# 'yes' automatically because of --enable-mpi. Function
+# 'check_all_tests_passed' that we run at the end makes sure that the options
+# have been enabled and the corresponding tests have not been skipped.
+"${top_srcdir}/configure" \
+--disable-maintainer-mode \
+--enable-iso-c-interface \
+--enable-mpi \
+--enable-option-checking=fatal \
+--with-eccodes \
+--with-netcdf="${NETCDF_ROOT}" \
+CC="${MPICC}" \
+CPPFLAGS="${CPPFLAGS}" \
+F77="${MPIFC}" \
+FC="${MPIFC}" \
+LDFLAGS="${LDFLAGS}" \
+MPI_LAUNCH="${MPI_LAUNCH}" \
+PKG_CONFIG_PATH="${YAXT_ROOT}/lib/pkgconfig:${PPM_ROOT}/lib/pkgconfig"
+
+make -j8
+
+make -j8 check | tee tests/test-suite.log
+
+check_all_tests_passed tests/test-suite.log
diff --git a/.ci/bb/levante-dkrz/test.all.intel-classic b/.ci/bb/levante-dkrz/test.all.intel-classic
new file mode 100755
index 0000000000000000000000000000000000000000..21c9e889d07941490439fe53b631531375a9f5c8
--- /dev/null
+++ b/.ci/bb/levante-dkrz/test.all.intel-classic
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+set -eu
+set -o pipefail
+
+script_dir=$(cd "$(dirname "$0")"; pwd)
+top_srcdir=$(cd "${script_dir}/../../.."; pwd)
+
+. "${script_dir}/utils.sh"
+init_intelclassic202150
+
+test -f "${top_srcdir}/configure" || "${top_srcdir}/autogen.sh"
+
+# Create a subdirectory for building and switch to it:
+mkdir build && cd build
+
+# The configure script does not check the 'lib64' subdirectory, therefore we
+# run it with '--with-eccodes' and the following flags. Note that fixing this
+# in the configure script might be tricky: the 'lib64' subdirectory should be
+# checked first but if it does not exist or does not contain the library, we
+# might end up linking to a library from the linker's default search path
+# (e.g. /usr/lib) instead of the one from "$with_eccodes/lib" because
+# "-L${with_eccodes}/lib64" would be ignored in that case:
+CPPFLAGS="-I${ECCODES_ROOT}/include"
+LDFLAGS="-L${ECCODES_ROOT}/lib64"
+
+"${top_srcdir}/configure" \
+--disable-maintainer-mode \
+--enable-cf-interface \
+--enable-iso-c-interface \
+--enable-mpi \
+--enable-option-checking=fatal \
+--with-eccodes \
+--with-netcdf="${NETCDF_ROOT}" \
+CC="${MPICC}" \
+CPPFLAGS="${CPPFLAGS}" \
+F77="${MPIFC}" \
+FC="${MPIFC}" \
+LDFLAGS="${LDFLAGS}" \
+MPI_LAUNCH="${MPI_LAUNCH}" \
+PKG_CONFIG_PATH="${YAXT_ROOT}/lib/pkgconfig:${PPM_ROOT}/lib/pkgconfig"
+
+make -j8
+
+make -j8 check | tee tests/test-suite.log
+
+check_all_tests_passed tests/test-suite.log
+
+make -j8 distclean
+
+check_no_files_in_cwd
diff --git a/.ci/bb/levante-dkrz/test.icon-pio.intel-classic b/.ci/bb/levante-dkrz/test.icon-pio.intel-classic
new file mode 100755
index 0000000000000000000000000000000000000000..b99b4bb9ba71c84cf583cdacf69ff9b6b1846b11
--- /dev/null
+++ b/.ci/bb/levante-dkrz/test.icon-pio.intel-classic
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+echo "WARNING: the current version of CDI-PIO is incompatible with the build system if ICON" >&2
+exit 0
diff --git a/.ci/bb/levante-dkrz/test.icon.gcc b/.ci/bb/levante-dkrz/test.icon.gcc
new file mode 100755
index 0000000000000000000000000000000000000000..0b1a23e46f403a41360796d06441f4f7bf5fc581
--- /dev/null
+++ b/.ci/bb/levante-dkrz/test.icon.gcc
@@ -0,0 +1,80 @@
+#!/bin/bash
+
+set -eu
+
+script_dir=$(cd "$(dirname "$0")"; pwd)
+top_srcdir=$(cd "${script_dir}/../../.."; pwd)
+
+. "${script_dir}/utils.sh"
+init_gcc1120
+
+# The following compiler flags are used by the respective ICON configure
+# wrapper. They are not set into stone and can be changed if needed. It is just
+# important to keep them the same as in the wrapper.
+CFLAGS='-g -gdwarf-4 -march=native -mpc64 -O2'
+FCFLAGS='-fmodule-private -fimplicit-none -fmax-identifier-length=63 -Wall -Wcharacter-truncation -Wconversion -Wunderflow -Wunused-parameter -Wno-surprising -fall-intrinsics -g -march=native -mpc64 -fbacktrace -fbounds-check -fstack-protector-all -finit-real=nan -finit-integer=-2147483648 -finit-character=127 -O2 -std=f2008'
+
+test -f "${top_srcdir}/configure" || "${top_srcdir}/autogen.sh"
+
+"${top_srcdir}/configure" \
+--disable-cdi-app \
+--disable-maintainer-mode \
+--disable-shared \
+--enable-cf-interface=no \
+--enable-cgribex \
+--enable-grib \
+--enable-iso-c-interface \
+--enable-mpi=no \
+--enable-ppm-dist-array=no \
+--enable-silent-rules=no \
+--enable-static \
+--with-eccodes=yes \
+--with-netcdf \
+--with-on-demand-check-programs \
+--without-example-programs \
+--without-grib_api \
+--without-szlib \
+--without-threads \
+BUILD_CC= \
+BUILD_CFLAGS= \
+BUILD_CXX= \
+BUILD_F77= \
+BUILD_FC= \
+BUILD_FCFLAGS= \
+BUILD_LDFLAGS= \
+BUILD_LIBS= \
+BUILD_MPI_C_LIB= \
+BUILD_MPI_FC_LIB= \
+CC="${MPICC}" \
+CFLAGS="${CFLAGS}" \
+CPPFLAGS="-I${NETCDF_ROOT}/include -I${ECCODES_ROOT}/include" \
+CXX=no \
+F77=no \
+FC="${MPIFC}" \
+FCFLAGS="${FCFLAGS}" \
+LDFLAGS="-L${NETCDF_ROOT}/lib -L${ECCODES_ROOT}/lib64" \
+LIBS='-leccodes -lnetcdf' \
+MPIROOT= \
+MPI_C_INCLUDE= \
+MPI_C_LIB= \
+MPI_FC_LIB= \
+MPI_FC_MOD= \
+MPI_LAUNCH="${MPI_LAUNCH}" \
+PKG_CONFIG= \
+PPM_CORE_C_INCLUDE= \
+PPM_CORE_C_LIB= \
+YAXT_C_INCLUDE= \
+YAXT_C_LIB= \
+YAXT_FC_LIB= \
+YAXT_FC_MOD= \
+ac_cv_func_uuid_create=no \
+ac_cv_lib_uuid_uuid_generate=no \
+acx_cv_have_libnc_dap=no \
+acx_cv_have_nc4hdf5=no \
+acx_cv_have_netcdf2=yes \
+acx_cv_have_netcdf4=yes \
+acx_cv_have_pnetcdf=no
+
+make -j8
+
+make -j8 check
diff --git a/.ci/bb/levante-dkrz/utils.sh b/.ci/bb/levante-dkrz/utils.sh
new file mode 100644
index 0000000000000000000000000000000000000000..0be138ae34319d65eff6ce3ac47e7566ac4006c3
--- /dev/null
+++ b/.ci/bb/levante-dkrz/utils.sh
@@ -0,0 +1,182 @@
+#
+# Accepts a list of environment modules and loads them witch conflict
+# resolution.
+#
+switch_for_module ()
+{
+  for sfm_module in "$@"; do
+    sfm_module_full=
+    sfm_module_short=
+    case $sfm_module in
+      */*)
+        # The module is provided with the version part:
+        sfm_module_full=$sfm_module
+        sfm_module_short=`echo $sfm_module | sed 's%/[^/]*$%%'` ;;
+      *)
+        # Only the name of the module is provided, get the default version:
+        sfm_module_full=`module show $sfm_module 2>&1 | sed -n "s%^[^ \t]*/\\($sfm_module.*\\):%\\1%p"`
+        sfm_module_short=$sfm_module ;;
+    esac
+
+    # A space-separated list of modules that are already loaded:
+    sfm_loaded_full=`module -t list 2>&1 | tr '\n' ' ' | sed 's/^.*Modulefiles://' | sed 's/(default)//g'`
+
+    # Check whether the requested module if already loaded:
+    if test -n "$sfm_module_full"; then
+      case " $sfm_loaded_full " in
+        *" $sfm_module_full "*)
+          echo "module $sfm_module is already loaded"
+          continue ;;
+      esac
+    fi
+
+    # A list of modules in conflict:
+    sfm_conflicts=`module show $sfm_module 2>&1 | sed -n 's/^conflict\(.*\)/\1/p' | tr '\n\t' '  '`
+
+    # A list of loaded modules without version parts:
+    sfm_loaded_short=`echo "$sfm_loaded_full" | sed 's%\([^ ][^ ]*\)/[^ ]*%\1%g'`
+
+    # Add the short name of the module to the list of conflicts:
+    sfm_conflicts="$sfm_conflicts $sfm_module_short"
+
+    # A list of loaded modules that are in conflict with the requested module:
+    sfm_loaded_conflicts=
+    for sfm_conflict in $sfm_conflicts""; do
+      sfm_loaded_list=      
+      case $sfm_conflict in
+        */*)
+          # The conflict is specified with the version part:
+          sfm_loaded_list=$sfm_loaded_full ;;
+        *)
+          # The conflict is specified without the version part:
+          sfm_loaded_list=$sfm_loaded_short ;;
+      esac
+
+      # Check that the conflicted module is loaded:
+      case " $sfm_loaded_list " in
+        *" $sfm_conflict "*)
+          # The conflict is loaded, check whether it is already added to the
+          # list:
+          case " $sfm_loaded_conflicts " in
+            *" $sfm_conflict "*) ;;
+            *)
+              # The conflict is not in the list, append:
+              sfm_loaded_conflicts="$sfm_loaded_conflicts $sfm_conflict" ;;
+          esac
+        ;;
+      esac
+    done
+
+    # Calculate the number of modules that must be unloaded to before loading
+    # the requested module:
+    sfm_loaded_conflicts_count=`echo $sfm_loaded_conflicts | wc -w`
+
+    case $sfm_loaded_conflicts_count in
+      0)
+        # None of the conflicting modules is loaded:
+        sfm_cmd="module load $sfm_module" ;;
+      1)
+        # There is only one module that must be unloaded, use switch command:
+        sfm_cmd="module switch $sfm_loaded_conflicts $sfm_module" ;;
+      *)
+        # There is more than one module that must be unloaded, unload all of
+        # them and then load the requested one:
+        sfm_cmd="module unload $sfm_loaded_conflicts && module load $sfm_module" ;;
+    esac
+
+    echo "$sfm_cmd"
+    eval "$sfm_cmd"
+  done
+}
+
+#
+# Initializes the environment.
+#
+init_env ()
+{
+  :
+}
+
+#
+# Sets variables for tests with GCC 11.2.0.
+#
+init_gcc1120 ()
+{
+  init_env
+  switch_for_module gcc/11.2.0-gcc-11.2.0 openmpi/4.1.2-gcc-11.2.0
+
+  CC=gcc
+  CXX=g++
+  FC=gfortran
+  MPICC=mpicc
+  MPIFC=mpif90
+  MPI_LAUNCH="$(which mpirun)"
+
+  ECCODES_ROOT='/sw/spack-levante/eccodes-2.21.0-4ywkk4'
+  NETCDF_ROOT='/sw/spack-levante/netcdf-c-4.8.1-6qheqr'
+  PPM_ROOT='/work/mh0287/m300488/libcdi-ci-sw/install/ppm-1.0.8-gcc-11.2.0'
+  YAXT_ROOT='/work/mh0287/m300488/libcdi-ci-sw/install/yaxt-0.9.3-gcc-11.2.0'
+
+  # Here we fix a never-ending story with Libtool overlinkning, absence of
+  # '*.la' files when they could help, and '-Wl,--disable/enable-new-dtags':
+  export LD_LIBRARY_PATH="${ECCODES_ROOT}/lib64:${NETCDF_ROOT}/lib:${LD_LIBRARY_PATH-}"
+}
+
+#
+# Sets variables for tests with Intel Classic 2021.5.0.
+#
+init_intelclassic202150 ()
+{
+  init_env
+  # Try to make sure that the compiler works with the system gcc:
+  module unload gcc
+  # For whatever reason, Intel Classic 2021.5.0 is enabled with
+  # intel-oneapi-compilers/2022.0.1-gcc-11.2.0:
+  switch_for_module intel-oneapi-compilers/2022.0.1-gcc-11.2.0 openmpi/4.1.2-intel-2021.5.0
+
+  AR=xiar
+  CC=icc
+  CXX=icpc
+  FC=ifort
+  MPICC=mpicc
+  MPIFC=mpif90
+  MPI_LAUNCH="$(which mpirun)"
+
+  ECCODES_ROOT='/sw/spack-levante/eccodes-2.21.0-3ehkbb'
+  NETCDF_ROOT='/sw/spack-levante/netcdf-c-4.8.1-2k3cmu'
+  PPM_ROOT='/work/mh0287/m300488/libcdi-ci-sw/install/ppm-1.0.8-intel-classic-2021.5.0'
+  YAXT_ROOT='/work/mh0287/m300488/libcdi-ci-sw/install/yaxt-0.9.3-intel-classic-2021.5.0'
+
+  # Here we fix a never-ending story with Libtool overlinkning, absence of
+  # '*.la' files when they could help, and '-Wl,--disable/enable-new-dtags':
+  export LD_LIBRARY_PATH="${ECCODES_ROOT}/lib64:${NETCDF_ROOT}/lib:${LD_LIBRARY_PATH-}"
+}
+
+#
+# Accepts a path to a file containing the testsuite summary (either the
+# 'test-suite.log' or the standard output of the 'make check' command) and
+# checks whether all tests were run and passed.
+#
+check_all_tests_passed ()
+{
+  awk '/SKIP: /{
+         print "ERROR: the total number of tests is not equal to the number of passed tests";
+         exit 1;
+       }' $1 >&2
+}
+
+#
+# Checks whether the current working directory or any of its subdirectories
+# contain a file and fails with an error message if that is the case.
+#
+check_no_files_in_cwd ()
+{
+  cnfic_files=`find . -type f 2>/dev/null`
+  if test -n "$cnfic_files"; then
+    {
+      echo "ERROR: the current working directory contains undeleted files:"
+      echo "$cnfic_files"
+    } >&2
+    exit 1
+  fi
+}
diff --git a/.ci/bb/run_all.sh b/.ci/bb/run_all.sh
new file mode 100755
index 0000000000000000000000000000000000000000..583e36a23de183b73984ada54a427ebe65dada46
--- /dev/null
+++ b/.ci/bb/run_all.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+set -eu
+set -o pipefail
+
+script_dir=$(cd "$(dirname "$0")"; pwd)
+top_srcdir=$(cd "${script_dir}/../.."; pwd)
+
+test_environment='unknown'
+case $(uname -s) in
+  Linux)
+    node_name=$(uname -n)
+    case $(host "${node_name}") in
+      mpipc*.mpimet.mpg.de\ * | \
+      breeze*.mpimet.mpg.de\ *)
+        test_environment='breeze-mpim' ;;
+      levante*.atos.local\ *)
+        test_environment='levante-dkrz' ;;
+      daint*.login.cscs.ch\ *)
+        test_environment='daint-cscs' ;;
+    esac
+esac
+
+test "x${test_environment}" != 'xunknown' || {
+  echo 'ERROR: unknown test environment' >&2
+  exit 1
+}
+
+cd "${top_srcdir}"
+
+git update-index -q --refresh || {
+  echo "ERROR: failed to update git index in '${top_srcdir}'" >&2
+  exit 1
+}
+
+git diff-files --quiet || {
+  echo "ERROR: '${top_srcdir}' has unstaged changes" >&2
+  exit 1
+}
+
+untracked_files=`git ls-files --others` || {
+  echo "ERROR: failed to get list of untracked files in '${top_srcdir}'" >&2
+  exit 1
+}
+if test -n "${untracked_files}"; then
+  {
+    echo "ERROR: '${top_srcdir}' has untracked files:" >&2
+    echo "${untracked_files}" >&2
+  } >&2
+  exit 1
+fi
+
+echo "Running tests for '${test_environment}'"
+
+for script in $(find "${script_dir}/${test_environment}" -type f -name 'test.*' -executable); do
+  echo "Running '${script}'"
+  "${script}"
+  git clean -fdx
+  git checkout .
+done
diff --git a/ChangeLog b/ChangeLog
index 62c8ef7606d6d72561ca2c2b0fd2a288191b357e..879960a148007daa960ed1a6c0154a2afe5922d6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,46 @@
+2022-11-05  Uwe Schulzweida
+
+	* NetCDF output: added compression support for data on GRID_GENERIC
+
+2022-10-19  Uwe Schulzweida
+
+	* Replaced CDI function vlistDefVarExtra() by cdiDefKeyString() with CDI_KEY_CHUNKS
+	* Replaced CDI function vlistInqVarExtra() by cdiInqKeyString() with CDI_KEY_CHUNKS
+	* Replaced CDI function vlistDefVarScalefactor() by cdiDefKeyFloat() with CDI_KEY_SCALEFACTOR
+	* Replaced CDI function vlistInqVarScalefactor() by cdiDefKeyFloat () with CDI_KEY_SCALEFACTOR
+	* Replaced CDI function vlistDefVarAddoffset() by cdiDefKeyFloat () with CDI_KEY_ADDOFFSET
+	* Replaced CDI function vlistInqVarAddoffset() by cdiDefKeyFloat () with CDI_KEY_ADDOFFSET
+
+2022-10-17  Uwe Schulzweida
+
+        * Added environment variable CDI_SHUFFLE to set shuffle option to NetCDF4 deflation compression
+
+2022-10-16  Uwe Schulzweida
+
+	* Improved read performance of temporal chunked NetCDF4 data
+        * Added environment variable CDI_CHUNK_CACHE to set the NetCDF4 chunk cache size
+        * Added environment variable CDI_CHUNK_CACHE_MAX to set the maximum chunk cache size
+
+2022-10-14  Uwe Schulzweida
+
+	* NetCDF: reading of lower time bounds is wrong since 2.0.6 (bug fix)
+
+2022-10-06  Uwe Schulzweida
+
+	* Version 2.1.0 released
+
+2022-10-05  Uwe Schulzweida
+
+	* Added CDI_PROJ_HEALPIX
+
+2022-10-04  Uwe Schulzweida
+
+	* cdi_encode_timeval: added support for TUNIT_SECOND
+
+2022-09-30  Uwe Schulzweida
+
+	* install cmake files in <install>/lib/cmake/cdi
+
 2022-08-12  Uwe Schulzweida
 
 	* added CDI_KEY_CHUNKTYPE and CDI_KEY_CHUNKSIZE
@@ -56,7 +99,7 @@
 
 2022-01-28  Uwe Schulzweida
 
-	* cdf_read_coordinates: check that bounds have only 2 dimensions [Bug #10575]
+	* cdf_read_coordinates: check that grid cell bounds have only 2 dimensions [Bug #10575]
 	* gribIterator::gridGenerate: copy CDI_KEY_UUID (bug fix)
 
 2022-01-12  Uwe Schulzweida
diff --git a/NEWS b/NEWS
index f424f07c0b0a6ac2fbefc2729a5a18a4bbe44f8f..ad1d2d665d26ca50f2a1ffe2c45127fd7a29c5c0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,16 +1,27 @@
 CDI NEWS
 --------
 
-Version 2.1.0 (11 October 2021):
+Version 2.2.0 (6 October 2023):
+
+   New features:
+     * Improved read performance of temporal chunked NetCDF4 data
+   Fixed bugs:
+
+Version 2.1.0 (6 October 2022):
 
    New features:
      * Added support for NCZarr
      * Set number of significant bits used for NetCDF 4.9.0 bit-roundung: vlistDefVarNSB()/vlistInqVarNSB()
      * Added support for milli seconds
      * Changed DateType back to int
+     * Made CDI compatible to revision 1.8.3 used in ICON
    Fixed bugs:
+     * recalculate optimal chunk_size if gridsize is > chunk_size_lim
+     * ecCodes encode: fix problem with startStep for step type MIN/MAX
+     * GRIB read: recalculate start date/time for every record and timestep
+     * changed chunk_size_lim from 1073741823 to 16777216
      * compareXYvals failed for unstructured grids (segmentation fault) [Bug #10632]
-     * cdf_read_coordinates: check that bounds have only 2 dimensions [Bug #10575]
+     * cdf_read_coordinates: check that grid cell bounds have only 2 dimensions [Bug #10575]
 
 Version 2.0.0 (11 October 2021):
 
diff --git a/app/cdi.c b/app/cdi.c
index 19f518a32774371d401d37ede09040eb9baa6b9f..689bba083f0e534ed88a4fb9ceadee76f76a3deb 100644
--- a/app/cdi.c
+++ b/app/cdi.c
@@ -78,8 +78,8 @@ static int datamode = DP_MODE;
 static void
 version(void)
 {
-  int filetypes[] = { CDI_FILETYPE_SRV, CDI_FILETYPE_EXT, CDI_FILETYPE_IEG, CDI_FILETYPE_GRB,  CDI_FILETYPE_GRB2,
-                      CDI_FILETYPE_NC,  CDI_FILETYPE_NC2, CDI_FILETYPE_NC4, CDI_FILETYPE_NC4C, CDI_FILETYPE_NC5, CDI_FILETYPE_NCZARR };
+  int filetypes[] = { CDI_FILETYPE_SRV, CDI_FILETYPE_EXT, CDI_FILETYPE_IEG,  CDI_FILETYPE_GRB, CDI_FILETYPE_GRB2,  CDI_FILETYPE_NC,
+                      CDI_FILETYPE_NC2, CDI_FILETYPE_NC4, CDI_FILETYPE_NC4C, CDI_FILETYPE_NC5, CDI_FILETYPE_NCZARR };
   const char *typenames[] = { "srv", "ext", "ieg", "grb", "grb2", "nc", "nc2", "nc4", "nc4c", "nc5", "nczarr" };
 
   fprintf(stderr, "CDI version 2.1\n");
@@ -497,8 +497,8 @@ printShortinfo(int streamID, int vlistID, int vardis)
             {
               const CdiDateTime dt = taxisInqRdatetime(taxisID);
 
-              fprintf(stdout, "     RefTime = %4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
-                      dt.date.year, dt.date.month, dt.date.day, dt.time.hour, dt.time.minute, dt.time.second);
+              fprintf(stdout, "     RefTime = %4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d", dt.date.year, dt.date.month, dt.date.day,
+                      dt.time.hour, dt.time.minute, dt.time.second);
               if (dt.time.ms) fprintf(stdout, ".%d", dt.time.ms);
 
               const int tunits = taxisInqTunit(taxisID);
@@ -560,8 +560,9 @@ setDefaultDataType(char *datatypestr)
           else
             {
               fprintf(stderr, "Unsupported number of bits %d!\n", nbits);
-              fprintf(stderr,
-                      "Use I8/I16/I32/F32/F64 for nc/nc2/nc4/nc4c/nc5/nczarr; F32/F64 for grb2/srv/ext/ieg; P1 - P24 for grb/grb2.\n");
+              fprintf(
+                  stderr,
+                  "Use I8/I16/I32/F32/F64 for nc/nc2/nc4/nc4c/nc5/nczarr; F32/F64 for grb2/srv/ext/ieg; P1 - P24 for grb/grb2.\n");
               exit(EXIT_FAILURE);
             }
         }
diff --git a/app/printinfo.c b/app/printinfo.c
index 0110224530e94fd3bfd90cc0481d6d87f42efa7d..21f1b26734f0b782de437012aa45f1f273937aa8 100644
--- a/app/printinfo.c
+++ b/app/printinfo.c
@@ -9,15 +9,14 @@
 
 #include "printinfo.h"
 
-
 #define DATE_FORMAT "%5.4d-%2.2d-%2.2d"
 #define TIME_FORMAT "%2.2d:%2.2d:%2.2d"
 
 void
 datetime2str(CdiDateTime dt, char *datetimestr, int maxlen)
 {
-  snprintf(datetimestr, maxlen, DATE_FORMAT "T" TIME_FORMAT,
-           dt.date.year, dt.date.month, dt.date.day, dt.time.hour, dt.time.minute, dt.time.second);
+  snprintf(datetimestr, maxlen, DATE_FORMAT "T" TIME_FORMAT, dt.date.year, dt.date.month, dt.date.day, dt.time.hour, dt.time.minute,
+           dt.time.second);
 }
 
 void
@@ -44,7 +43,8 @@ time2str(CdiTime time, char *timestr, int maxlen)
     }
 
   if (msDigitsNum)
-    snprintf(timestr, maxlen, "%2.2d:%2.2d:%0*.*f", time.hour, time.minute, msDigitsNum + 3, msDigitsNum, time.second + time.ms / 1000.0);
+    snprintf(timestr, maxlen, "%2.2d:%2.2d:%0*.*f", time.hour, time.minute, msDigitsNum + 3, msDigitsNum,
+             time.second + time.ms / 1000.0);
   else
     snprintf(timestr, maxlen, TIME_FORMAT, time.hour, time.minute, time.second);
 }
diff --git a/config/default b/config/default
index 9454f5561565851ff53290c96572606dc36f9216..78cba4d32d89e306d3b3a300a331e5b72463cd74 100755
--- a/config/default
+++ b/config/default
@@ -42,7 +42,7 @@ case "${HOSTNAME}" in
 	            CC=icc CFLAGS="-g -D_REENTRANT -Wall -Wwrite-strings -O3 -march=native -fp-model source"
 	;;
     bailung*|d133*|d134*)
-	${CONFPATH}configure --prefix=$HOME/local \
+	${CONFPATH}configure --prefix=$HOME/local/cdi \
                     --enable-maintainer-mode \
                     --enable-iso-c-interface \
                     --enable-swig \
@@ -69,7 +69,7 @@ case "${HOSTNAME}" in
                  --with-fdb5=$HOME/src/fdb \
                  --with-eccodes=$HOME/local/eccodes-2.22.0 \
                  --with-netcdf=$HOME/local/netcdf-c-4.9.0"
-        PREFIX="--prefix=$HOME/local"
+        PREFIX="--prefix=$HOME/local/cdi"
         LD_ADD="-Wl,-rpath,$HOME/local/eccodes-2.22.0/lib -Wl,-rpath,$HOME/src/fdb/lib"
         if  test "$COMP" = clang ; then
           ${CONFPATH}configure $CONFIG_OPTS $PREFIX $CDILIBS LDFLAGS="$LD_ADD $LDFLAGS" \
diff --git a/configure.ac b/configure.ac
index b3469f9e843cd6624fb4bc2627260a6043efa2a7..1b0232e6909f0e8cb0aef163ad88d5fe39fa09af 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@
 AC_PREREQ([2.69])
 LT_PREREQ([2.4.6])
 
-AC_INIT([cdi],[2.0.7],[https://mpimet.mpg.de/cdi])
+AC_INIT([cdi],[2.1.1],[https://mpimet.mpg.de/cdi])
 
 AC_DEFINE_UNQUOTED(CDI, ["$PACKAGE_VERSION"], [CDI version])
 
@@ -395,13 +395,13 @@ dnl
 m4_foreach([build_flag_var],[[BUILD_CFLAGS],[BUILD_FCFLAGS],[BUILD_LDFLAGS],[BUILD_LIBS],[BUILD_MPI_C_LIB],[BUILD_MPI_FC_LIB],[BUILD_C_INCLUDE],[BUILD_FC_INCLUDE]],
   [AC_ARG_VAR(build_flag_var,
      [append to ]m4_bpatsubst(build_flag_var, [BUILD_], [])[ during build but not in configure phase])dnl
-AC_CONFIG_COMMANDS_PRE(m4_bpatsubst(build_flag_var, [BUILD_], [])[="$]m4_bpatsubst(build_flag_var, [BUILD_], [])[$]{build_flag_var+ $build_flag_var[}"])dnl
+AC_CONFIG_COMMANDS_PRE(m4_bpatsubst(build_flag_var, [BUILD_], [])[="$]m4_bpatsubst(build_flag_var, [BUILD_], [])[$]{build_flag_var:+ $build_flag_var[}"])dnl
 AM_SUBST_NOTMAKE(build_flag_var)])dnl
 
 m4_foreach([build_tool_var],[[BUILD_CC],[BUILD_CXX],[BUILD_FC],[BUILD_F77]],
   [AC_ARG_VAR(build_tool_var,
      [replace ]m4_bpatsubst(build_tool_var, [BUILD_], [])[ with expansion of $]build_tool_var[ during build but not in configure phase])dnl
-AC_CONFIG_COMMANDS_PRE(m4_bpatsubst(build_tool_var, [BUILD_], [])[="$]{build_tool_var-$[]m4_bpatsubst(build_tool_var, [BUILD_], [])}["])dnl
+AC_CONFIG_COMMANDS_PRE(m4_bpatsubst(build_tool_var, [BUILD_], [])[="$]{build_tool_var:-$[]m4_bpatsubst(build_tool_var, [BUILD_], [])}["])dnl
 AM_SUBST_NOTMAKE(build_tool_var)])dnl
 dnl
 dnl
@@ -440,7 +440,7 @@ AC_CONFIG_FILES([tests/test_cksum_grib \
 
 AC_CONFIG_FILES([Makefile src/Makefile interfaces/Makefile app/Makefile \
 	tests/Makefile examples/Makefile cdi.settings \
-	examples/pio/Makefile src/cmake/libcdi/cdi-config.cmake src/cmake/libcdi/cdi-config-version.cmake \
+	examples/pio/Makefile src/cmake/cdi/cdi-config.cmake src/cmake/cdi/cdi-config-version.cmake \
         src/pkgconfig/cdi.pc src/pkgconfig/cdipio.pc src/pkgconfig/cdi_f2003.pc])
 AC_OUTPUT
 
diff --git a/doc/tex/c_quick_ref.tex b/doc/tex/c_quick_ref.tex
index 690c6789232da753f94cc5badca08f42c1a31fa6..daf8205cd8d41bfb2bf87273c7446844b25b6d00 100644
--- a/doc/tex/c_quick_ref.tex
+++ b/doc/tex/c_quick_ref.tex
@@ -1065,15 +1065,6 @@ Define the data type of a Variable.
 Set an arbitrary keyword/double value pair for GRIB API.
 
 
-\section*{\tt \htmlref{vlistDefVarExtra}{vlistDefVarExtra}}
-
-\begin{verbatim}
-    void vlistDefVarExtra (int vlistID, int varID, const char *extra);
-\end{verbatim}
-
-Define extra information of a Variable.
-
-
 \section*{\tt \htmlref{vlistDefVarIntKey}{vlistDefVarIntKey}}
 
 \begin{verbatim}
@@ -1210,15 +1201,6 @@ Get the data type of a Variable.
 raw access to GRIB meta-data.
 
 
-\section*{\tt \htmlref{vlistInqVarExtra}{vlistInqVarExtra}}
-
-\begin{verbatim}
-    void vlistInqVarExtra (int vlistID, int varID, char *extra);
-\end{verbatim}
-
-Get extra information of a Variable.
-
-
 \section*{\tt \htmlref{vlistInqVarIntKey}{vlistInqVarIntKey}}
 
 \begin{verbatim}
diff --git a/doc/tex/cdi_cman.tex b/doc/tex/cdi_cman.tex
index 14a8fd4315cd24589615726c818a7232ccfcef3c..a7143c1810b5ad412bc93967ad17f3b1df12a539 100644
--- a/doc/tex/cdi_cman.tex
+++ b/doc/tex/cdi_cman.tex
@@ -47,6 +47,7 @@
   \renewcommand{\headrulewidth}{0pt}
 }
 
+\usepackage{html}
 \usepackage{exscale}
 \usepackage{array,colortbl}    % color table
 
@@ -135,7 +136,7 @@
 \end{picture}
 
 \begin{flushright}
-{\large\bfseries Climate Data Interface \\ Version 2.0.0 \\ October 2021}
+{\large\bfseries Climate Data Interface \\ Version 2.2.0 \\ October 2023}
 \end{flushright}
 
 \vfill
diff --git a/doc/tex/cdi_fman.tex b/doc/tex/cdi_fman.tex
index 37a76cb994dac6f486f20cd8230a02b15bb41e52..a656e41b287218e86ebf2566b5b8233d193e6af4 100644
--- a/doc/tex/cdi_fman.tex
+++ b/doc/tex/cdi_fman.tex
@@ -45,6 +45,7 @@
   \renewcommand{\headrulewidth}{0pt}
 }
 
+\usepackage{html}
 \usepackage{exscale}
 \usepackage{array,colortbl}    % color table
 
@@ -132,7 +133,7 @@
 \end{picture}
 
 \begin{flushright}
-{\large\bfseries Climate Data Interface \\ Version 2.0.0 \\ October 2021}
+{\large\bfseries Climate Data Interface \\ Version 2.2.0 \\ October 2023}
 \end{flushright}
 
 \vfill
diff --git a/doc/tex/dataset.tex b/doc/tex/dataset.tex
index a0cef17c1fcbbca6801bed77a452ab04f99c3c80..cedca3be9976e2e42a915f2b920ea48fd3da555d 100644
--- a/doc/tex/dataset.tex
+++ b/doc/tex/dataset.tex
@@ -12,6 +12,7 @@ with one of the following predefined file format types:
 \item[{\large\texttt{CDI\_FILETYPE\_NC4}}]   File type NetCDF-4 (HDF5)
 \item[{\large\texttt{CDI\_FILETYPE\_NC4C}}]  File type NetCDF-4 classic
 \item[{\large\texttt{CDI\_FILETYPE\_NC5}}]   File type NetCDF version 5 (64-bit data)
+\item[{\large\texttt{CDI\_FILETYPE\_NCZARR}}]   File type NetCDF NCZarr
 \item[{\large\texttt{CDI\_FILETYPE\_SRV}}]   File type SERVICE
 \item[{\large\texttt{CDI\_FILETYPE\_EXT}}]   File type EXTRA
 \item[{\large\texttt{CDI\_FILETYPE\_IEG}}]   File type IEG
diff --git a/doc/tex/environment.tex b/doc/tex/environment.tex
index ba6b8f0efc496fbf1b5915231c1e28f73560d62a..c086ffc2415d0202abb8ef178e1521cfc813f098 100644
--- a/doc/tex/environment.tex
+++ b/doc/tex/environment.tex
@@ -11,9 +11,12 @@ The following table describes the environment variables that affect {\CDI}.
 %\cellcolor{pcolor2}
 {\bfseries Variable name}           &  {\bfseries Default} & {\bfseries Description} \\ \hline
 CDI\_CONVERT\_CUBESPHERE &        1   & Convert cubed-sphere data to unstructured grid. \\
+CDI\_CHUNK\_CACHE            &         0   & Set the NetCDF4 chunk cache size. \\
+CDI\_CHUNK\_CACHE\_MAX  &         0   & Set maximum chunk cache size. \\
 CDI\_GRIB1\_TEMPLATE          &   None   &  Path to a GRIB1 template file for GRIB\_API. \\
 CDI\_GRIB2\_TEMPLATE          &   None   &  Path to a GRIB2 template file for GRIB\_API. \\
 CDI\_INVENTORY\_MODE        &   None   &  Set to time to skip double variable entries. \\
 CDI\_READ\_CELL\_CORNERS  &         1   &  Read grid cell corners. \\
+CDI\_SHUFFLE                            &         0   & Set shuffle option to NetCDF4 deflation compression. \\
 CDI\_VERSION\_INFO               &         1   &  Set to 0 to disable NetCDF global attribute CDI.
 \end{tabular}
diff --git a/doc/tex/f_quick_ref.tex b/doc/tex/f_quick_ref.tex
index b44741069d603cdec19e356a0db7954428afa7be..e72627a4db4e4b3701c48314b17ad8e3ea86bf09 100644
--- a/doc/tex/f_quick_ref.tex
+++ b/doc/tex/f_quick_ref.tex
@@ -1077,15 +1077,6 @@ Define the data type of a Variable.
 Set an arbitrary keyword/double value pair for GRIB API.
 
 
-\section*{\tt \htmlref{vlistDefVarExtra}{vlistDefVarExtra}}
-
-\begin{verbatim}
-    SUBROUTINE vlistDefVarExtra (INTEGER vlistID, INTEGER varID, CHARACTER*(*) extra)
-\end{verbatim}
-
-Define extra information of a Variable.
-
-
 \section*{\tt \htmlref{vlistDefVarIntKey}{vlistDefVarIntKey}}
 
 \begin{verbatim}
@@ -1229,15 +1220,6 @@ Get the data type of a Variable.
 raw access to GRIB meta-data.
 
 
-\section*{\tt \htmlref{vlistInqVarExtra}{vlistInqVarExtra}}
-
-\begin{verbatim}
-    SUBROUTINE vlistInqVarExtra (INTEGER vlistID, INTEGER varID, CHARACTER*(*) extra)
-\end{verbatim}
-
-Get extra information of a Variable.
-
-
 \section*{\tt \htmlref{vlistInqVarIntKey}{vlistInqVarIntKey}}
 
 \begin{verbatim}
diff --git a/doc/tex/keys.tex b/doc/tex/keys.tex
index 6e54ecd26ed14a592eee52e067520ec5d88b8405..cc56e1f0bc9d1c31bf1e70763e391f6d38dae3ee 100644
--- a/doc/tex/keys.tex
+++ b/doc/tex/keys.tex
@@ -10,10 +10,10 @@ Use the variable ID or one of the following identifiers for the coordinates:
 
 \vspace*{3mm}
 \hspace*{8mm}\begin{minipage}{15cm}
-\begin{deflist}{\large\texttt{CDI\_KEY\_GLOBAL \ \ }}
-\item[\large\texttt{CDI\_KEY\_XAXIS}]   X-axis ID
-\item[\large\texttt{CDI\_KEY\_YAXIS}]   Y-axis ID 
-\item[\large\texttt{CDI\_KEY\_GLOBAL}]   Global Z-axis
+\begin{deflist}{\large\texttt{CDI\_GLOBAL \ \ }}
+\item[\large\texttt{CDI\_XAXIS}]   X-axis ID
+\item[\large\texttt{CDI\_YAXIS}]   Y-axis ID 
+\item[\large\texttt{CDI\_GLOBAL}]   Global Z-axis
 \end{deflist}
 \end{minipage}
 \vspace*{4mm}
@@ -48,12 +48,22 @@ The following key attributes are available:
 \item[\large\texttt{CDI\_KEY\_NUMBEROFGRIDINREFERENCE}]   GRIB2 numberOfGridInReference
 \item[\large\texttt{CDI\_KEY\_NUMBEROFVGRIDUSED}]   GRIB2 numberOfVGridUsed
 \item[\large\texttt{CDI\_KEY\_NLEV}]   GRIB2 nlev
+\item[\large\texttt{CDI\_KEY\_CHUNKTYPE}]   ChunkType: CDI\_CHUNK\_AUTO/CDI\_CHUNK\_GRID/CDI\_CHUNK\_LINES
+\item[\large\texttt{CDI\_KEY\_CHUNKSIZE}]   ChunkSize
 \end{deflist}
 \end{minipage}
 \vspace*{4mm}
 
 \textbf{Floating point keys}
 
+\vspace*{3mm}
+\hspace*{8mm}\begin{minipage}{15cm}
+\begin{deflist}{\large\texttt{CDI\_KEY\_MISSVAL \ \ }}
+\item[\large\texttt{CDI\_KEY\_MISSVAL}]   Missing value
+\end{deflist}
+\end{minipage}
+\vspace*{4mm}
+
 \textbf{Byte array keys}
 
 \vspace*{3mm}
diff --git a/examples/pio/Makefile.am b/examples/pio/Makefile.am
index 82f232df7a853f2ec7325990e497572ec8c2ae58..e840afb55e1a0c0a20ec1ae8f9dfa28b98d18604 100644
--- a/examples/pio/Makefile.am
+++ b/examples/pio/Makefile.am
@@ -16,8 +16,8 @@ endif
 collectData_SOURCES=collectData.c
 
 if USE_MPI
-LDADD=$(top_builddir)/src/libcdipio.la $(LIBRT) $(MPI_C_LIB)
-collectData2003_LDADD=$(top_builddir)/src/libcdipio.la $(LIBRT) $(MPI_FC_LIB)
+LDADD=$(top_builddir)/src/libcdipio.la $(top_builddir)/src/libcdi.la $(YAXT_LIBS) $(MPI_C_LIB)
+collectData2003_LDADD=$(top_builddir)/src/libcdipio.la $(top_builddir)/src/libcdi.la $(YAXT_LIBS) $(MPI_FC_LIB)
 else
 LDADD=$(top_builddir)/src/libcdi.la
 collectData2003_LDADD=$(top_builddir)/src/libcdi.la
diff --git a/interfaces/cdi.cpp b/interfaces/cdi.cpp
index 0894b58414cc68f3cd44a39eb805827c26143a5f..fe3d33871c4692bbc37c01ce03502fb16a475a3b 100644
--- a/interfaces/cdi.cpp
+++ b/interfaces/cdi.cpp
@@ -288,7 +288,7 @@ double *
 CdiVariable::getValuesAsPointer()
 {
   int levelID = 0, tsID = 0;
-  size_t nmiss;
+  SizeType nmiss;
 
   int nrecs = streamInqTimestep(streamID, tsID);
   int vdate = taxisInqVdate(taxisID);
@@ -303,7 +303,7 @@ double **
 CdiVariable::getValuesWithLevelAsPointer(int tsID)
 {
   int levelID, nrecs;
-  size_t nmiss;
+  SizeType nmiss;
   double **fieldWithLevel, *field;
 
   nrecs = streamInqTimestep(streamID, tsID);
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
index d383ad5c6d6a5061370800bb1dc89b7a334c0638..1598d077ff020f1f0be8388fded01c871c946354 100644
--- a/m4/ax_pthread.m4
+++ b/m4/ax_pthread.m4
@@ -1,5 +1,5 @@
 # ===========================================================================
-#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+#        https://www.gnu.org/software/autoconf-archive/ax_pthread.html
 # ===========================================================================
 #
 # SYNOPSIS
@@ -19,10 +19,10 @@
 #   is necessary on AIX to use the special cc_r compiler alias.)
 #
 #   NOTE: You are assumed to not only compile your program with these flags,
-#   but also link it with them as well. e.g. you should link with
+#   but also to link with them as well. For example, you might link with
 #   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
 #
-#   If you are only building threads programs, you may wish to use these
+#   If you are only building threaded programs, you may wish to use these
 #   variables in your default LIBS, CFLAGS, and CC:
 #
 #     LIBS="$PTHREAD_LIBS $LIBS"
@@ -30,8 +30,8 @@
 #     CC="$PTHREAD_CC"
 #
 #   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
-#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
-#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#   has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
+#   that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
 #
 #   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
 #   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
@@ -55,6 +55,7 @@
 #
 #   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
 #   Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
+#   Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl>
 #
 #   This program is free software: you can redistribute it and/or modify it
 #   under the terms of the GNU General Public License as published by the
@@ -67,7 +68,7 @@
 #   Public License for more details.
 #
 #   You should have received a copy of the GNU General Public License along
-#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#   with this program. If not, see <https://www.gnu.org/licenses/>.
 #
 #   As a special exception, the respective Autoconf Macro's copyright owner
 #   gives unlimited permission to copy, distribute and modify the configure
@@ -82,35 +83,40 @@
 #   modified version of the Autoconf Macro, you may extend this special
 #   exception to the GPL to apply to your modified version as well.
 
-#serial 21
+#serial 27
 
 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
 AC_DEFUN([AX_PTHREAD], [
 AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([AC_PROG_CC])
+AC_REQUIRE([AC_PROG_SED])
 AC_LANG_PUSH([C])
 ax_pthread_ok=no
 
 # We used to check for pthread.h first, but this fails if pthread.h
-# requires special compiler flags (e.g. on True64 or Sequent).
+# requires special compiler flags (e.g. on Tru64 or Sequent).
 # It gets checked for in the link test anyway.
 
 # First of all, check if the user has set any of the PTHREAD_LIBS,
 # etcetera environment variables, and if threads linking works using
 # them:
-if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
-        save_CFLAGS="$CFLAGS"
+if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
+        ax_pthread_save_CC="$CC"
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
         CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-        save_LIBS="$LIBS"
         LIBS="$PTHREAD_LIBS $LIBS"
-        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
-        AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
+        AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
+        AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
         AC_MSG_RESULT([$ax_pthread_ok])
-        if test x"$ax_pthread_ok" = xno; then
+        if test "x$ax_pthread_ok" = "xno"; then
                 PTHREAD_LIBS=""
                 PTHREAD_CFLAGS=""
         fi
-        LIBS="$save_LIBS"
-        CFLAGS="$save_CFLAGS"
+        CC="$ax_pthread_save_CC"
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
 fi
 
 # We must check for the threads library under a number of different
@@ -118,12 +124,14 @@ fi
 # (e.g. DEC) have both -lpthread and -lpthreads, where one of the
 # libraries is broken (non-POSIX).
 
-# Create a list of thread flags to try.  Items starting with a "-" are
-# C compiler flags, and other items are library names, except for "none"
-# which indicates that we try without any flags at all, and "pthread-config"
-# which is a program returning the flags for the Pth emulation library.
+# Create a list of thread flags to try. Items with a "," contain both
+# C compiler flags (before ",") and linker flags (after ","). Other items
+# starting with a "-" are C compiler flags, and remaining items are
+# library names, except for "none" which indicates that we try without
+# any flags at all, and "pthread-config" which is a program returning
+# the flags for the Pth emulation library.
 
-ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
 
 # The ordering *is* (sometimes) important.  Some notes on the
 # individual items follow:
@@ -132,82 +140,163 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt
 # none: in case threads are in libc; should be tried before -Kthread and
 #       other compiler flags to prevent continual compiler warnings
 # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
-# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
-# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
-# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
-# -pthreads: Solaris/gcc
-# -mthreads: Mingw32/gcc, Lynx/gcc
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
+#           (Note: HP C rejects this with "bad form for `-t' option")
+# -pthreads: Solaris/gcc (Note: HP C also rejects)
 # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
-#      doesn't hurt to check since this sometimes defines pthreads too;
-#      also defines -D_REENTRANT)
-#      ... -mt is also the pthreads flag for HP/aCC
+#      doesn't hurt to check since this sometimes defines pthreads and
+#      -D_REENTRANT too), HP C (must be checked before -lpthread, which
+#      is present but should not be used directly; and before -mthreads,
+#      because the compiler interprets this as "-mt" + "-hreads")
+# -mthreads: Mingw32/gcc, Lynx/gcc
 # pthread: Linux, etcetera
 # --thread-safe: KAI C++
 # pthread-config: use pthread-config program (for GNU Pth library)
 
-case ${host_os} in
+case $host_os in
+
+        freebsd*)
+
+        # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+        # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+
+        ax_pthread_flags="-kthread lthread $ax_pthread_flags"
+        ;;
+
+        hpux*)
+
+        # From the cc(1) man page: "[-mt] Sets various -D flags to enable
+        # multi-threading and also sets -lpthread."
+
+        ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
+        ;;
+
+        openedition*)
+
+        # IBM z/OS requires a feature-test macro to be defined in order to
+        # enable POSIX threads at all, so give the user a hint if this is
+        # not set. (We don't define these ourselves, as they can affect
+        # other portions of the system API in unpredictable ways.)
+
+        AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
+            [
+#            if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
+             AX_PTHREAD_ZOS_MISSING
+#            endif
+            ],
+            [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
+        ;;
+
         solaris*)
 
         # On Solaris (at least, for some versions), libc contains stubbed
         # (non-functional) versions of the pthreads routines, so link-based
-        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
-        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
-        # a function called by this macro, so we could check for that, but
-        # who knows whether they'll stub that too in a future libc.)  So,
-        # we'll just look for -pthreads and -lpthread first:
+        # tests will erroneously succeed. (N.B.: The stubs are missing
+        # pthread_cleanup_push, or rather a function called by this macro,
+        # so we could check for that, but who knows whether they'll stub
+        # that too in a future libc.)  So we'll check first for the
+        # standard Solaris way of linking pthreads (-mt -lpthread).
+
+        ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
+        ;;
+esac
+
+# Are we compiling with Clang?
+
+AC_CACHE_CHECK([whether $CC is Clang],
+    [ax_cv_PTHREAD_CLANG],
+    [ax_cv_PTHREAD_CLANG=no
+     # Note that Autoconf sets GCC=yes for Clang as well as GCC
+     if test "x$GCC" = "xyes"; then
+        AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
+            [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+#            if defined(__clang__) && defined(__llvm__)
+             AX_PTHREAD_CC_IS_CLANG
+#            endif
+            ],
+            [ax_cv_PTHREAD_CLANG=yes])
+     fi
+    ])
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+
+# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
+
+# Note that for GCC and Clang -pthread generally implies -lpthread,
+# except when -nostdlib is passed.
+# This is problematic using libtool to build C++ shared libraries with pthread:
+# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
+# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
+# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
+# To solve this, first try -pthread together with -lpthread for GCC
+
+AS_IF([test "x$GCC" = "xyes"],
+      [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
+
+# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
+
+AS_IF([test "x$ax_pthread_clang" = "xyes"],
+      [ax_pthread_flags="-pthread,-lpthread -pthread"])
 
-        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
+
+# The presence of a feature test macro requesting re-entrant function
+# definitions is, on some systems, a strong hint that pthreads support is
+# correctly enabled
+
+case $host_os in
+        darwin* | hpux* | linux* | osf* | solaris*)
+        ax_pthread_check_macro="_REENTRANT"
         ;;
 
-        darwin*)
-        ax_pthread_flags="-pthread $ax_pthread_flags"
+        aix*)
+        ax_pthread_check_macro="_THREAD_SAFE"
         ;;
-esac
 
-# Clang doesn't consider unrecognized options an error unless we specify
-# -Werror. We throw in some extra Clang-specific options to ensure that
-# this doesn't happen for GCC, which also accepts -Werror.
+        *)
+        ax_pthread_check_macro="--"
+        ;;
+esac
+AS_IF([test "x$ax_pthread_check_macro" = "x--"],
+      [ax_pthread_check_cond=0],
+      [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
 
-AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
-save_CFLAGS="$CFLAGS"
-ax_pthread_extra_flags="-Werror"
-CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
-                  [AC_MSG_RESULT([yes])],
-                  [ax_pthread_extra_flags=
-                   AC_MSG_RESULT([no])])
-CFLAGS="$save_CFLAGS"
 
-if test x"$ax_pthread_ok" = xno; then
-for flag in $ax_pthread_flags; do
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
 
-        case $flag in
+        case $ax_pthread_try_flag in
                 none)
                 AC_MSG_CHECKING([whether pthreads work without any flags])
                 ;;
 
+                *,*)
+                PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
+                PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
+                AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
+                ;;
+
                 -*)
-                AC_MSG_CHECKING([whether pthreads work with $flag])
-                PTHREAD_CFLAGS="$flag"
+                AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
+                PTHREAD_CFLAGS="$ax_pthread_try_flag"
                 ;;
 
                 pthread-config)
                 AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
-                if test x"$ax_pthread_config" = xno; then continue; fi
+                AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
                 PTHREAD_CFLAGS="`pthread-config --cflags`"
                 PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
                 ;;
 
                 *)
-                AC_MSG_CHECKING([for the pthreads library -l$flag])
-                PTHREAD_LIBS="-l$flag"
+                AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
+                PTHREAD_LIBS="-l$ax_pthread_try_flag"
                 ;;
         esac
 
-        save_LIBS="$LIBS"
-        save_CFLAGS="$CFLAGS"
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
         LIBS="$PTHREAD_LIBS $LIBS"
-        CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
 
         # Check for various functions.  We must include pthread.h,
         # since some functions may be macros.  (On the Sequent, we
@@ -218,8 +307,18 @@ for flag in $ax_pthread_flags; do
         # pthread_cleanup_push because it is one of the few pthread
         # functions on Solaris that doesn't have a non-functional libc stub.
         # We try pthread_create on general principles.
+
         AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
-                        static void routine(void *a) { a = 0; }
+#                       if $ax_pthread_check_cond
+#                        error "$ax_pthread_check_macro must be defined"
+#                       endif
+                        static void *some_global = NULL;
+                        static void routine(void *a)
+                          {
+                             /* To avoid any unused-parameter or
+                                unused-but-set-parameter warning.  */
+                             some_global = a;
+                          }
                         static void *start_routine(void *a) { return a; }],
                        [pthread_t th; pthread_attr_t attr;
                         pthread_create(&th, 0, start_routine, 0);
@@ -227,88 +326,164 @@ for flag in $ax_pthread_flags; do
                         pthread_attr_init(&attr);
                         pthread_cleanup_push(routine, 0);
                         pthread_cleanup_pop(0) /* ; */])],
-                [ax_pthread_ok=yes],
-                [])
+            [ax_pthread_ok=yes],
+            [])
 
-        LIBS="$save_LIBS"
-        CFLAGS="$save_CFLAGS"
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
 
         AC_MSG_RESULT([$ax_pthread_ok])
-        if test "x$ax_pthread_ok" = xyes; then
-                break;
-        fi
+        AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
 
         PTHREAD_LIBS=""
         PTHREAD_CFLAGS=""
 done
 fi
 
+
+# Clang needs special handling, because older versions handle the -pthread
+# option in a rather... idiosyncratic way
+
+if test "x$ax_pthread_clang" = "xyes"; then
+
+        # Clang takes -pthread; it has never supported any other flag
+
+        # (Note 1: This will need to be revisited if a system that Clang
+        # supports has POSIX threads in a separate library.  This tends not
+        # to be the way of modern systems, but it's conceivable.)
+
+        # (Note 2: On some systems, notably Darwin, -pthread is not needed
+        # to get POSIX threads support; the API is always present and
+        # active.  We could reasonably leave PTHREAD_CFLAGS empty.  But
+        # -pthread does define _REENTRANT, and while the Darwin headers
+        # ignore this macro, third-party headers might not.)
+
+        # However, older versions of Clang make a point of warning the user
+        # that, in an invocation where only linking and no compilation is
+        # taking place, the -pthread option has no effect ("argument unused
+        # during compilation").  They expect -pthread to be passed in only
+        # when source code is being compiled.
+        #
+        # Problem is, this is at odds with the way Automake and most other
+        # C build frameworks function, which is that the same flags used in
+        # compilation (CFLAGS) are also used in linking.  Many systems
+        # supported by AX_PTHREAD require exactly this for POSIX threads
+        # support, and in fact it is often not straightforward to specify a
+        # flag that is used only in the compilation phase and not in
+        # linking.  Such a scenario is extremely rare in practice.
+        #
+        # Even though use of the -pthread flag in linking would only print
+        # a warning, this can be a nuisance for well-run software projects
+        # that build with -Werror.  So if the active version of Clang has
+        # this misfeature, we search for an option to squash it.
+
+        AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
+            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
+            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
+             # Create an alternate version of $ac_link that compiles and
+             # links in two steps (.c -> .o, .o -> exe) instead of one
+             # (.c -> exe), because the warning occurs only in the second
+             # step
+             ax_pthread_save_ac_link="$ac_link"
+             ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
+             ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
+             ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
+             ax_pthread_save_CFLAGS="$CFLAGS"
+             for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
+                AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
+                CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
+                ac_link="$ax_pthread_save_ac_link"
+                AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+                    [ac_link="$ax_pthread_2step_ac_link"
+                     AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+                         [break])
+                    ])
+             done
+             ac_link="$ax_pthread_save_ac_link"
+             CFLAGS="$ax_pthread_save_CFLAGS"
+             AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
+             ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
+            ])
+
+        case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
+                no | unknown) ;;
+                *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
+        esac
+
+fi # $ax_pthread_clang = yes
+
+
+
 # Various other checks:
-if test "x$ax_pthread_ok" = xyes; then
-        save_LIBS="$LIBS"
-        LIBS="$PTHREAD_LIBS $LIBS"
-        save_CFLAGS="$CFLAGS"
+if test "x$ax_pthread_ok" = "xyes"; then
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
         CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
 
         # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
-        AC_MSG_CHECKING([for joinable pthread attribute])
-        attr_name=unknown
-        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
-            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
-                           [int attr = $attr; return attr /* ; */])],
-                [attr_name=$attr; break],
-                [])
-        done
-        AC_MSG_RESULT([$attr_name])
-        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
-            AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
-                               [Define to necessary symbol if this constant
-                                uses a non-standard name on your system.])
-        fi
-
-        AC_MSG_CHECKING([if more special flags are required for pthreads])
-        flag=no
-        case ${host_os} in
-            aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
-            osf* | hpux*) flag="-D_REENTRANT";;
-            solaris*)
-            if test "$GCC" = "yes"; then
-                flag="-D_REENTRANT"
-            else
-                # TODO: What about Clang on Solaris?
-                flag="-mt -D_REENTRANT"
-            fi
-            ;;
-        esac
-        AC_MSG_RESULT([$flag])
-        if test "x$flag" != xno; then
-            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
-        fi
+        AC_CACHE_CHECK([for joinable pthread attribute],
+            [ax_cv_PTHREAD_JOINABLE_ATTR],
+            [ax_cv_PTHREAD_JOINABLE_ATTR=unknown
+             for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+                 AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+                                                 [int attr = $ax_pthread_attr; return attr /* ; */])],
+                                [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
+                                [])
+             done
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
+               test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
+               test "x$ax_pthread_joinable_attr_defined" != "xyes"],
+              [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
+                                  [$ax_cv_PTHREAD_JOINABLE_ATTR],
+                                  [Define to necessary symbol if this constant
+                                   uses a non-standard name on your system.])
+               ax_pthread_joinable_attr_defined=yes
+              ])
+
+        AC_CACHE_CHECK([whether more special flags are required for pthreads],
+            [ax_cv_PTHREAD_SPECIAL_FLAGS],
+            [ax_cv_PTHREAD_SPECIAL_FLAGS=no
+             case $host_os in
+             solaris*)
+             ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
+             ;;
+             esac
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
+               test "x$ax_pthread_special_flags_added" != "xyes"],
+              [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
+               ax_pthread_special_flags_added=yes])
 
         AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
-            [ax_cv_PTHREAD_PRIO_INHERIT], [
-                AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
-                                                [[int i = PTHREAD_PRIO_INHERIT;]])],
-                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
-                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
+            [ax_cv_PTHREAD_PRIO_INHERIT],
+            [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+                                             [[int i = PTHREAD_PRIO_INHERIT;
+                                               return i;]])],
+                            [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+                            [ax_cv_PTHREAD_PRIO_INHERIT=no])
             ])
-        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
-            [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
+        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
+               test "x$ax_pthread_prio_inherit_defined" != "xyes"],
+              [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
+               ax_pthread_prio_inherit_defined=yes
+              ])
 
-        LIBS="$save_LIBS"
-        CFLAGS="$save_CFLAGS"
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
 
         # More AIX lossage: compile with *_r variant
-        if test "x$GCC" != xyes; then
+        if test "x$GCC" != "xyes"; then
             case $host_os in
                 aix*)
                 AS_CASE(["x/$CC"],
-                  [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
-                  [#handle absolute path differently from PATH based program lookup
-                   AS_CASE(["x$CC"],
-                     [x/*],
-                     [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
-                     [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+                    [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
+                    [#handle absolute path differently from PATH based program lookup
+                     AS_CASE(["x$CC"],
+                         [x/*],
+                         [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
+                         [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
                 ;;
             esac
         fi
@@ -321,7 +496,7 @@ AC_SUBST([PTHREAD_CFLAGS])
 AC_SUBST([PTHREAD_CC])
 
 # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
-if test x"$ax_pthread_ok" = xyes; then
+if test "x$ax_pthread_ok" = "xyes"; then
         ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
         :
 else
diff --git a/patch/ltmain.sh.nag_pthread.patch b/patch/ltmain.sh.nag_pthread.patch
index 4ec8747158f956419fdc34046049e88782d535be..63b3d3c66dd379150633c99c24e80358171e20f2 100644
--- a/patch/ltmain.sh.nag_pthread.patch
+++ b/patch/ltmain.sh.nag_pthread.patch
@@ -8,7 +8,7 @@
 +	  # Additionally convert " -pthread" to " -Wl,-pthread" for nagfor
 +	  func_cc_basename $CC
 +	  case $func_cc_basename_result in
-+	    nagfor*) tmp_inherited_linker_flags=`$ECHO "$tmp_inherited_linker_flags" | $SED 's/ -pthread/ -Wl,-pthread/g'` ;;
++	    nagfor*) tmp_inherited_linker_flags=`$ECHO " $tmp_inherited_linker_flags" | $SED 's/ -pthread/ -Wl,-pthread/g'` ;;
 +	  esac
 +
  	  for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
diff --git a/src/Makefile.am b/src/Makefile.am
index 2cea954ce896dc240fad72049bd1d2d62c9b0d90..77e1c06cbbe4c46157ffebb9d482887d8b935d1a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -259,7 +259,7 @@ libcdipio_la_SOURCES += $(libcdipio_la_HAVE_PARALLEL_NC4_extra_sources)
 endif
 endif
 
-libcdipio_la_LIBADD   = libcdi.la $(PPM_CORE_LIBS) $(YAXT_LIBS) $(MPI_C_LIB)
+libcdipio_la_LIBADD   = libcdi.la $(LIBRT) $(PPM_CORE_LIBS) $(YAXT_LIBS) $(MPI_C_LIB)
 
 #
 #cdilib.c:
@@ -270,8 +270,8 @@ libcdipio_la_LIBADD   = libcdi.la $(PPM_CORE_LIBS) $(YAXT_LIBS) $(MPI_C_LIB)
 
 LOCALTARGETS  =
 if ENABLE_CDI_LIB
-LOCALTARGETS += cmake/libcdi/cdi-config.cmake
-LOCALTARGETS += cmake/libcdi/cdi-config-version.cmake
+LOCALTARGETS += cmake/cdi/cdi-config.cmake
+LOCALTARGETS += cmake/cdi/cdi-config-version.cmake
 LOCALTARGETS += pkgconfig/cdi.pc
 if USE_MPI
 LOCALTARGETS += pkgconfig/cdipio.pc
@@ -295,11 +295,11 @@ mo_cdi.$(FCMODEXT): mo_cdi.lo
 endif
 	@if test ! -f $@; then rm -f $<; $(MAKE) $<; fi
 #
-cmake/libcdi/cdi-config.cmake: cmake/libcdi/cdi-config.cmake.in ../config.status
-	(cd .. ; ./config.status src/cmake/libcdi/cdi-config.cmake)
+cmake/cdi/cdi-config.cmake: cmake/cdi/cdi-config.cmake.in ../config.status
+	(cd .. ; ./config.status src/cmake/cdi/cdi-config.cmake)
 
-cmake/libcdi/cdi-config-version.cmake: cmake/libcdi/cdi-config-version.cmake.in ../config.status
-	(cd .. ; ./config.status src/cmake/libcdi/cdi-config-version.cmake)
+cmake/cdi/cdi-config-version.cmake: cmake/cdi/cdi-config-version.cmake.in ../config.status
+	(cd .. ; ./config.status src/cmake/cdi/cdi-config-version.cmake)
 
 pkgconfig/cdi.pc: pkgconfig/cdi.pc.in ../config.status
 	(cd .. ; ./config.status src/pkgconfig/cdi.pc)
@@ -326,10 +326,10 @@ endif
 endif
 
 if ENABLE_CDI_LIB
-CMAKECONFIG_FILES = cmake/libcdi/cdi-config.cmake
-CLEANFILES += cmake/libcdi/cdi-config.cmake
-CMAKECONFIG_FILES += cmake/libcdi/cdi-config-version.cmake
-CLEANFILES += cmake/libcdi/cdi-config-version.cmake
+CMAKECONFIG_FILES = cmake/cdi/cdi-config.cmake
+CLEANFILES += cmake/cdi/cdi-config.cmake
+CMAKECONFIG_FILES += cmake/cdi/cdi-config-version.cmake
+CLEANFILES += cmake/cdi/cdi-config-version.cmake
 PKGCONFIG_FILES = pkgconfig/cdi.pc
 CLEANFILES += pkgconfig/cdi.pc
 if USE_MPI
diff --git a/src/calendar.h b/src/calendar.h
index dad6978c7ebb10f889ed9b355cf37215e84946ed..cf38f24d7355af213743d526d27ba68960d1f58a 100644
--- a/src/calendar.h
+++ b/src/calendar.h
@@ -2,7 +2,7 @@
 #define CALENDAR_H
 
 #include "cdi.h"
-#include <stdint.h>    // int64_t
+#include <stdint.h>  // int64_t
 
 // clang-format off
 
diff --git a/src/cdf.c b/src/cdf.c
index 8b0061cd6c60db4e7c65935fcaccc3b61b311fdc..0c81882bb26958cdad3370c003d6733363e2b32a 100644
--- a/src/cdf.c
+++ b/src/cdf.c
@@ -42,9 +42,9 @@ hdfLibraryVersion(void)
       unsigned majnum, minnum, relnum;
       H5get_libversion(&majnum, &minnum, &relnum);
 #ifdef HAVE_NC4HDF5_THREADSAFE
-      sprintf(hdf_libvers, "%u.%u.%u threadsafe", majnum, minnum, relnum);
+      snprintf(hdf_libvers, sizeof(hdf_libvers), "%u.%u.%u threadsafe", majnum, minnum, relnum);
 #else
-      sprintf(hdf_libvers, "%u.%u.%u", majnum, minnum, relnum);
+      snprintf(hdf_libvers, sizeof(hdf_libvers), "%u.%u.%u", majnum, minnum, relnum);
 #endif
     }
 
diff --git a/src/cdf_int.c b/src/cdf_int.c
index 80add6a6b157aab7b0840d88b4c450ff5d26a10e..e3485f02438959ed5723b7acf779a6f4e4ae2c8a 100644
--- a/src/cdf_int.c
+++ b/src/cdf_int.c
@@ -36,7 +36,7 @@ cdf__create(const char *path, int cmode, int *ncidp)
   size_t initialsz = 0;
 
 #if defined(__SX__) || defined(ES)
-  chunksizehint = 16777216; // 16 MB
+  chunksizehint = 16777216;  // 16 MB
 #endif
 
   if (CDI_Netcdf_Chunksizehint != CDI_UNDEFID) chunksizehint = (size_t) CDI_Netcdf_Chunksizehint;
diff --git a/src/cdf_read.c b/src/cdf_read.c
index 0e7bcb4de6e9dec21a0b72a97056660b917dd508..e1d53333f18a551b05b6329a46cb7d00dcba9bf8 100644
--- a/src/cdf_read.c
+++ b/src/cdf_read.c
@@ -93,12 +93,11 @@ cdfDoInputDataTransformationDP(int vlistID, int varID, size_t valueCount, double
   const int haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
   double validRange[2];
   if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange))) validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
-  const double offset = vlistInqVarAddoffset(vlistID, varID);
-  const double scaleFactor = vlistInqVarScalefactor(vlistID, varID);
+  double addoffset = 0.0, scalefactor = 1.0;
+  const int haveAddoffset = (cdiInqKeyFloat(vlistID, varID, CDI_KEY_ADDOFFSET, &addoffset) == CDI_NOERR);
+  const int haveScalefactor = (cdiInqKeyFloat(vlistID, varID, CDI_KEY_SCALEFACTOR, &scalefactor) == CDI_NOERR);
 
   const bool missValIsNaN = DBL_IS_NAN(missVal);
-  const int haveOffset = IS_NOT_EQUAL(offset, 0.0);
-  const int haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1.0);
   size_t missValCount = 0;
 
   double validMin = validRange[0];
@@ -109,33 +108,33 @@ cdfDoInputDataTransformationDP(int vlistID, int varID, size_t valueCount, double
   const int haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin, DBL_MIN));
   assert(!haveRangeCheck || haveMissVal);
 
-  switch (haveMissVal | (haveScaleFactor << 1) | (haveOffset << 2) | (haveRangeCheck << 3))
+  switch (haveMissVal | (haveScalefactor << 1) | (haveAddoffset << 2) | (haveRangeCheck << 3))
     {
-    case 15:  // haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset
+    case 15:  // haveRangeCheck & haveMissVal & haveScalefactor & haveAddoffset
       for (size_t i = 0; i < valueCount; ++i)
         {
           int outOfRange = (data[i] < validMin || data[i] > validMax);
           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
           missValCount += (size_t) (outOfRange | isMissVal);
-          data[i] = outOfRange ? missVal : isMissVal ? data[i] : data[i] * scaleFactor + offset;
+          data[i] = outOfRange ? missVal : isMissVal ? data[i] : data[i] * scalefactor + addoffset;
         }
       break;
-    case 13:  // haveRangeCheck & haveMissVal & haveOffset
+    case 13:  // haveRangeCheck & haveMissVal & haveAddoffset
       for (size_t i = 0; i < valueCount; ++i)
         {
           int outOfRange = (data[i] < validMin || data[i] > validMax);
           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
           missValCount += (size_t) (outOfRange | isMissVal);
-          data[i] = outOfRange ? missVal : isMissVal ? data[i] : data[i] + offset;
+          data[i] = outOfRange ? missVal : isMissVal ? data[i] : data[i] + addoffset;
         }
       break;
-    case 11:  // haveRangeCheck & haveMissVal & haveScaleFactor
+    case 11:  // haveRangeCheck & haveMissVal & haveScalefactor
       for (size_t i = 0; i < valueCount; ++i)
         {
           int outOfRange = (data[i] < validMin || data[i] > validMax);
           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
           missValCount += (size_t) (outOfRange | isMissVal);
-          data[i] = outOfRange ? missVal : isMissVal ? data[i] : data[i] * scaleFactor;
+          data[i] = outOfRange ? missVal : isMissVal ? data[i] : data[i] * scalefactor;
         }
       break;
     case 9:  // haveRangeCheck & haveMissVal
@@ -147,35 +146,35 @@ cdfDoInputDataTransformationDP(int vlistID, int varID, size_t valueCount, double
           data[i] = outOfRange ? missVal : data[i];
         }
       break;
-    case 7:  // haveMissVal & haveScaleFactor & haveOffset
+    case 7:  // haveMissVal & haveScalefactor & haveAddoffset
       for (size_t i = 0; i < valueCount; ++i)
         if (DBL_IS_EQUAL(data[i], missVal))
           missValCount++;
         else
-          data[i] = data[i] * scaleFactor + offset;
+          data[i] = data[i] * scalefactor + addoffset;
       break;
-    case 6:  // haveOffset & haveScaleFactor
-      for (size_t i = 0; i < valueCount; ++i) data[i] = data[i] * scaleFactor + offset;
+    case 6:  // haveAddoffset & haveScalefactor
+      for (size_t i = 0; i < valueCount; ++i) data[i] = data[i] * scalefactor + addoffset;
       break;
-    case 5:  // haveMissVal & haveOffset
+    case 5:  // haveMissVal & haveAddoffset
       for (size_t i = 0; i < valueCount; ++i)
         if (DBL_IS_EQUAL(data[i], missVal))
           missValCount++;
         else
-          data[i] += offset;
+          data[i] += addoffset;
       break;
-    case 4:  // haveOffset
-      for (size_t i = 0; i < valueCount; ++i) data[i] += offset;
+    case 4:  // haveAddoffset
+      for (size_t i = 0; i < valueCount; ++i) data[i] += addoffset;
       break;
-    case 3:  // haveMissVal & haveScaleFactor
+    case 3:  // haveMissVal & haveScalefactor
       for (size_t i = 0; i < valueCount; ++i)
         if (DBL_IS_EQUAL(data[i], missVal))
           missValCount++;
         else
-          data[i] *= scaleFactor;
+          data[i] *= scalefactor;
       break;
-    case 2:  // haveScaleFactor
-      for (size_t i = 0; i < valueCount; ++i) data[i] *= scaleFactor;
+    case 2:  // haveScalefactor
+      for (size_t i = 0; i < valueCount; ++i) data[i] *= scalefactor;
       break;
     case 1:  // haveMissVal
       if (missValIsNaN)
@@ -199,12 +198,11 @@ cdfDoInputDataTransformationSP(int vlistID, int varID, size_t valueCount, float
   const int haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
   double validRange[2];
   if (!(haveMissVal && vlistInqVarValidrange(vlistID, varID, validRange))) validRange[0] = DBL_MIN, validRange[1] = DBL_MAX;
-  const double offset = vlistInqVarAddoffset(vlistID, varID);
-  const double scaleFactor = vlistInqVarScalefactor(vlistID, varID);
+  double addoffset = 0.0, scalefactor = 1.0;
+  const int haveAddoffset = (cdiInqKeyFloat(vlistID, varID, CDI_KEY_ADDOFFSET, &addoffset) == CDI_NOERR);
+  const int haveScalefactor = (cdiInqKeyFloat(vlistID, varID, CDI_KEY_SCALEFACTOR, &scalefactor) == CDI_NOERR);
 
   const bool missValIsNaN = DBL_IS_NAN(missVal);
-  const int haveOffset = IS_NOT_EQUAL(offset, 0.0);
-  const int haveScaleFactor = IS_NOT_EQUAL(scaleFactor, 1.0);
   size_t missValCount = 0;
 
   double validMin = validRange[0];
@@ -215,33 +213,33 @@ cdfDoInputDataTransformationSP(int vlistID, int varID, size_t valueCount, float
   const int haveRangeCheck = (IS_NOT_EQUAL(validMax, DBL_MAX)) | (IS_NOT_EQUAL(validMin, DBL_MIN));
   assert(!haveRangeCheck || haveMissVal);
 
-  switch (haveMissVal | (haveScaleFactor << 1) | (haveOffset << 2) | (haveRangeCheck << 3))
+  switch (haveMissVal | (haveScalefactor << 1) | (haveAddoffset << 2) | (haveRangeCheck << 3))
     {
-    case 15:  // haveRangeCheck & haveMissVal & haveScaleFactor & haveOffset
+    case 15:  // haveRangeCheck & haveMissVal & haveScalefactor & haveAddoffset
       for (size_t i = 0; i < valueCount; ++i)
         {
           int outOfRange = (data[i] < validMin || data[i] > validMax);
           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
           missValCount += (size_t) (outOfRange | isMissVal);
-          data[i] = outOfRange ? (float) missVal : isMissVal ? data[i] : (float) (data[i] * scaleFactor + offset);
+          data[i] = outOfRange ? (float) missVal : isMissVal ? data[i] : (float) (data[i] * scalefactor + addoffset);
         }
       break;
-    case 13:  // haveRangeCheck & haveMissVal & haveOffset
+    case 13:  // haveRangeCheck & haveMissVal & haveAddoffset
       for (size_t i = 0; i < valueCount; ++i)
         {
           int outOfRange = (data[i] < validMin || data[i] > validMax);
           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
           missValCount += (size_t) (outOfRange | isMissVal);
-          data[i] = outOfRange ? (float) missVal : isMissVal ? data[i] : (float) (data[i] + offset);
+          data[i] = outOfRange ? (float) missVal : isMissVal ? data[i] : (float) (data[i] + addoffset);
         }
       break;
-    case 11:  // haveRangeCheck & haveMissVal & haveScaleFactor
+    case 11:  // haveRangeCheck & haveMissVal & haveScalefactor
       for (size_t i = 0; i < valueCount; ++i)
         {
           int outOfRange = (data[i] < validMin || data[i] > validMax);
           int isMissVal = DBL_IS_EQUAL(data[i], missVal);
           missValCount += (size_t) (outOfRange | isMissVal);
-          data[i] = outOfRange ? (float) missVal : isMissVal ? data[i] : (float) (data[i] * scaleFactor);
+          data[i] = outOfRange ? (float) missVal : isMissVal ? data[i] : (float) (data[i] * scalefactor);
         }
       break;
     case 9:  // haveRangeCheck & haveMissVal
@@ -253,35 +251,35 @@ cdfDoInputDataTransformationSP(int vlistID, int varID, size_t valueCount, float
           data[i] = outOfRange ? (float) missVal : data[i];
         }
       break;
-    case 7:  // haveMissVal & haveScaleFactor & haveOffset
+    case 7:  // haveMissVal & haveScalefactor & haveAddoffset
       for (size_t i = 0; i < valueCount; ++i)
         if (DBL_IS_EQUAL(data[i], missVal))
           missValCount++;
         else
-          data[i] = (float) (data[i] * scaleFactor + offset);
+          data[i] = (float) (data[i] * scalefactor + addoffset);
       break;
-    case 6:  // haveOffset & haveScaleFactor
-      for (size_t i = 0; i < valueCount; ++i) data[i] = (float) (data[i] * scaleFactor + offset);
+    case 6:  // haveAddoffset & haveScalefactor
+      for (size_t i = 0; i < valueCount; ++i) data[i] = (float) (data[i] * scalefactor + addoffset);
       break;
-    case 5:  // haveMissVal & haveOffset
+    case 5:  // haveMissVal & haveAddoffset
       for (size_t i = 0; i < valueCount; ++i)
         if (DBL_IS_EQUAL(data[i], missVal))
           missValCount++;
         else
-          data[i] = (float) (data[i] + offset);
+          data[i] = (float) (data[i] + addoffset);
       break;
-    case 4:  // haveOffset
-      for (size_t i = 0; i < valueCount; ++i) data[i] = (float) (data[i] + offset);
+    case 4:  // haveAddoffset
+      for (size_t i = 0; i < valueCount; ++i) data[i] = (float) (data[i] + addoffset);
       break;
-    case 3:  // haveMissVal & haveScaleFactor
+    case 3:  // haveMissVal & haveScalefactor
       for (size_t i = 0; i < valueCount; ++i)
         if (DBL_IS_EQUAL(data[i], missVal))
           missValCount++;
         else
-          data[i] = (float) (data[i] * scaleFactor);
+          data[i] = (float) (data[i] * scalefactor);
       break;
-    case 2:  // haveScaleFactor
-      for (size_t i = 0; i < valueCount; ++i) data[i] = (float) (data[i] * scaleFactor);
+    case 2:  // haveScalefactor
+      for (size_t i = 0; i < valueCount; ++i) data[i] = (float) (data[i] * scalefactor);
       break;
     case 1:  // haveMissVal
       if (missValIsNaN)
diff --git a/src/cdf_util.c b/src/cdf_util.c
index 14cdf0641bd160de50ddeaee1f57596497d11412..7735fbf1b51614374aedd7a0cdf8a12241747b6e 100644
--- a/src/cdf_util.c
+++ b/src/cdf_util.c
@@ -30,7 +30,7 @@ strStartsWith(const char *vstr, const char *cstr)
 }
 
 int
-get_timeunit(size_t len, const char *ptu)
+get_time_units(size_t len, const char *ptu)
 {
   int timeunit = -1;
 
@@ -51,7 +51,7 @@ get_timeunit(size_t len, const char *ptu)
       else if (strStartsWith(ptu, "calendar_month")) timeunit = TUNIT_MONTH;
       else if (strStartsWith(ptu, "year"))           timeunit = TUNIT_YEAR;
     }
-  else if (len == 1 && ptu[0] == 's')  timeunit = TUNIT_SECOND;
+  else if     (len == 1 && ptu[0] == 's')            timeunit = TUNIT_SECOND;
   // clang-format on
 
   return timeunit;
@@ -87,17 +87,15 @@ is_timeaxis_units(const char *timeunits)
 
   for (size_t i = 0; i < len; i++) ptu[i] = (char) tolower((int) ptu[i]);
 
-  int timeunit = get_timeunit(len, ptu);
+  int timeunit = get_time_units(len, ptu);
   if (timeunit != -1)
     {
       while (!isspace(*ptu) && *ptu != 0) ptu++;
       if (*ptu)
         {
           while (isspace(*ptu)) ptu++;
-
           int timetype = strStartsWith(ptu, "as") ? TAXIS_ABSOLUTE : strStartsWith(ptu, "since") ? TAXIS_RELATIVE : -1;
-
-          status = timetype != -1;
+          status = (timetype != -1);
         }
     }
 
diff --git a/src/cdf_util.h b/src/cdf_util.h
index 974e7dd619aac3751dac377ea4fac72c83eb1a49..22f5061a409255bdc6d012f98c34391d2322ca32 100644
--- a/src/cdf_util.h
+++ b/src/cdf_util.h
@@ -3,7 +3,7 @@
 
 #include <stdbool.h>
 
-int get_timeunit(size_t len, const char *ptu);
+int get_time_units(size_t len, const char *ptu);
 
 bool is_time_units(const char *timeunits);
 bool is_timeaxis_units(const char *timeunits);
diff --git a/src/cdf_write.c b/src/cdf_write.c
index 570fa85d0bdd7984bb7c87271545a2511887fece..da8e0b6624ae8e4e8661ba469e2102d353598706 100644
--- a/src/cdf_write.c
+++ b/src/cdf_write.c
@@ -14,16 +14,16 @@
 #include "vlist_var.h"
 
 void
-cdfDefVarDeflate(int ncid, int ncvarID, int deflate_level)
+cdfDefVarDeflate(int ncid, int ncvarID, int deflateLevel)
 {
 #ifdef HAVE_NETCDF4
   // Set chunking, shuffle, and deflate.
-  const int shuffle = 1, deflate = 1;
+  const int shuffle = (CDI_Shuffle > 0), deflate = 1;
 
-  if (deflate_level < 1 || deflate_level > 9) deflate_level = 1;
+  if (deflateLevel < 1 || deflateLevel > 9) deflateLevel = 1;
 
   int status;
-  if ((status = nc_def_var_deflate(ncid, ncvarID, shuffle, deflate, deflate_level)))
+  if ((status = nc_def_var_deflate(ncid, ncvarID, shuffle, deflate, deflateLevel)))
     {
       Error("nc_def_var_deflate failed; %s", nc_strerror(status));
     }
@@ -267,7 +267,7 @@ cdfDefineCellMethods(stream_t *streamptr, int cdiID, int varID, int fileID, int
     {
       const char *attname = "cell_methods";
       char atttxt[CDI_MAX_NAME + 10];
-      sprintf(atttxt, "%s: %s", timeVarName, cellMethod);
+      snprintf(atttxt, sizeof(atttxt), "%s: %s", timeVarName, cellMethod);
       cdf_put_att_text(fileID, ncvarID, attname, strlen(atttxt), atttxt);
     }
 }
@@ -287,7 +287,7 @@ cdfDefineAttributes(int cdiID, int varID, int fileID, int ncvarID)
     {
       cdiInqAtt(cdiID, varID, iatt, attname, &atttype, &attlen);
 
-      //if (attlen == 0) continue;
+      // if (attlen == 0) continue;
 
       if (atttype == CDI_DATATYPE_TXT)
         {
@@ -426,7 +426,8 @@ cdfDefVarCompression(const stream_t *streamptr, int ncvarID, nc_type xtype)
 {
   if (streamptr->comptype == CDI_COMPRESS_ZIP)
     {
-      if (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C || streamptr->filetype == CDI_FILETYPE_NCZARR)
+      if (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C
+          || streamptr->filetype == CDI_FILETYPE_NCZARR)
         {
           cdfDefVarDeflate(streamptr->fileID, ncvarID, streamptr->complevel);
         }
@@ -442,7 +443,8 @@ cdfDefVarCompression(const stream_t *streamptr, int ncvarID, nc_type xtype)
     }
   else if (streamptr->comptype == CDI_COMPRESS_SZIP)
     {
-      if (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C || streamptr->filetype == CDI_FILETYPE_NCZARR)
+      if (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C
+          || streamptr->filetype == CDI_FILETYPE_NCZARR)
         {
           cdfDefVarSzip(streamptr->fileID, ncvarID, xtype2ppb(xtype));
         }
@@ -463,12 +465,11 @@ cdfDefVarPacking(const stream_t *streamptr, int ncvarID, nc_type xtype, int vlis
 {
   //  if ( xtype == NC_BYTE || xtype == NC_SHORT || xtype == NC_INT )
   {
-    const double addoffset = vlistInqVarAddoffset(vlistID, varID);
-    const double scalefactor = vlistInqVarScalefactor(vlistID, varID);
-    const bool laddoffset = IS_NOT_EQUAL(addoffset, 0);
-    const bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+    double addoffset = 0.0, scalefactor = 1.0;
+    const bool haveAddoffset = (cdiInqKeyFloat(vlistID, varID, CDI_KEY_ADDOFFSET, &addoffset) == CDI_NOERR);
+    const bool haveScalefactor = (cdiInqKeyFloat(vlistID, varID, CDI_KEY_SCALEFACTOR, &scalefactor) == CDI_NOERR);
 
-    if (laddoffset || lscalefactor)
+    if (haveAddoffset || haveScalefactor)
       {
         nc_type astype = (xtype == NC_FLOAT) ? NC_FLOAT : NC_DOUBLE;
         if ((astype == NC_DOUBLE) && IS_EQUAL(addoffset, (double) ((float) addoffset))
@@ -635,7 +636,7 @@ calc_chunksize(size_t chunkSizeLim, size_t size)
 
   size_t numChunks = (size / chunkSizeLim) + 1;
   size_t chunkSize = size / numChunks;
-  if (chunkSize%pageSize) chunkSize = (chunkSize / pageSize + 1) * pageSize;
+  if (chunkSize % pageSize) chunkSize = (chunkSize / pageSize + 1) * pageSize;
 
   return chunkSize;
 }
@@ -656,7 +657,7 @@ size_t
 calc_chunksize_x(int chunkType, int chunkSize, size_t xsize, bool yIsUndefined)
 {
   if (chunkType == CDI_CHUNK_AUTO && yIsUndefined)
-    return (chunkSize > 0) ? (size_t)chunkSize : ((xsize <= chunkSizeMax) ? xsize : chunkSizeMax);
+    return (chunkSize > 0) ? (size_t) chunkSize : ((xsize <= chunkSizeMax) ? xsize : chunkSizeMax);
   else
     return calc_chunksize(chunkSizeLim, xsize);
 }
@@ -724,8 +725,8 @@ cdfDefineDimsAndChunks(const stream_t *streamptr, int varID, int xid, int yid, i
     }
 
   if (CDI_Debug)
-    fprintf(stderr, "useChunks %d chunkType %d chunkSize %d  chunks %zu %zu %zu %zu\n",
-            useChunks, chunkType, chunkSize, chunks[0], chunks[1], chunks[2], chunks[3]);
+    fprintf(stderr, "useChunks %d chunkType %d chunkSize %d  chunks %zu %zu %zu %zu\n", useChunks, chunkType, chunkSize, chunks[0],
+            chunks[1], chunks[2], chunks[3]);
 
   *piax = iax;
   return ndims;
@@ -775,7 +776,7 @@ cdfCheckVarname(int fileID, char name[CDI_MAX_NAME])
     {
       int ncvarID;
       char varname[CDI_MAX_NAME];
-      sprintf(varname, "%s", name);
+      snprintf(varname, sizeof(varname), "%s", name);
       char *varname2 = varname + strlen(varname);
       unsigned iz = 0;
 
@@ -808,9 +809,9 @@ cdfGenVarname(int fileID, char name[CDI_MAX_NAME], int pnum, int pcat, int *pdis
   if (pnum < 0) pnum = -pnum;
 
   if (*pdis == 255)
-    sprintf(varname, "var%d", code);
+    snprintf(varname, sizeof(varname), "var%d", code);
   else
-    sprintf(varname, "param%d.%d.%d", pnum, pcat, *pdis);
+    snprintf(varname, sizeof(varname), "param%d.%d.%d", pnum, pcat, *pdis);
 
   char *varname2 = varname + strlen(varname);
   int ncvarID;
@@ -861,9 +862,10 @@ cdfDefVar(stream_t *streamptr, int varID)
   const int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
   const int zid = streamptr->zaxisID[zaxisindex];
 
-  int dimorder[3];  // ZYX and ZXY
+  int dimorder[3];  // ZYX/321 and ZXY/312
   vlistInqVarDimorder(vlistID, varID, &dimorder);
-  const bool useChunks = (dimorder[0] == 3) ? (gridsize >= 32) : false;
+  const bool useGridsize = (dimorder[0] == 3) || (dimorder[1] == 3 && dimorder[2] == 1 && gridsize == gridInqXsize(gridID));
+  const bool useChunks = useGridsize ? (gridsize >= 32) : false;
 
   if (((dimorder[0] > 0) + (dimorder[1] > 0) + (dimorder[2] > 0))
       < ((xid != CDI_UNDEFID) + (yid != CDI_UNDEFID) + (zid != CDI_UNDEFID)))
@@ -911,11 +913,13 @@ cdfDefVar(stream_t *streamptr, int varID)
     {
       const int nsb = vlistInqVarNSB(vlistID, varID);
       if (nsb > 0) nc_def_var_quantize(fileID, ncvarID, NC_QUANTIZE_BITROUND, nsb);
-      //if (nsb > 0) nc_def_var_quantize(fileID, ncvarID, NC_QUANTIZE_GRANULARBR, nsb);
+      // if (nsb > 0) nc_def_var_quantize(fileID, ncvarID, NC_QUANTIZE_GRANULARBR, nsb);
     }
 #endif
 
-  if (useChunks && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C || streamptr->filetype == CDI_FILETYPE_NCZARR))
+  if (useChunks
+      && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C
+          || streamptr->filetype == CDI_FILETYPE_NCZARR))
     cdf_def_var_chunking(fileID, ncvarID, NC_CHUNKED, chunks);
 #endif
 
@@ -1028,12 +1032,11 @@ cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarID, int dtype, s
   /*  if ( dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 ) */
   {
     const double missval = vlistInqVarMissval(vlistID, varID);
-    const double addoffset = vlistInqVarAddoffset(vlistID, varID);
-    const double scalefactor = vlistInqVarScalefactor(vlistID, varID);
-    const bool laddoffset = IS_NOT_EQUAL(addoffset, 0);
-    const bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+    double addoffset = 0.0, scalefactor = 1.0;
+    const bool haveAddoffset = (cdiInqKeyFloat(vlistID, varID, CDI_KEY_ADDOFFSET, &addoffset) == CDI_NOERR);
+    const bool haveScalefactor = (cdiInqKeyFloat(vlistID, varID, CDI_KEY_SCALEFACTOR, &scalefactor) == CDI_NOERR);
 
-    if (laddoffset || lscalefactor)
+    if (haveAddoffset || haveScalefactor)
       {
         if (memtype == MEMTYPE_FLOAT)
           {
@@ -1048,8 +1051,8 @@ cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarID, int dtype, s
                     double temp = mdata_sp[i];
                     if (!DBL_IS_EQUAL(temp, missval))
                       {
-                        if (laddoffset) temp -= addoffset;
-                        if (lscalefactor) temp /= scalefactor;
+                        if (haveAddoffset) temp -= addoffset;
+                        if (haveScalefactor) temp /= scalefactor;
                         mdata_sp[i] = (float) temp;
                       }
                   }
@@ -1059,8 +1062,8 @@ cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarID, int dtype, s
                 for (size_t i = 0; i < nvals; ++i)
                   {
                     double temp = mdata_sp[i];
-                    if (laddoffset) temp -= addoffset;
-                    if (lscalefactor) temp /= scalefactor;
+                    if (haveAddoffset) temp -= addoffset;
+                    if (haveScalefactor) temp /= scalefactor;
                     mdata_sp[i] = (float) temp;
                   }
               }
@@ -1077,8 +1080,8 @@ cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarID, int dtype, s
                   {
                     if (!DBL_IS_EQUAL(mdata_dp[i], missval))
                       {
-                        if (laddoffset) mdata_dp[i] -= addoffset;
-                        if (lscalefactor) mdata_dp[i] /= scalefactor;
+                        if (haveAddoffset) mdata_dp[i] -= addoffset;
+                        if (haveScalefactor) mdata_dp[i] /= scalefactor;
                       }
                   }
               }
@@ -1086,8 +1089,8 @@ cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarID, int dtype, s
               {
                 for (size_t i = 0; i < nvals; ++i)
                   {
-                    if (laddoffset) mdata_dp[i] -= addoffset;
-                    if (lscalefactor) mdata_dp[i] /= scalefactor;
+                    if (haveAddoffset) mdata_dp[i] -= addoffset;
+                    if (haveScalefactor) mdata_dp[i] /= scalefactor;
                   }
               }
           }
diff --git a/src/cdi.h b/src/cdi.h
index 1df50877eebd4bbfb3bf7c10fa9c362548d537f5..af02e06465593062fa099b274afc9e865c2bf779 100644
--- a/src/cdi.h
+++ b/src/cdi.h
@@ -185,6 +185,7 @@ extern "C" {
 #define  CDI_PROJ_LAEA             23  // Lambert Azimuthal Equal Area
 #define  CDI_PROJ_SINU             24  // Sinusoidal
 #define  CDI_PROJ_STERE            25  // Polar stereographic
+#define  CDI_PROJ_HEALPIX          26  // Healpix
 
 // ZAXIS types
 
@@ -672,17 +673,6 @@ void    vlistDefVarMissval(int vlistID, int varID, double missval);
 //      vlistInqVarMissval: Get the missing value of a Variable
 double  vlistInqVarMissval(int vlistID, int varID);
 
-//      vlistDefVarExtra: Define extra information of a Variable
-void    vlistDefVarExtra(int vlistID, int varID, const char *extra);
-
-//      vlistInqVarExtra: Get extra information of a Variable
-void    vlistInqVarExtra(int vlistID, int varID, char *extra);
-
-void    vlistDefVarScalefactor(int vlistID, int varID, double scalefactor);
-double  vlistInqVarScalefactor(int vlistID, int varID);
-void    vlistDefVarAddoffset(int vlistID, int varID, double addoffset);
-double  vlistInqVarAddoffset(int vlistID, int varID);
-
 SizeType vlistInqVarSize(int vlistID, int varID);
 
 void    vlistDefIndex(int vlistID, int varID, int levID, int index);
@@ -830,6 +820,7 @@ SizeType gridInqYCvals(int gridID, char *ycvals[]);
 #define  CDI_KEY_UNITS                         945  // Units of the variable
 #define  CDI_KEY_DATATYPE                      946  // Data type
 #define  CDI_KEY_REFERENCEURI                  947  // Reference URI to grid file
+#define  CDI_KEY_CHUNKS                        948  // Chunks
 
 // Integer keys
 #define  CDI_KEY_NUMBEROFGRIDUSED              961  // GRIB2 numberOfGridUsed
@@ -841,6 +832,8 @@ SizeType gridInqYCvals(int gridID, char *ycvals[]);
 
 // Floating point keys
 #define  CDI_KEY_MISSVAL                       701  // Missing value
+#define  CDI_KEY_ADDOFFSET                     702  // Add offset
+#define  CDI_KEY_SCALEFACTOR                   703  // Scale factor
 
 // Byte array keys
 #define  CDI_KEY_UUID                          960  // UUID for grid/Z-axis reference [size: CDI_UUID_SIZE]
diff --git a/src/cdi.inc b/src/cdi.inc
index 646cb1bc4343ce2f82b848cc7302d8d1c99e607a..6bcfce6dd1231657076950cbfb1ebc7e84ef6ae6 100644
--- a/src/cdi.inc
+++ b/src/cdi.inc
@@ -1,10 +1,10 @@
 ! This file was automatically generated, don't edit!
 !
-! Fortran interface for CDI library version 2.0.0
+! Fortran interface for CDI library version 2.1.0
 !
 ! Author:
 ! -------
-! Uwe Schulzweida, MPI-MET, Hamburg,   August 2022
+! Uwe Schulzweida, MPI-MET, Hamburg,   October 2022
 !
 
 !
@@ -293,6 +293,8 @@
       PARAMETER (CDI_PROJ_SINU          = 24)
       INTEGER    CDI_PROJ_STERE
       PARAMETER (CDI_PROJ_STERE         = 25)
+      INTEGER    CDI_PROJ_HEALPIX
+      PARAMETER (CDI_PROJ_HEALPIX       = 26)
 !
 !  ZAXIS types
 !
@@ -1254,40 +1256,6 @@
 !                                     INTEGER         varID)
       EXTERNAL        vlistInqVarMissval
 
-!                     vlistDefVarExtra
-!                                    (INTEGER         vlistID,
-!                                     INTEGER         varID,
-!                                     CHARACTER*(*)   extra)
-      EXTERNAL        vlistDefVarExtra
-
-!                     vlistInqVarExtra
-!                                    (INTEGER         vlistID,
-!                                     INTEGER         varID,
-!                                     CHARACTER*(*)   extra)
-      EXTERNAL        vlistInqVarExtra
-
-!                     vlistDefVarScalefactor
-!                                    (INTEGER         vlistID,
-!                                     INTEGER         varID,
-!                                     DOUBLEPRECISION scalefactor)
-      EXTERNAL        vlistDefVarScalefactor
-
-      DOUBLEPRECISION vlistInqVarScalefactor
-!                                    (INTEGER         vlistID,
-!                                     INTEGER         varID)
-      EXTERNAL        vlistInqVarScalefactor
-
-!                     vlistDefVarAddoffset
-!                                    (INTEGER         vlistID,
-!                                     INTEGER         varID,
-!                                     DOUBLEPRECISION addoffset)
-      EXTERNAL        vlistDefVarAddoffset
-
-      DOUBLEPRECISION vlistInqVarAddoffset
-!                                    (INTEGER         vlistID,
-!                                     INTEGER         varID)
-      EXTERNAL        vlistInqVarAddoffset
-
       INTEGER         vlistInqVarSize
 !                                    (INTEGER         vlistID,
 !                                     INTEGER         varID)
@@ -1630,6 +1598,8 @@
       PARAMETER (CDI_KEY_DATATYPE       = 946)
       INTEGER    CDI_KEY_REFERENCEURI
       PARAMETER (CDI_KEY_REFERENCEURI   = 947)
+      INTEGER    CDI_KEY_CHUNKS
+      PARAMETER (CDI_KEY_CHUNKS         = 948)
 !
 !  Integer keys
 !
@@ -1650,6 +1620,10 @@
 !
       INTEGER    CDI_KEY_MISSVAL
       PARAMETER (CDI_KEY_MISSVAL        = 701)
+      INTEGER    CDI_KEY_ADDOFFSET
+      PARAMETER (CDI_KEY_ADDOFFSET      = 702)
+      INTEGER    CDI_KEY_SCALEFACTOR
+      PARAMETER (CDI_KEY_SCALEFACTOR    = 703)
 !
 !  Byte array keys
 !
diff --git a/src/cdiFortran.c b/src/cdiFortran.c
index 0fef6d6777d51e9f71f771cc996e97224d36d7a1..cac999910f6ce46e5d07018547b9c7a55322cde7 100644
--- a/src/cdiFortran.c
+++ b/src/cdiFortran.c
@@ -395,12 +395,6 @@ FCALLSCSUB3 (vlistDefVarUnits, VLISTDEFVARUNITS, vlistdefvarunits, INT, INT, STR
 FCALLSCSUB3 (vlistInqVarUnits, VLISTINQVARUNITS, vlistinqvarunits, INT, INT, PSTRING)
 FCALLSCSUB3 (vlistDefVarMissval, VLISTDEFVARMISSVAL, vlistdefvarmissval, INT, INT, DOUBLE)
 FCALLSCFUN2 (DOUBLE, vlistInqVarMissval, VLISTINQVARMISSVAL, vlistinqvarmissval, INT, INT)
-FCALLSCSUB3 (vlistDefVarExtra, VLISTDEFVAREXTRA, vlistdefvarextra, INT, INT, STRING)
-FCALLSCSUB3 (vlistInqVarExtra, VLISTINQVAREXTRA, vlistinqvarextra, INT, INT, PSTRING)
-FCALLSCSUB3 (vlistDefVarScalefactor, VLISTDEFVARSCALEFACTOR, vlistdefvarscalefactor, INT, INT, DOUBLE)
-FCALLSCFUN2 (DOUBLE, vlistInqVarScalefactor, VLISTINQVARSCALEFACTOR, vlistinqvarscalefactor, INT, INT)
-FCALLSCSUB3 (vlistDefVarAddoffset, VLISTDEFVARADDOFFSET, vlistdefvaraddoffset, INT, INT, DOUBLE)
-FCALLSCFUN2 (DOUBLE, vlistInqVarAddoffset, VLISTINQVARADDOFFSET, vlistinqvaraddoffset, INT, INT)
 static int vlistInqVarSize_fwrap(int vlistID, int varID)
 {
   SizeType v;
diff --git a/src/cdi_datetime.c b/src/cdi_datetime.c
index 6711b1a896e12b04dc4113fc8300a144d6f108f5..187c1a95ec5d29dc2fda47a22e58e4eb589d1c44 100644
--- a/src/cdi_datetime.c
+++ b/src/cdi_datetime.c
@@ -53,8 +53,8 @@ cdiDate_set(int64_t date)
 
   CdiDate cdiDate;
   cdiDate.year = year;
-  cdiDate.month = (short)month;
-  cdiDate.day = (short)day;
+  cdiDate.month = (short) month;
+  cdiDate.day = (short) day;
 
   return cdiDate;
 }
@@ -66,9 +66,9 @@ cdiTime_set(int time)
   cdiDecodeTime(time, &hour, &minute, &second);
 
   CdiTime cdiTime;
-  cdiTime.hour = (short)hour;
-  cdiTime.minute = (short)minute;
-  cdiTime.second = (short)second;
+  cdiTime.hour = (short) hour;
+  cdiTime.minute = (short) minute;
+  cdiTime.second = (short) second;
   cdiTime.ms = ms;
 
   return cdiTime;
diff --git a/src/cdi_int.c b/src/cdi_int.c
index 1f98b381449ae52ce2317274c5ea56a6318f07bf..c7623b504aae1cbe59316d5c83933b067f25cc34 100644
--- a/src/cdi_int.c
+++ b/src/cdi_int.c
@@ -38,7 +38,10 @@ int CDI_Convert_Cubesphere = 1;
 int CDI_Read_Cell_Corners = 1;
 int CDI_CMOR_Mode = 0;
 int CDI_Reduce_Dim = 0;
+int CDI_Shuffle = 0;
 size_t CDI_Netcdf_Hdr_Pad = 0UL;
+size_t CDI_Chunk_Cache = 0UL;
+size_t CDI_Chunk_Cache_Max = 0UL;
 bool CDI_Netcdf_Lazy_Grid_Load = false;
 
 char *cdiPartabPath = NULL;
@@ -77,7 +80,7 @@ int cdiSortParam = 0;
 int cdiHaveMissval = 0;
 
 static long
-cdiGetenvInt(const char *envName)
+cdi_getenv_int(const char *envName)
 {
   long envValue = -1;
 
@@ -328,48 +331,57 @@ cdiInitialize(void)
       grib_multi_support_off(NULL);
 #endif
 
-      value = cdiGetenvInt("CDI_DEBUG");
+      value = cdi_getenv_int("CDI_DEBUG");
       if (value >= 0) CDI_Debug = (int) value;
 
-      value = cdiGetenvInt("CDI_GRIBAPI_DEBUG");
+      value = cdi_getenv_int("CDI_GRIBAPI_DEBUG");
       if (value >= 0) CDI_gribapi_debug = (bool) value;
 
-      value = cdiGetenvInt("CDI_ECCODES_DEBUG");
+      value = cdi_getenv_int("CDI_ECCODES_DEBUG");
       if (value >= 0) CDI_gribapi_debug = (bool) value;
 
-      value = cdiGetenvInt("CDI_ECCODES_GRIB1");
+      value = cdi_getenv_int("CDI_ECCODES_GRIB1");
       if (value >= 0) cdiSetEccodesGrib1((bool) value);
 
-      value = cdiGetenvInt("CDI_READ_CELL_CORNERS");
+      value = cdi_getenv_int("CDI_READ_CELL_CORNERS");
       if (value >= 0) CDI_Read_Cell_Corners = (int) value;
 
-      value = cdiGetenvInt("CDI_RECOPT");
+      value = cdi_getenv_int("CDI_RECOPT");
       if (value >= 0) CDI_Recopt = (int) value;
 
-      value = cdiGetenvInt("CDI_REGULARGRID");
+      value = cdi_getenv_int("CDI_REGULARGRID");
       if (value >= 0) cdiDataUnreduced = (int) value;
 
-      value = cdiGetenvInt("CDI_SORTNAME");
+      value = cdi_getenv_int("CDI_SORTNAME");
       if (value >= 0) cdiSortName = (int) value;
 
-      value = cdiGetenvInt("CDI_SORTPARAM");
+      value = cdi_getenv_int("CDI_SORTPARAM");
       if (value >= 0) cdiSortParam = (int) value;
 
-      value = cdiGetenvInt("CDI_HAVE_MISSVAL");
+      value = cdi_getenv_int("CDI_HAVE_MISSVAL");
       if (value >= 0) cdiHaveMissval = (int) value;
 
-      value = cdiGetenvInt("CDI_LEVELTYPE");
+      value = cdi_getenv_int("CDI_LEVELTYPE");
       if (value >= 0) cdiDefaultLeveltype = (int) value;
 
-      value = cdiGetenvInt("CDI_NETCDF_HDR_PAD");
+      value = cdi_getenv_int("CDI_NETCDF_HDR_PAD");
       if (value >= 0) CDI_Netcdf_Hdr_Pad = (size_t) value;
 
+      value = cdi_getenv_int("CDI_CHUNK_CACHE");
+      if (value >= 0) CDI_Chunk_Cache = (size_t) value;
+
+      value = cdi_getenv_int("CDI_CHUNK_CACHE_MAX");
+      if (value >= 0) CDI_Chunk_Cache_Max = (size_t) value;
+
       envstr = getenv("CDI_GRIB1_TEMPLATE");
       if (envstr) CDI_GRIB1_Template = envstr;
 
       envstr = getenv("CDI_GRIB2_TEMPLATE");
       if (envstr) CDI_GRIB2_Template = envstr;
 
+      envstr = getenv("CDI_SHUFFLE");
+      if (envstr) CDI_Shuffle = atoi(envstr);
+
       envstr = getenv("CDI_MISSVAL");
       if (envstr) CDI_Default_Missval = atof(envstr);
       /*
diff --git a/src/cdi_int.h b/src/cdi_int.h
index bcd39cd1834ecbc9cda6699b7c7ec6f569f9302a..f1985b8521efc8a3431b1b2d5b16395b33a4b2fe 100644
--- a/src/cdi_int.h
+++ b/src/cdi_int.h
@@ -162,8 +162,8 @@ typedef struct
   int gridID;
   int varID;
   int levelID;
-  int prec;           // ext, srv
-  void *objectp;      // pointer to ieg, ext, srv or cgribex objects
+  int prec;       // ext, srv
+  void *objectp;  // pointer to ieg, ext, srv or cgribex objects
 } Record;
 
 // data structure specifying tile-related meta-data. structure contains "-1" if this is no tile-variable.
@@ -240,7 +240,7 @@ typedef struct
   sleveltable_t *recordTable;  // record IDs for each subtype
   int ncvarid;
   int subtypeSize;
-  bool defmiss;   // true: if missval is defined in file
+  bool defmiss;  // true: if missval is defined in file
   bool isUsed;
 
   int gridID;
@@ -260,7 +260,7 @@ typedef struct
 #ifdef HAVE_LIBNETCDF
 enum cdfIDIdx
 {
-  CDF_DIMID_E,   // 3rd dimID of cube sphere grid (len=6)
+  CDF_DIMID_E,  // 3rd dimID of cube sphere grid (len=6)
   CDF_DIMID_X,
   CDF_DIMID_Y,
   CDF_DIMID_RP,  // reducedPoints
@@ -281,23 +281,23 @@ typedef struct
 typedef struct
 {
   int self;
-  int accesstype;    // TYPE_REC or TYPE_VAR
+  int accesstype;  // TYPE_REC or TYPE_VAR
   int accessmode;
   int filetype;
   int byteorder;
   int fileID;
   int filemode;
-  int nrecs;         // number of records
+  int nrecs;  // number of records
   SizeType numvals;
   char *filename;
   Record *record;
   svarinfo_t *vars;
-  int nvars;         // number of variables
+  int nvars;  // number of variables
   int varsAllocated;
-  int curTsID;       // current timestep ID
-  int rtsteps;       // number of tsteps accessed
-  long ntsteps;      // number of tsteps : only set if all records accessed
-  int maxSteps;      // max. number of timesteps (needed for CDI_FILETYPE_NCZARR)
+  int curTsID;   // current timestep ID
+  int rtsteps;   // number of tsteps accessed
+  long ntsteps;  // number of tsteps : only set if all records accessed
+  int maxSteps;  // max. number of timesteps (needed for CDI_FILETYPE_NCZARR)
   tsteps_t *tsteps;
   int tstepsTableSize;
   int tstepsNextID;
@@ -404,7 +404,10 @@ extern int CDI_Convert_Cubesphere;
 extern int CDI_Read_Cell_Corners;
 extern int CDI_CMOR_Mode;
 extern int CDI_Reduce_Dim;
+extern int CDI_Shuffle;
 extern size_t CDI_Netcdf_Hdr_Pad;
+extern size_t CDI_Chunk_Cache;
+extern size_t CDI_Chunk_Cache_Max;
 extern bool CDI_Netcdf_Lazy_Grid_Load;
 extern int STREAM_Debug;
 
diff --git a/src/cdi_key.c b/src/cdi_key.c
index c5ce9a0fa7b50526c5a0947aefd36d6870db77df..be1dde0142cc651826a696e313e8a1a8ba1bd44a 100644
--- a/src/cdi_key.c
+++ b/src/cdi_key.c
@@ -8,10 +8,8 @@
 static cdi_keys_t *
 vlist_get_keysp(vlist_t *vlistptr, int varID)
 {
-  if (varID == CDI_GLOBAL)
-    return &vlistptr->keys;
-  else if (varID >= 0 && varID < vlistptr->nvars)
-    return &(vlistptr->vars[varID].keys);
+  if (varID == CDI_GLOBAL) return &vlistptr->keys;
+  if (varID >= 0 && varID < vlistptr->nvars) return &(vlistptr->vars[varID].keys);
 
   return NULL;
 }
@@ -19,12 +17,9 @@ vlist_get_keysp(vlist_t *vlistptr, int varID)
 static cdi_keys_t *
 grid_get_keysp(grid_t *gridptr, int varID)
 {
-  if (varID == CDI_GLOBAL)
-    return &gridptr->keys;
-  else if (varID == CDI_XAXIS)
-    return &gridptr->x.keys;
-  else if (varID == CDI_YAXIS)
-    return &gridptr->y.keys;
+  if (varID == CDI_GLOBAL) return &gridptr->keys;
+  if (varID == CDI_XAXIS) return &gridptr->x.keys;
+  if (varID == CDI_YAXIS) return &gridptr->y.keys;
 
   return NULL;
 }
@@ -32,9 +27,7 @@ grid_get_keysp(grid_t *gridptr, int varID)
 static cdi_keys_t *
 zaxis_get_keysp(zaxis_t *zaxisptr, int varID)
 {
-  if (varID == CDI_GLOBAL) return &zaxisptr->keys;
-
-  return NULL;
+  return (varID == CDI_GLOBAL) ? &zaxisptr->keys : NULL;
 }
 
 static cdi_key_t *
@@ -48,8 +41,8 @@ new_key(cdi_keys_t *keysp, int key)
   keysp->nelems++;
 
   keyp->key = key;
-  keyp->length = 0;
   keyp->type = 0;
+  keyp->length = 0;
   keyp->v.s = NULL;
 
   return keyp;
@@ -90,12 +83,9 @@ find_key_const(const cdi_keys_t *keysp, int key)
 static cdi_keys_t *
 cdi_get_keysp(int objID, int varID)
 {
-  if (reshGetTxCode(objID) == GRID)
-    return grid_get_keysp(grid_to_pointer(objID), varID);
-  else if (reshGetTxCode(objID) == ZAXIS)
-    return zaxis_get_keysp(zaxis_to_pointer(objID), varID);
-  else if (reshGetTxCode(objID) == VLIST)
-    return vlist_get_keysp(vlist_to_pointer(objID), varID);
+  if (reshGetTxCode(objID) == GRID) return grid_get_keysp(grid_to_pointer(objID), varID);
+  if (reshGetTxCode(objID) == ZAXIS) return zaxis_get_keysp(zaxis_to_pointer(objID), varID);
+  if (reshGetTxCode(objID) == VLIST) return vlist_get_keysp(vlist_to_pointer(objID), varID);
 
   return NULL;
 }
@@ -107,39 +97,45 @@ cdi_key_compare(cdi_keys_t *keyspa, cdi_keys_t *keyspb, int keynum)
   cdi_key_t *keypa = keyspa->value + keynum, *keypb = keyspb->value + keynum;
 
   if (keypa->key != keypb->key) return 1;
-
   if (keypa->type != keypb->type) return 1;
+  if (keypa->length != keypb->length) return 1;
 
-  if (keypa->type == KEY_BYTES)
-    {
-      if (keypa->length != keypb->length) return 1;
-      return memcmp(keypa->v.s, keypb->v.s, keypa->length);
-    }
-  else if (keypa->type == KEY_FLOAT)
-    {
-      if (IS_NOT_EQUAL(keypa->v.d, keypb->v.d)) return 1;
-    }
-  else if (keypa->type == KEY_INT)
-    {
-      if (keypa->v.i != keypb->v.i) return 1;
-    }
+  if (keypa->type == KEY_BYTES) return (memcmp(keypa->v.s, keypb->v.s, keypa->length) != 0);
+  if (keypa->type == KEY_FLOAT) return (IS_NOT_EQUAL(keypa->v.d, keypb->v.d));
+  if (keypa->type == KEY_INT) return (keypa->v.i != keypb->v.i);
 
   return 0;
 }
 
+static void
+cdi_delete_key(cdi_key_t *keyp)
+{
+  if (keyp != NULL && keyp->length)  // key in use
+    {
+      keyp->length = 0;
+      if (keyp->type == KEY_BYTES)
+        {
+          if (keyp->v.s) free(keyp->v.s);
+          keyp->v.s = NULL;
+        }
+      else if (keyp->type == KEY_FLOAT)
+        {
+          keyp->v.d = 0.0;
+        }
+      else if (keyp->type == KEY_INT)
+        {
+          keyp->v.i = 0;
+        }
+    }
+}
+
 void
 cdiDeleteVarKeys(cdi_keys_t *keysp)
 {
   const int nelems = keysp ? (int) keysp->nelems : 0;
   for (int keyid = 0; keyid < nelems; keyid++)
     {
-      cdi_key_t *keyp = &(keysp->value[keyid]);
-      if (keyp->length)
-        {
-          free(keyp->v.s);
-          keyp->v.s = NULL;
-          keyp->length = 0;
-        }
+      cdi_delete_key(&(keysp->value[keyid]));
     }
 
   keysp->nelems = 0;
@@ -161,17 +157,18 @@ cdiPrintVarKeys(cdi_keys_t *keysp)
   for (int keyid = 0; keyid < nelems; keyid++)
     {
       cdi_key_t *keyp = &(keysp->value[keyid]);
+      if (keyp->length == 0) continue;
       if (keyp->type == KEY_BYTES)
         {
-          printf("%d key %d length %d value %s\n", keyid + 1, keyp->key, keyp->length, keyp->v.s);
+          fprintf(stdout, "%d key %d length %d value %s\n", keyid + 1, keyp->key, keyp->length, keyp->v.s);
         }
       else if (keyp->type == KEY_FLOAT)
         {
-          printf("%d key %d value %g\n", keyid + 1, keyp->key, keyp->v.d);
+          fprintf(stdout, "%d key %d value %g\n", keyid + 1, keyp->key, keyp->v.d);
         }
       else if (keyp->type == KEY_INT)
         {
-          printf("%d key %d value %d\n", keyid + 1, keyp->key, keyp->v.i);
+          fprintf(stdout, "%d key %d value %d\n", keyid + 1, keyp->key, keyp->v.i);
         }
     }
 }
@@ -195,10 +192,9 @@ cdiInqKeyLen(int cdiID, int varID, int key, int *length)
   xassert(keysp != NULL);
 
   const cdi_key_t *keyp = find_key_const(keysp, key);
-  if (keyp != NULL)
+  if (keyp != NULL && keyp->length > 0)
     {
       *length = keyp->length;
-      if (*length == 0) *length = 1;
       status = CDI_NOERR;
     }
 
@@ -208,32 +204,22 @@ cdiInqKeyLen(int cdiID, int varID, int key, int *length)
 static void
 cdi_define_key(const cdi_key_t *keyp, cdi_keys_t *keysp)
 {
-  if (keyp->type == KEY_INT)
-    cdiDefVarKeyInt(keysp, keyp->key, keyp->v.i);
-  else if (keyp->type == KEY_FLOAT)
-    cdiDefVarKeyFloat(keysp, keyp->key, keyp->v.d);
-  else if (keyp->type == KEY_BYTES)
-    cdiDefVarKeyBytes(keysp, keyp->key, keyp->v.s, keyp->length);
+  // clang-format off
+  if      (keyp->type == KEY_INT)   cdiDefVarKeyInt(keysp, keyp->key, keyp->v.i);
+  else if (keyp->type == KEY_FLOAT) cdiDefVarKeyFloat(keysp, keyp->key, keyp->v.d);
+  else if (keyp->type == KEY_BYTES) cdiDefVarKeyBytes(keysp, keyp->key, keyp->v.s, keyp->length);
+  // clang-format on
 }
 
 int
 cdiDeleteKey(int cdiID, int varID, int key)
 {
-  int status = CDI_NOERR;
+  const int status = CDI_NOERR;
 
   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
   xassert(keysp != NULL);
 
-  cdi_key_t *keyp = find_key(keysp, key);
-  if (keyp != NULL)  // key in use
-    {
-      if (keyp->length)
-        {
-          free(keyp->v.s);
-          keyp->v.s = NULL;
-          keyp->length = 0;
-        }
-    }
+  cdi_delete_key(find_key(keysp, key));
 
   return status;
 }
@@ -244,14 +230,14 @@ cdiCopyVarKeys(const cdi_keys_t *keysp1, cdi_keys_t *keysp2)
   for (size_t keyid = 0; keyid < keysp1->nelems; keyid++)
     {
       const cdi_key_t *keyp = &(keysp1->value[keyid]);
-      cdi_define_key(keyp, keysp2);
+      if (keyp->length > 0) cdi_define_key(keyp, keysp2);
     }
 }
 
 int
 cdiCopyKeys(int cdiID1, int varID1, int cdiID2, int varID2)
 {
-  int status = CDI_NOERR;
+  const int status = CDI_NOERR;
 
   cdi_keys_t *keysp1 = cdi_get_keysp(cdiID1, varID1);
   xassert(keysp1 != NULL);
@@ -267,12 +253,12 @@ cdiCopyKeys(int cdiID1, int varID1, int cdiID2, int varID2)
 int
 cdiCopyVarKey(const cdi_keys_t *keysp1, int key, cdi_keys_t *keysp2)
 {
-  int status = CDI_NOERR;
+  const int status = CDI_NOERR;
 
   const cdi_key_t *keyp = find_key_const(keysp1, key);
   if (keyp == NULL) return -1;
 
-  cdi_define_key(keyp, keysp2);
+  if (keyp->length > 0) cdi_define_key(keyp, keysp2);
 
   return status;
 }
@@ -301,6 +287,7 @@ cdiDefVarKeyInt(cdi_keys_t *keysp, int key, int value)
       {
         keyp->type = KEY_INT;
         keyp->v.i = value;
+        keyp->length = 1;
       }
     }
 }
@@ -327,7 +314,7 @@ The function @func{cdiDefKeyInt} defines an integer value from a key.
 int
 cdiDefKeyInt(int cdiID, int varID, int key, int value)
 {
-  int status = CDI_NOERR;
+  const int status = CDI_NOERR;
 
   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
   xassert(keysp != NULL);
@@ -367,7 +354,7 @@ cdiInqKeyInt(int cdiID, int varID, int key, int *value)
   xassert(keysp != NULL);
 
   const cdi_key_t *keyp = find_key_const(keysp, key);
-  if (keyp != NULL)  // key in use
+  if (keyp != NULL && keyp->length == 1)  // key in use
     {
       if (keyp->type == KEY_INT)
         {
@@ -398,11 +385,9 @@ cdiDefVarKeyFloat(cdi_keys_t *keysp, int key, double value)
 
   if (keyp != NULL)
     {
-      // if ( keyp->v.i != value )
-      {
-        keyp->type = KEY_INT;
-        keyp->v.d = value;
-      }
+      keyp->type = KEY_FLOAT;
+      keyp->v.d = value;
+      keyp->length = 1;
     }
 }
 
@@ -428,7 +413,7 @@ The function @func{cdiDefKeyFloat} defines a CDI floating point value from a key
 int
 cdiDefKeyFloat(int cdiID, int varID, int key, double value)
 {
-  int status = CDI_NOERR;
+  const int status = CDI_NOERR;
 
   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
   xassert(keysp != NULL);
@@ -462,13 +447,13 @@ cdiInqKeyFloat(int cdiID, int varID, int key, double *value)
 {
   int status = -1;
 
-  // if ( varID != CDI_GLOBAL ) status = cdiInqKeyFloat(cdiID, CDI_GLOBAL, key, value);
+  // if (varID != CDI_GLOBAL) status = cdiInqKeyFloat(cdiID, CDI_GLOBAL, key, value);
 
   const cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
   xassert(keysp != NULL);
 
   const cdi_key_t *keyp = find_key_const(keysp, key);
-  if (keyp != NULL)  // key in use
+  if (keyp != NULL && keyp->length == 1)  // key in use
     {
       if (keyp->type == KEY_FLOAT)
         {
@@ -490,7 +475,7 @@ cdiDefVarKeyBytes(cdi_keys_t *keysp, int key, const unsigned char *bytes, int le
     {
       if (keyp->length != 0 && keyp->length != length)
         {
-          free(keyp->v.s);
+          if (keyp->v.s) free(keyp->v.s);
           keyp->length = 0;
         }
       if (keyp->length == 0)
@@ -527,7 +512,7 @@ The function @func{cdiDefKeyBytes} defines a byte array from a key.
 int
 cdiDefKeyBytes(int cdiID, int varID, int key, const unsigned char *bytes, int length)
 {
-  int status = CDI_NOERR;
+  const int status = CDI_NOERR;
 
   cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
   xassert(keysp != NULL);
@@ -543,7 +528,7 @@ cdiInqVarKeyBytes(const cdi_keys_t *keysp, int key, unsigned char *bytes, int *l
   int status = -1;
 
   const cdi_key_t *keyp = find_key_const(keysp, key);
-  if (keyp != NULL)  // key in use
+  if (keyp != NULL && keyp->length > 0)  // key in use
     {
       if (keyp->type == KEY_BYTES)
         {
@@ -583,7 +568,7 @@ cdiInqKeyBytes(int cdiID, int varID, int key, unsigned char *bytes, int *length)
   xassert(bytes != NULL);
   xassert(length != NULL);
 
-  // if ( varID != CDI_GLOBAL ) status = cdiInqKeyBytes(cdiID, CDI_GLOBAL, key, bytes, length);
+  // if (varID != CDI_GLOBAL) status = cdiInqKeyBytes(cdiID, CDI_GLOBAL, key, bytes, length);
 
   const cdi_keys_t *keysp = cdi_get_keysp(cdiID, varID);
   xassert(keysp != NULL);
@@ -629,8 +614,8 @@ cdiDefKeyString(int cdiID, int varID, int key, const char *string)
 {
   xassert(string != NULL);
 
-  int length = strlen(string) + 1;
-  int status = cdiDefKeyBytes(cdiID, varID, key, (const unsigned char *) string, length);
+  const int length = strlen(string) + 1;
+  const int status = cdiDefKeyBytes(cdiID, varID, key, (const unsigned char *) string, length);
 
   return status;
 }
@@ -684,10 +669,10 @@ cdiInqKeyString(int cdiID, int varID, int key, char *string, int *length)
   if (maxlength > 0) string[0] = '\0';
 
   int status = cdiInqKeyBytes(cdiID, varID, key, (unsigned char *) string, length);
-  if (status != CDI_NOERR)
-    *length = 0;
-  else
+  if (CDI_NOERR == status)
     string[maxlength - 1] = '\0';
+  else
+    *length = 0;
 
   return status;
 }
diff --git a/src/cmake/libcdi/cdi-config-version.cmake.in b/src/cmake/cdi/cdi-config-version.cmake.in
similarity index 100%
rename from src/cmake/libcdi/cdi-config-version.cmake.in
rename to src/cmake/cdi/cdi-config-version.cmake.in
diff --git a/src/cmake/libcdi/cdi-config.cmake.in b/src/cmake/cdi/cdi-config.cmake.in
similarity index 100%
rename from src/cmake/libcdi/cdi-config.cmake.in
rename to src/cmake/cdi/cdi-config.cmake.in
diff --git a/src/grb_read.c b/src/grb_read.c
index 453474ef089d20e1e447421c0033cba42177ffa5..632abd3df1a25003ea70c2fe862b6e3162c899d3 100644
--- a/src/grb_read.c
+++ b/src/grb_read.c
@@ -19,8 +19,8 @@
 #include "cgribex.h" /* gribZip gribGetZip gribGinfo */
 
 static int
-grbDecode(int filetype, int memtype, void *cgribexp, void *gribbuffer, size_t gribsize, void *data, size_t datasize, int unreduced,
-          size_t *nmiss, double missval)
+grb_decode(int filetype, int memtype, void *cgribexp, void *gribbuffer, size_t gribsize, void *data, size_t datasize, int unreduced,
+           size_t *nmiss, double missval)
 {
   int status = 0;
 
@@ -60,7 +60,7 @@ grbDecode(int filetype, int memtype, void *cgribexp, void *gribbuffer, size_t gr
 
 // Decompresses the grib data in gribbuffer.
 static int
-grbUnzipRecord(void *gribbuffer, size_t *gribsize)
+grib1_unzip_record(void *gribbuffer, size_t *gribsize)
 {
   int zip = 0;
 
@@ -72,7 +72,7 @@ grbUnzipRecord(void *gribbuffer, size_t *gribsize)
   if ((izip = gribGetZip(igribsize, (unsigned char *) gribbuffer, &unzipsize)) > 0)
     {
       zip = izip;
-      if (izip == 128) /* szip */
+      if (izip == 128) // szip
         {
           if (unzipsize < igribsize)
             {
@@ -80,7 +80,7 @@ grbUnzipRecord(void *gribbuffer, size_t *gribsize)
               return 0;
             }
 
-          unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
+          unzipsize += 100; // need 0 to 1 bytes for rounding of bds
 
           void *buffer = Malloc(igribsize);
           memcpy(buffer, gribbuffer, igribsize);
@@ -115,9 +115,9 @@ static int
 grb_decode_record(void *untypedArgs)
 {
   DecodeArgs *args = (DecodeArgs *) untypedArgs;
-  *args->outZip = grbUnzipRecord(args->gribbuffer, &args->recsize);
-  grbDecode(args->filetype, args->memtype, args->cgribexp, args->gribbuffer, args->recsize, args->data, args->gridsize,
-            args->unreduced, &args->nmiss, args->missval);
+  *args->outZip = grib1_unzip_record(args->gribbuffer, &args->recsize);
+  grb_decode(args->filetype, args->memtype, args->cgribexp, args->gribbuffer, args->recsize, args->data, args->gridsize,
+             args->unreduced, &args->nmiss, args->missval);
   return 0;
 }
 
@@ -135,7 +135,7 @@ grb_read_raw_data(stream_t *streamptr, int recID, int memtype, void *gribbuffer,
 
   void *cgribexp = (gribbuffer && streamptr->record->objectp) ? streamptr->record->objectp : NULL;
   if (!gribbuffer) gribbuffer = Malloc(streamptr->record->buffersize);
-  if (!data) data = Malloc(gridsize * (memtype == MEMTYPE_FLOAT ? sizeof(float) : sizeof(double)));
+  if (!data) data = Malloc(gridsize * ((memtype == MEMTYPE_FLOAT) ? sizeof(float) : sizeof(double)));
 
   if (streamptr->protocol == CDI_PROTOCOL_FDB)
     {
@@ -148,24 +148,17 @@ grb_read_raw_data(stream_t *streamptr, int recID, int memtype, void *gribbuffer,
     }
   else
     {
+      if (recsize == 0) Error("Internal problem! Recordsize is zero for record %d at timestep %d", recID + 1, tsID + 1);
+
       const int fileID = streamptr->fileID;
       const off_t recpos = streamptr->tsteps[tsID].records[recID].position;
+      const off_t currentfilepos = (resetFilePos ? fileGetPos(fileID) : 0);
 
-      if (recsize == 0) Error("Internal problem! Recordsize is zero for record %d at timestep %d", recID + 1, tsID + 1);
+      fileSetPos(fileID, recpos, SEEK_SET);
+      if (fileRead(fileID, gribbuffer, recsize) != recsize) Error("Failed to read GRIB record!");
 
-      if (resetFilePos)
-        {
-          const off_t currentfilepos = fileGetPos(fileID);
-          fileSetPos(fileID, recpos, SEEK_SET);
-          if (fileRead(fileID, gribbuffer, recsize) != recsize) Error("Failed to read GRIB record!");
-          fileSetPos(fileID, currentfilepos, SEEK_SET);
-        }
-      else
-        {
-          fileSetPos(fileID, recpos, SEEK_SET);
-          if (fileRead(fileID, gribbuffer, recsize) != recsize) Error("Failed to read GRIB record!");
-          streamptr->numvals += gridsize;
-        }
+      if (resetFilePos) fileSetPos(fileID, currentfilepos, SEEK_SET);
+      if (!resetFilePos) streamptr->numvals += gridsize;
     }
 
   return (DecodeArgs){
@@ -184,6 +177,14 @@ grb_read_raw_data(stream_t *streamptr, int recID, int memtype, void *gribbuffer,
   };
 }
 
+static size_t
+grb_read_and_decode_record(stream_t *streamptr, int recID, int memtype, void *data, bool resetFilePos)
+{
+  DecodeArgs args = grb_read_raw_data(streamptr, recID, memtype, streamptr->record->buffer, data, resetFilePos);
+  grb_decode_record(&args);
+  return args.nmiss;
+}
+
 typedef struct JobDescriptor
 {
   DecodeArgs args;
@@ -202,7 +203,7 @@ static void
 JobDescriptor_finishJob(AsyncManager *jobManager, JobDescriptor *me, void *data, size_t *nmiss)
 {
   if (AsyncWorker_wait(jobManager, me->job)) xabort("error executing job in worker thread");
-  memcpy(data, me->args.data, me->args.gridsize * (me->args.memtype == MEMTYPE_FLOAT ? sizeof(float) : sizeof(double)));
+  memcpy(data, me->args.data, me->args.gridsize * ((me->args.memtype == MEMTYPE_FLOAT) ? sizeof(float) : sizeof(double)));
   *nmiss = me->args.nmiss;
 
   Free(me->args.gribbuffer);
@@ -228,7 +229,7 @@ grb_read_next_record(stream_t *streamptr, int recID, int memtype, void *data, si
 
       if (!jobs)
         {
-          jobs = (JobDescriptor *) malloc(workerCount * sizeof *jobs);
+          jobs = (JobDescriptor *) malloc(workerCount * sizeof(*jobs));
           streamptr->jobs = jobs;
           for (int i = 0; i < workerCount; i++) jobs[i].args.recID = -1;
           if (AsyncWorker_init(&jobManager, workerCount)) xabort("error while trying to start worker threads");
@@ -271,12 +272,7 @@ grb_read_next_record(stream_t *streamptr, int recID, int memtype, void *data, si
     }
 
   // perform the work synchronously if we didn't start a job for it yet
-  if (!jobFound)
-    {
-      DecodeArgs args = grb_read_raw_data(streamptr, recID, memtype, streamptr->record->buffer, data, resetFilePos);
-      grb_decode_record(&args);
-      *nmiss = args.nmiss;
-    }
+  if (!jobFound) *nmiss = grb_read_and_decode_record(streamptr, recID, memtype, data, resetFilePos);
 }
 
 void
@@ -295,7 +291,7 @@ grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, voi
   const int isub = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
   const int recID = streamptr->vars[varID].recordTable[isub].recordID[levelID];
 
-  grb_read_next_record(streamptr, recID, memtype, data, nmiss, true);
+  *nmiss = grb_read_and_decode_record(streamptr, recID, memtype, data, true);
 }
 
 void
@@ -318,16 +314,10 @@ grb_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nm
   for (int levelID = 0; levelID < nlevs; levelID++)
     {
       const int recID = streamptr->vars[varID].recordTable[isub].recordID[levelID];
+      const size_t offset = levelID * gridsize;
+      void *datap = (memtype == MEMTYPE_FLOAT) ? (void*)((float *) data + offset) : (void*)((double *) data + offset);
 
-      void *datap = NULL;
-      if (memtype == MEMTYPE_FLOAT)
-        datap = (float *) data + levelID * gridsize;
-      else
-        datap = (double *) data + levelID * gridsize;
-
-      size_t imiss;
-      grb_read_next_record(streamptr, recID, memtype, datap, &imiss, false);
-      *nmiss += imiss;
+      *nmiss += grb_read_and_decode_record(streamptr, recID, memtype, datap, false);
     }
 
   fileSetPos(fileID, currentfilepos, SEEK_SET);
diff --git a/src/grb_write.c b/src/grb_write.c
index 41f8223321a175e2ec151c59b1bbcbc59de4cbc0..815cc7239a5108894568cb696f605b4a4b5a5b91 100644
--- a/src/grb_write.c
+++ b/src/grb_write.c
@@ -343,8 +343,8 @@ grbCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
       const int zaxisType = zaxisInqType(zaxisID);
 
       FDB_Keys fdbKeys;
-      snprintf(fdbKeys.date, sizeof(fdbKeys.date), "%d", (int)cdiDate_get(streamptr1->tsteps[tsID].taxis.vdatetime.date));
-      snprintf(fdbKeys.time, sizeof(fdbKeys.time), "%04d", cdiTime_get(streamptr1->tsteps[tsID].taxis.vdatetime.time) / 100);
+      snprintf(fdbKeys.date, sizeof(fdbKeys.date), "%d", (int) cdiDate_get(streamptr1->tsteps[tsID].taxis.vdatetime.date));
+      snprintf(fdbKeys.time, sizeof(fdbKeys.time), "%04d", (short)(cdiTime_get(streamptr1->tsteps[tsID].taxis.vdatetime.time) / 100));
       snprintf(fdbKeys.param, sizeof(fdbKeys.param), "%d", get_fdb_param(record->param));
       const bool isML = (zaxisType == ZAXIS_HYBRID || zaxisType == ZAXIS_HYBRID_HALF);
       snprintf(fdbKeys.levtype, sizeof(fdbKeys.levtype), "%s", isML ? "ml" : "sfc");
@@ -378,7 +378,7 @@ grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, co
   const int zaxisID = vlistInqVarZaxis(vlistID, varID);
   const int tsteptype = vlistInqVarTsteptype(vlistID, varID);
   const int tsID = streamptr->curTsID;
-  const int date = (int)cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date);
+  const int date = (int) cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date);
   const int time = cdiTime_get(streamptr->tsteps[tsID].taxis.vdatetime.time);
   const int numavg = (tsteptype == TSTEP_AVG) ? streamptr->tsteps[tsID].taxis.numavg : 0;
   int comptype = streamptr->comptype;
@@ -424,8 +424,8 @@ grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, co
         const double level = zaxisInqLevel(zaxisID, levelID);
 
         FDB_Keys fdbKeys;
-        snprintf(fdbKeys.date, sizeof(fdbKeys.date), "%d", (int)cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date));
-        snprintf(fdbKeys.time, sizeof(fdbKeys.time), "%04d", cdiTime_get(streamptr->tsteps[tsID].taxis.vdatetime.time) / 100);
+        snprintf(fdbKeys.date, sizeof(fdbKeys.date), "%d", (int) cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date));
+        snprintf(fdbKeys.time, sizeof(fdbKeys.time), "%04d", (short)(cdiTime_get(streamptr->tsteps[tsID].taxis.vdatetime.time) / 100));
         snprintf(fdbKeys.param, sizeof(fdbKeys.param), "%d", get_fdb_param(vlistInqVarParam(vlistID, varID)));
         const bool isML = (zaxisType == ZAXIS_HYBRID || zaxisType == ZAXIS_HYBRID_HALF);
         snprintf(fdbKeys.levtype, sizeof(fdbKeys.levtype), "%s", isML ? "ml" : "sfc");
diff --git a/src/gribapi.c b/src/gribapi.c
index 7336e13d6203e6f578927488028fc2c0a4df5cd4..c063ac5abc545da111cf31147a03259fecb63a30 100644
--- a/src/gribapi.c
+++ b/src/gribapi.c
@@ -42,7 +42,7 @@ gribapiLibraryVersionString(void)
       int major_version, minor_version, revision_version;
       gribapiLibraryVersion(&major_version, &minor_version, &revision_version);
 
-      sprintf(gribapi_libvers, "%d.%d.%d", major_version, minor_version, revision_version);
+      snprintf(gribapi_libvers, sizeof(gribapi_libvers), "%d.%d.%d", major_version, minor_version, revision_version);
       gribapi_libvers_init = true;
     }
 #endif
diff --git a/src/gribapi_utilities.c b/src/gribapi_utilities.c
index 5d149cbb03aa5580981e96ff2a9d028a8da228d3..c87c92bf384b1c0f60b637a9201c53dc6a54e493 100644
--- a/src/gribapi_utilities.c
+++ b/src/gribapi_utilities.c
@@ -271,8 +271,9 @@ addToDate(struct tm *me, long long amount, long unit)
 static char *
 makeDateString(struct tm *me)
 {
-  char *result = (char *) Malloc(4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 4 + 1);
-  sprintf(result, "%04d-%02d-%02dT%02d:%02d:%02d.000", me->tm_year + 1900, me->tm_mon + 1, me->tm_mday, me->tm_hour, me->tm_min,
+  const size_t length = 4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 4 + 1;
+  char *result = (char *) Malloc(length);
+  snprintf(result, length, "%04d-%02d-%02dT%02d:%02d:%02d.000", me->tm_year + 1900, me->tm_mon + 1, me->tm_mday, me->tm_hour, me->tm_min,
           me->tm_sec);
   return result;
 }
diff --git a/src/grid.c b/src/grid.c
index 77dea09af6afd09f2a3e3beeae6173ca48a11b48..88937b37c480e1321d88e30b6bbdd93ea536be94 100644
--- a/src/grid.c
+++ b/src/grid.c
@@ -898,6 +898,7 @@ gridInqProjType(int gridID)
           else if (strIsEqual(gmapname, "lambert_conformal_conic"))      projtype = CDI_PROJ_LCC;
           else if (strIsEqual(gmapname, "sinusoidal"))                   projtype = CDI_PROJ_SINU;
           else if (strIsEqual(gmapname, "polar_stereographic"))          projtype = CDI_PROJ_STERE;
+          else if (strIsEqual(gmapname, "healpix"))                      projtype = CDI_PROJ_HEALPIX;
           // clang-format on
           gridptr->projtype = projtype;
         }
@@ -2593,7 +2594,7 @@ gridCompareP(void *gridptr1, void *gridptr2)
 }
 
 static void
-gridComplete(grid_t *grid)
+grid_complete(grid_t *grid)
 {
   const int gridID = grid->self;
 
@@ -2781,7 +2782,7 @@ gridGenerate(const grid_t *grid)
   gridptr->gme.ni2 = grid->gme.ni2;
   gridptr->gme.ni3 = grid->gme.ni3;
 
-  gridComplete(gridptr);
+  grid_complete(gridptr);
 
   cdiCopyVarKey(&grid->keys, CDI_KEY_UUID, &gridptr->keys);
 
@@ -4613,8 +4614,8 @@ cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
           1 search in grid table only
           2 search in grid table only and don't store the grid in vlist
    */
-  bool gridglobdefined = false;
-  bool griddefined = false;
+  bool gridIsDefinedGlobal = false;
+  bool gridIsDefined = false;
   int gridID = CDI_UNDEFID;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
@@ -4627,7 +4628,7 @@ cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
           {
             if (gridCompare(gridID, grid, false) == false)
               {
-                griddefined = true;
+                gridIsDefined = true;
                 break;
               }
           }
@@ -4635,28 +4636,28 @@ cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
           Error("Internal problem: undefined gridID in vlist %d, position %u!", vlistID, index);
       }
 
-  if (!griddefined)
+  if (!gridIsDefined)
     {
       struct gridCompareSearchState query;
       query.queryKey = grid;  // = { .queryKey = grid };
-      if ((gridglobdefined = (cdiResHFilterApply(&gridOps, gridCompareSearch, &query) == CDI_APPLY_STOP)))
+      if ((gridIsDefinedGlobal = (cdiResHFilterApply(&gridOps, gridCompareSearch, &query) == CDI_APPLY_STOP)))
         gridID = query.resIDValue;
 
-      if (mode == 1 && gridglobdefined)
+      if (mode == 1 && gridIsDefinedGlobal)
         for (int index = 0; index < ngrids; index++)
           if (vlistptr->gridIDs[index] == gridID)
             {
-              gridglobdefined = false;
+              gridIsDefinedGlobal = false;
               break;
             }
     }
 
-  if (!griddefined)
+  if (!gridIsDefined)
     {
-      if (!gridglobdefined)
+      if (!gridIsDefinedGlobal)
         {
           grid->self = gridID = reshPut(grid, &gridOps);
-          gridComplete(grid);
+          grid_complete(grid);
         }
       if (mode < 2)
         {
@@ -4666,7 +4667,7 @@ cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
         }
     }
 
-  return (struct addIfNewRes){ .Id = gridID, .isNew = (!griddefined && !gridglobdefined) };
+  return (struct addIfNewRes){ .Id = gridID, .isNew = (!gridIsDefined && !gridIsDefinedGlobal) };
 }
 
 const struct gridVirtTable cdiGridVtable = {
diff --git a/src/grid.h b/src/grid.h
index 6f1e056e3130415912ed1c4b4139ca81ee30cb34..5546947ff26465ef6c4a04fc39183d681d8a644d 100644
--- a/src/grid.h
+++ b/src/grid.h
@@ -148,8 +148,8 @@ struct addIfNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode);
 int gridVerifyProjParamsLCC(struct CDI_GridProjParams *gpp);
 int gridVerifyProjParamsSTERE(struct CDI_GridProjParams *gpp);
 
-bool isGaussianLatitudes(SizeType nlats, const double *latitudes);
-void gaussianLatitudes(SizeType nlats, double *latitudes, double *weights);
+bool isGaussianLatitudes(size_t nlats, const double *latitudes);
+void gaussianLatitudes(size_t nlats, double *latitudes, double *weights);
 
 int gridFromMGF(MGF *mgf);
 
diff --git a/src/iterator_grib.c b/src/iterator_grib.c
index 40991e7323c7b1d685d15b26bd25c5722f438807..42699dd9710cf7624602c005db508d2920deebe6 100644
--- a/src/iterator_grib.c
+++ b/src/iterator_grib.c
@@ -339,10 +339,10 @@ static void hexdump(void *data, size_t size)
 
 // Read a record into memory and wrap it in a grib_handle.
 // XXX: I have omitted checking for szip compression as it is done in grbReadVarDP() & friends since that appears to be a
-// non-standard extension of the GRIB1 standard: bit 1 in octet 14 of the binary data section which is used to signal szip compressio
-// is defined to be reserved in the standard. As such, it seems prudent not to support this and to encourage people with such szip
-// compressed files to switch to the GRIB2/JPEG2000 format. However, in the case that this reasoning is wrong, this function is
-// probably the place to add the check for zsip compression.
+// non-standard extension of the GRIB1 standard: bit 1 in octet 14 of the binary data section which is used to signal szip
+// compressio is defined to be reserved in the standard. As such, it seems prudent not to support this and to encourage people with
+// such szip compressed files to switch to the GRIB2/JPEG2000 format. However, in the case that this reasoning is wrong, this
+// function is probably the place to add the check for zsip compression.
 static int
 readMessage(CdiGribIterator *me)
 {
diff --git a/src/julian_date.c b/src/julian_date.c
index 23df04a77df843ca8400ce2bad52616b21312c63..0c9fe2643aa13c68105f720d5cfecc4f3e762ea6 100644
--- a/src/julian_date.c
+++ b/src/julian_date.c
@@ -3,10 +3,10 @@
 
 // convert Julian calendar day into year, months, day
 static void
-decode_julday(int calendar, int64_t julianDay, // Julian day number to convert
-              int *year,                       // Gregorian year (out)
-              int *mon,                        // Gregorian month (1-12) (out)
-              int *day)                        // Gregorian day (1-31) (out)
+decode_julday(int calendar, int64_t julianDay,  // Julian day number to convert
+              int *year,                        // Gregorian year (out)
+              int *mon,                         // Gregorian month (1-12) (out)
+              int *day)                         // Gregorian day (1-31) (out)
 {
   const int64_t a = julianDay;
 
@@ -241,84 +241,86 @@ main(void)
 
   // 1 - Check valid range of years
   {
-  int nmin = 11000;
-  int vdate0 = -80001201;
-  int vtime0 = 120500;
+    int nmin = 11000;
+    int vdate0 = -80001201;
+    int vtime0 = 120500;
 
-  printf("start time: %8d %4d\n", vdate0, vtime0);
+    printf("start time: %8d %4d\n", vdate0, vtime0);
 
-  CdiDateTime dt = cdiDateTime_set(vdate0, vtime0);
+    CdiDateTime dt = cdiDateTime_set(vdate0, vtime0);
 
-  for (int i = 0; i < nmin; i++)
-    {
-      JulianDate julianDate = julianDate_encode(calendar, dt);
+    for (int i = 0; i < nmin; i++)
+      {
+        JulianDate julianDate = julianDate_encode(calendar, dt);
 
-      dt = julianDate_decode(calendar, julianDate);
-      int vdate = (int)cdiDate_get(dt.date);
-      int vtime = cdiTime_get(dt.time);
+        dt = julianDate_decode(calendar, julianDate);
+        int vdate = (int) cdiDate_get(dt.date);
+        int vtime = cdiTime_get(dt.time);
 
-      if (vdate0 != vdate || vtime0 != vtime)
-        printf("%4d %8d %4d %8d %4d %9d %g\n", ++j, vdate0, vtime0, vdate, vtime, (int)julianDate.julianDay, julianDate.secondOfDay);
+        if (vdate0 != vdate || vtime0 != vtime)
+          printf("%4d %8d %4d %8d %4d %9d %g\n", ++j, vdate0, vtime0, vdate, vtime, (int) julianDate.julianDay,
+                 julianDate.secondOfDay);
 
-      dt.date.year++;
-      julianDate = julianDate_encode(calendar, dt);
+        dt.date.year++;
+        julianDate = julianDate_encode(calendar, dt);
 
-      dt = julianDate_decode(calendar, julianDate);
-      vdate0 = (int)cdiDate_get(dt.date);
-      vtime0 = cdiTime_get(dt.time);
-    }
+        dt = julianDate_decode(calendar, julianDate);
+        vdate0 = (int) cdiDate_get(dt.date);
+        vtime0 = cdiTime_get(dt.time);
+      }
 
-  printf("stop time: %8d %4d\n", vdate0, vtime0);
+    printf("stop time: %8d %4d\n", vdate0, vtime0);
   }
   // 2 - Check time increment of one minute
   {
-  int nmin = 120000;
-  int ijulinc = 60;
-  int vdate0 = 20001201;
-  int vtime0 = 0;
-
-  printf("start time: %8d %4d\n", vdate0, vtime0);
-
-  CdiDateTime dt = cdiDateTime_set(vdate0, vtime0);
-  JulianDate julianDate = julianDate_encode(calendar, dt);
-
-  for (int i = 0; i < nmin; i++)
-    {
-      int year, mon, day, hour, minute, second;
-      cdiDecodeDate(vdate0, &year, &mon, &day);
-      cdiDecodeTime(vtime0, &hour, &minute, &second);
-
-      if (++minute >= 60)
-        {
-          minute = 0;
-          if (++hour >= 24)
-            {
-              hour = 0;
-              if (++day >= 32)
-                {
-                  day = 1;
-                  if (++mon >= 13)
-                    {
-                      mon = 1;
-                      year++;
-                    }
-                }
-            }
-        }
-
-      vdate0 = cdiEncodeDate(year, mon, day);
-      vtime0 = cdiEncodeTime(hour, minute, second);
-
-      julianDate = julianDate_add_seconds(julianDate, ijulinc);
-      dt = julianDate_decode(calendar, julianDate);
-      int vdate = (int)cdiDate_get(dt.date);
-      int vtime = cdiTime_get(dt.time);
-
-      if (vdate0 != vdate || vtime0 != vtime)
-        printf("%4d %8d %4d %8d %4d %9d %g\n", ++j, vdate0, vtime0, vdate, vtime, (int)julianDate.julianDay, julianDate.secondOfDay);
-    }
-
-  printf("stop time: %8d %4d\n", vdate0, vtime0);
+    int nmin = 120000;
+    int ijulinc = 60;
+    int vdate0 = 20001201;
+    int vtime0 = 0;
+
+    printf("start time: %8d %4d\n", vdate0, vtime0);
+
+    CdiDateTime dt = cdiDateTime_set(vdate0, vtime0);
+    JulianDate julianDate = julianDate_encode(calendar, dt);
+
+    for (int i = 0; i < nmin; i++)
+      {
+        int year, mon, day, hour, minute, second;
+        cdiDecodeDate(vdate0, &year, &mon, &day);
+        cdiDecodeTime(vtime0, &hour, &minute, &second);
+
+        if (++minute >= 60)
+          {
+            minute = 0;
+            if (++hour >= 24)
+              {
+                hour = 0;
+                if (++day >= 32)
+                  {
+                    day = 1;
+                    if (++mon >= 13)
+                      {
+                        mon = 1;
+                        year++;
+                      }
+                  }
+              }
+          }
+
+        vdate0 = cdiEncodeDate(year, mon, day);
+        vtime0 = cdiEncodeTime(hour, minute, second);
+
+        julianDate = julianDate_add_seconds(julianDate, ijulinc);
+        dt = julianDate_decode(calendar, julianDate);
+        int vdate = (int) cdiDate_get(dt.date);
+        int vtime = cdiTime_get(dt.time);
+
+        if (vdate0 != vdate || vtime0 != vtime)
+          printf("%4d %8d %4d %8d %4d %9d %g\n", ++j, vdate0, vtime0, vdate, vtime, (int) julianDate.julianDay,
+                 julianDate.secondOfDay);
+      }
+
+    printf("stop time: %8d %4d\n", vdate0, vtime0);
   }
   return 0;
 }
@@ -343,19 +345,20 @@ main(void)
   CdiDateTime dt;
   dt.date = cdiDate_encode(year, month, day);
   dt.time = cdiTime_encode(hour, minute, second, ms);
-  printf("%d/%02d/%02d %02d:%02d:%02d.%03d\n",
-         dt.date.year, dt.date.month, dt.date.day, dt.time.hour, dt.time.minute, dt.time.second, dt.time.ms);
+  printf("%d/%02d/%02d %02d:%02d:%02d.%03d\n", dt.date.year, dt.date.month, dt.date.day, dt.time.hour, dt.time.minute,
+         dt.time.second, dt.time.ms);
 
   JulianDate julianDate = julianDate_encode(calendar, dt);
 
   dt = julianDate_decode(calendar, julianDate);
-  printf("%d/%02d/%02d %02d:%02d:%02d.%03d   %d %g\n",
-         dt.date.year, dt.date.month, dt.date.day, dt.time.hour, dt.time.minute, dt.time.second, dt.time.ms, (int)julianDate.julianDay, julianDate.secondOfDay);
+  printf("%d/%02d/%02d %02d:%02d:%02d.%03d   %d %g\n", dt.date.year, dt.date.month, dt.date.day, dt.time.hour, dt.time.minute,
+         dt.time.second, dt.time.ms, (int) julianDate.julianDay, julianDate.secondOfDay);
 
   for (int i = 0; i < 420; i++)
     {
       dt = julianDate_decode(calendar, julianDate);
-      printf("%2d %d/%02d/%02d %02d:%02d:%02d.%03d\n", i, dt.date.year, dt.date.month, dt.date.day, dt.time.hour, dt.time.minute, dt.time.second, dt.time.ms);
+      printf("%2d %d/%02d/%02d %02d:%02d:%02d.%03d\n", i, dt.date.year, dt.date.month, dt.date.day, dt.time.hour, dt.time.minute,
+             dt.time.second, dt.time.ms);
       julianDate = julianDate_add_seconds(julianDate, value * factor);
     }
 
diff --git a/src/make_fint.c b/src/make_fint.c
index db4bcca1d3a5d307b83fd8da134e9ad7d15aa3f3..b06e6c74b1c5c393850636cce75ee3c6ee60544e 100644
--- a/src/make_fint.c
+++ b/src/make_fint.c
@@ -18,7 +18,7 @@
 // clang-format off
 
 //#include "config.h"
-#define VERSION "2.0.0"
+#define VERSION "2.1.0"
 
 typedef struct
 {
diff --git a/src/mo_cdi.f90 b/src/mo_cdi.f90
index 85f4c88eac1fee2e1efc1ccc173fe5a8d7fc3be9..5886bc7832707166f229fb27f34c11d0f55317c2 100644
--- a/src/mo_cdi.f90
+++ b/src/mo_cdi.f90
@@ -147,6 +147,7 @@ module mo_cdi
   integer(c_int), public, parameter :: CDI_PROJ_LAEA = 23
   integer(c_int), public, parameter :: CDI_PROJ_SINU = 24
   integer(c_int), public, parameter :: CDI_PROJ_STERE = 25
+  integer(c_int), public, parameter :: CDI_PROJ_HEALPIX = 26
   integer(c_int), public, parameter :: ZAXIS_SURFACE = 0
   integer(c_int), public, parameter :: ZAXIS_GENERIC = 1
   integer(c_int), public, parameter :: ZAXIS_HYBRID = 2
@@ -412,12 +413,6 @@ module mo_cdi
   public :: vlistInqVarUnits
   public :: vlistDefVarMissval
   public :: vlistInqVarMissval
-  public :: vlistDefVarExtra
-  public :: vlistInqVarExtra
-  public :: vlistDefVarScalefactor
-  public :: vlistInqVarScalefactor
-  public :: vlistDefVarAddoffset
-  public :: vlistInqVarAddoffset
   public :: vlistInqVarSize
   public :: vlistDefIndex
   public :: vlistInqIndex
@@ -483,6 +478,7 @@ module mo_cdi
   integer(c_int), public, parameter :: CDI_KEY_UNITS = 945
   integer(c_int), public, parameter :: CDI_KEY_DATATYPE = 946
   integer(c_int), public, parameter :: CDI_KEY_REFERENCEURI = 947
+  integer(c_int), public, parameter :: CDI_KEY_CHUNKS = 948
   integer(c_int), public, parameter :: CDI_KEY_NUMBEROFGRIDUSED = 961
   integer(c_int), public, parameter :: CDI_KEY_NUMBEROFGRIDINREFERENCE = 962
   integer(c_int), public, parameter :: CDI_KEY_NUMBEROFVGRIDUSED = 963
@@ -490,6 +486,8 @@ module mo_cdi
   integer(c_int), public, parameter :: CDI_KEY_CHUNKTYPE = 965
   integer(c_int), public, parameter :: CDI_KEY_CHUNKSIZE = 966
   integer(c_int), public, parameter :: CDI_KEY_MISSVAL = 701
+  integer(c_int), public, parameter :: CDI_KEY_ADDOFFSET = 702
+  integer(c_int), public, parameter :: CDI_KEY_SCALEFACTOR = 703
   integer(c_int), public, parameter :: CDI_KEY_UUID = 960
   integer(c_int), public, parameter :: CDI_KEY_DIMNAME = 941
   integer(c_int), public, parameter :: CDI_KEY_PSNAME = 950
@@ -1624,38 +1622,6 @@ module mo_cdi
       real(c_double) :: f_result
     end function vlistInqVarMissval
 
-    subroutine vlistDefVarScalefactor(vlistID_dummy, varID_dummy,&
-    & scalefactor_dummy) bind(c, name = 'vlistDefVarScalefactor')
-      import c_double, c_int
-      integer(c_int), value :: vlistID_dummy
-      integer(c_int), value :: varID_dummy
-      real(c_double), value :: scalefactor_dummy
-    end subroutine vlistDefVarScalefactor
-
-    function vlistInqVarScalefactor(vlistID_dummy, varID_dummy) bind(c, name =&
-    & 'vlistInqVarScalefactor') result(f_result)
-      import c_double, c_int
-      integer(c_int), value :: vlistID_dummy
-      integer(c_int), value :: varID_dummy
-      real(c_double) :: f_result
-    end function vlistInqVarScalefactor
-
-    subroutine vlistDefVarAddoffset(vlistID_dummy, varID_dummy,&
-    & addoffset_dummy) bind(c, name = 'vlistDefVarAddoffset')
-      import c_double, c_int
-      integer(c_int), value :: vlistID_dummy
-      integer(c_int), value :: varID_dummy
-      real(c_double), value :: addoffset_dummy
-    end subroutine vlistDefVarAddoffset
-
-    function vlistInqVarAddoffset(vlistID_dummy, varID_dummy) bind(c, name =&
-    & 'vlistInqVarAddoffset') result(f_result)
-      import c_double, c_int
-      integer(c_int), value :: vlistID_dummy
-      integer(c_int), value :: varID_dummy
-      real(c_double) :: f_result
-    end function vlistInqVarAddoffset
-
     function vlistInqVarSize(vlistID_dummy, varID_dummy) bind(c, name =&
     & 'vlistInqVarSize') result(f_result)
       import c_int
@@ -4437,61 +4403,6 @@ contains
     end do
   end subroutine vlistInqVarUnits
 
-  subroutine vlistDefVarExtra(vlistID_dummy, varID_dummy, extra_dummy)
-    integer(c_int), value :: vlistID_dummy
-    integer(c_int), value :: varID_dummy
-    character(kind = c_char, len = *), intent(in) :: extra_dummy
-    character(kind = c_char) :: extra_temp(len(extra_dummy) + 1)
-    integer :: extra_i
-    interface
-      subroutine lib_vlistDefVarExtra(vlistID_dummy, varID_dummy, extra_dummy)&
-      & bind(c, name = 'vlistDefVarExtra')
-        import c_char, c_int
-        integer(c_int), value :: vlistID_dummy
-        integer(c_int), value :: varID_dummy
-        character(kind = c_char) :: extra_dummy(*)
-      end subroutine lib_vlistDefVarExtra
-    end interface
-    do extra_i = 1, len(extra_dummy)
-      extra_temp(extra_i) = extra_dummy(extra_i:extra_i)
-    end do
-    extra_temp(len(extra_dummy) + 1) = c_null_char
-    call lib_vlistDefVarExtra(vlistID_dummy, varID_dummy, extra_temp)
-  end subroutine vlistDefVarExtra
-
-  subroutine vlistInqVarExtra(vlistID_dummy, varID_dummy, extra_dummy)
-    integer(c_int), value :: vlistID_dummy
-    integer(c_int), value :: varID_dummy
-    character(kind = c_char, len = *), intent(inout) :: extra_dummy
-    character(kind = c_char) :: extra_temp(len(extra_dummy) + 1)
-    integer :: extra_i
-    interface
-      subroutine lib_vlistInqVarExtra(vlistID_dummy, varID_dummy, extra_dummy)&
-      & bind(c, name = 'vlistInqVarExtra')
-        import c_char, c_int
-        integer(c_int), value :: vlistID_dummy
-        integer(c_int), value :: varID_dummy
-        character(kind = c_char) :: extra_dummy(*)
-      end subroutine lib_vlistInqVarExtra
-    end interface
-    extra_temp(len(extra_dummy) + 1) = c_null_char
-    do extra_i = len(extra_dummy), 1, -1
-      if(extra_dummy(extra_i:extra_i) /= ' ') exit
-      extra_temp(extra_i) = c_null_char
-    end do
-    do extra_i = extra_i, 1, -1
-        extra_temp(extra_i) = extra_dummy(extra_i:extra_i)
-    end do
-    call lib_vlistInqVarExtra(vlistID_dummy, varID_dummy, extra_temp)
-    do extra_i = 1, len(extra_dummy)
-      if(extra_temp(extra_i) == c_null_char) exit
-      extra_dummy(extra_i:extra_i) = extra_temp(extra_i)
-    end do
-    do extra_i = extra_i, len(extra_dummy)
-      extra_dummy(extra_i:extra_i) = ' '
-    end do
-  end subroutine vlistInqVarExtra
-
   subroutine cdiDefAdditionalKey(string_dummy)
     character(kind = c_char, len = *), intent(in) :: string_dummy
     character(kind = c_char) :: string_temp(len(string_dummy) + 1)
diff --git a/src/namespace.h b/src/namespace.h
index bb725507db86fd96cec5edac319e5298426d2999..58397075e380cf3216301cfcbdd6e3d87b1a2420 100644
--- a/src/namespace.h
+++ b/src/namespace.h
@@ -47,7 +47,7 @@ union namespaceSwitchValue
   void (*func)();
 };
 
-#define NSSW_FUNC(p) ((union namespaceSwitchValue){ .func = (void (*)()) (p) })
+#define NSSW_FUNC(p) ((union namespaceSwitchValue){ .func = (void (*)())(p) })
 #define NSSW_DATA(p) ((union namespaceSwitchValue){ .data = (void *) (p) })
 
 // int              namespaceNew();
diff --git a/src/stream_cdf.h b/src/stream_cdf.h
index 1575887e82e9d11c05d9605c747b394f314022e3..14520600efb500fe043c198aa3c7e78b6798b737 100644
--- a/src/stream_cdf.h
+++ b/src/stream_cdf.h
@@ -32,15 +32,15 @@ void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
 
 void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype, const int rect[][2], const void *data, size_t nmiss);
 
-void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level);
+void cdfDefVarDeflate(int ncid, int ncvarid, int deflateLevel);
 void cdfDefTime(stream_t *streamptr);
 
 void cdf_scale_add(size_t size, double *data, double addoffset, double scalefactor);
 
 int cdfDefDatatype(int datatype, stream_t *streamptr);
 
-#define ChunkSizeMax     65536
-#define ChunkSizeLim  16777216
+#define ChunkSizeMax 65536
+#define ChunkSizeLim 16777216
 size_t calc_chunksize_x(int chunkType, int chunkSize, size_t xsize, bool yIsUndefined);
 size_t calc_chunksize_y(int chunkType, size_t gridsize, size_t xsize, size_t ysize);
 
diff --git a/src/stream_cdf_i.c b/src/stream_cdf_i.c
index fb076ffc9853b14e630b571aea5385befcb32701..42d7ee81d089394f6da4447b7af487dc31a7cc71 100644
--- a/src/stream_cdf_i.c
+++ b/src/stream_cdf_i.c
@@ -104,6 +104,11 @@ typedef struct
   bool chunked;
   int chunkType;
   int chunkSize;
+  size_t chunkCacheSize;
+  size_t chunkCacheNelems;
+  float chunkCachePreemption;
+  size_t gridSize;
+  size_t numLevels;
   int natts;
   int *atts;
   size_t vctsize;
@@ -120,6 +125,7 @@ typedef struct
   int typeOfEnsembleForecast;
   int numberOfForecastsInEnsemble;
   int perturbationNumber;
+  int unitsLen;
   char name[CDI_MAX_NAME];
   char longname[CDI_MAX_NAME];
   char stdname[CDI_MAX_NAME];
@@ -171,46 +177,46 @@ static int
 scan_time_units(const char *unitstr)
 {
   const size_t len = strlen(unitstr);
-  const int timeunit = get_timeunit(len, unitstr);
+  const int timeunit = get_time_units(len, unitstr);
   if (timeunit == -1) Message("Unsupported TIMEUNIT: %s!", unitstr);
   return timeunit;
 }
 
 static void
-setForecastTime(const char *timestr, taxis_t *taxis)
+set_forecast_time(const char *timestr, taxis_t *taxis)
 {
   const size_t len = strlen(timestr);
   if (len != 0)
     {
       const CdiDateTime datetime = scan_time_string(timestr);
-      taxis->fdate = (int)cdiDate_get(datetime.date);
+      taxis->fdate = (int) cdiDate_get(datetime.date);
       taxis->ftime = cdiTime_get(datetime.time);
-     }
+    }
   else
     taxis->fdate = taxis->ftime = 0;
 }
 
 static int
-setBaseTime(const char *timeunits, taxis_t *taxis)
+set_base_time(const char *timeUnitsStr, taxis_t *taxis)
 {
-  int taxistype = TAXIS_ABSOLUTE;
+  int taxisType = TAXIS_ABSOLUTE;
 
-  size_t len = strlen(timeunits);
-  while (isspace(*timeunits) && len)
+  size_t len = strlen(timeUnitsStr);
+  while (isspace(*timeUnitsStr) && len)
     {
-      timeunits++;
+      timeUnitsStr++;
       len--;
     }
 
-  char *tu = (char *) Malloc((len + 1) * sizeof(char));
+  char *tu = (char *) malloc((len + 1) * sizeof(char));
 
-  for (size_t i = 0; i < len; i++) tu[i] = (char) tolower((int) timeunits[i]);
+  for (size_t i = 0; i < len; i++) tu[i] = (char) tolower((int) timeUnitsStr[i]);
   tu[len] = 0;
 
-  int timeunit = get_timeunit(len, tu);
-  if (timeunit == -1)
+  int timeUnits = get_time_units(len, tu);
+  if (timeUnits == -1)
     {
-      Message("Unsupported TIMEUNIT: %s!", timeunits);
+      Message("Unsupported TIMEUNIT: %s!", timeUnitsStr);
       return 1;
     }
 
@@ -220,37 +226,37 @@ setBaseTime(const char *timeunits, taxis_t *taxis)
     {
       while (isspace(tu[pos])) ++pos;
 
-      if (strStartsWith(tu + pos, "since")) taxistype = TAXIS_RELATIVE;
+      if (strStartsWith(tu + pos, "since")) taxisType = TAXIS_RELATIVE;
 
       while (pos < len && !isspace(tu[pos])) ++pos;
       if (tu[pos])
         {
           while (isspace(tu[pos])) ++pos;
 
-          if (taxistype == TAXIS_ABSOLUTE)
+          if (taxisType == TAXIS_ABSOLUTE)
             {
-              if (timeunit == TUNIT_DAY)
+              if (timeUnits == TUNIT_DAY)
                 {
                   if (!strStartsWith(tu + pos, "%y%m%d.%f"))
                     {
                       Warning("Unsupported format %s for TIMEUNIT day!", tu + pos);
-                      timeunit = -1;
+                      timeUnits = -1;
                     }
                 }
-              else if (timeunit == TUNIT_MONTH)
+              else if (timeUnits == TUNIT_MONTH)
                 {
                   if (!strStartsWith(tu + pos, "%y%m.%f"))
                     {
                       Warning("Unsupported format %s for TIMEUNIT month!", tu + pos);
-                      timeunit = -1;
+                      timeUnits = -1;
                     }
                 }
-              else if (timeunit == TUNIT_YEAR)
+              else if (timeUnits == TUNIT_YEAR)
                 {
                   if (!strStartsWith(tu + pos, "%y.%f"))
                     {
                       Warning("Unsupported format %s for TIMEUNIT year!", tu + pos);
-                      timeunit = -1;
+                      timeUnits = -1;
                     }
                 }
               else
@@ -258,20 +264,21 @@ setBaseTime(const char *timeunits, taxis_t *taxis)
                   Warning("Unsupported format for time units: %s!", tu);
                 }
             }
-          else if (taxistype == TAXIS_RELATIVE)
+          else if (taxisType == TAXIS_RELATIVE)
             {
               taxis->rdatetime = scan_time_string(tu + pos);
-              if (CDI_Debug) Message("rdate = %d  rtime = %d", (int)cdiDate_get(taxis->rdatetime.date), cdiTime_get(taxis->rdatetime.time));
+              if (CDI_Debug)
+                Message("rdate = %d  rtime = %d", (int) cdiDate_get(taxis->rdatetime.date), cdiTime_get(taxis->rdatetime.time));
             }
         }
     }
 
-  taxis->type = taxistype;
-  taxis->unit = timeunit;
+  taxis->type = taxisType;
+  taxis->unit = timeUnits;
 
-  Free(tu);
+  free(tu);
 
-  if (CDI_Debug) Message("taxistype = %d  unit = %d", taxistype, timeunit);
+  if (CDI_Debug) Message("taxisType = %d  timeUnits = %d", taxisType, timeUnits);
 
   return 0;
 }
@@ -315,19 +322,19 @@ cdfInqDatatype(stream_t *streamptr, int xtype, bool lunsigned)
 #endif
 
   // clang-format off
-  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      (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;
 #ifdef 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;
+  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;
   else
     {
       if (xtype != streamptr->nc_complex_float_id && xtype != streamptr->nc_complex_double_id)
@@ -355,8 +362,8 @@ cdfInqDatatype(stream_t *streamptr, int xtype, bool lunsigned)
                 }
             }
         }
-      if      ( xtype == streamptr->nc_complex_float_id  )  datatype = CDI_DATATYPE_CPX32;
-      else if ( xtype == streamptr->nc_complex_double_id )  datatype = CDI_DATATYPE_CPX64;
+      if      (xtype == streamptr->nc_complex_float_id )  datatype = CDI_DATATYPE_CPX32;
+      else if (xtype == streamptr->nc_complex_double_id)  datatype = CDI_DATATYPE_CPX64;
     }
 #endif
   // clang-format on
@@ -416,11 +423,12 @@ cdfCheckAttText(int fileID, int ncvarid, const char *attname)
   nc_type atttype;
   const int status_nc = nc_inq_atttype(fileID, ncvarid, attname, &atttype);
 
-  return (status_nc == NC_NOERR && (atttype == NC_CHAR
+  return (status_nc == NC_NOERR
+          && (atttype == NC_CHAR
 #ifdef HAVE_NETCDF4
-          || atttype == NC_STRING
+              || atttype == NC_STRING
 #endif
-          ));
+              ));
 }
 
 static void
@@ -467,18 +475,18 @@ cdfGetAttText(int fileID, int ncvarid, const char *attname, size_t attlen, char
 void
 cdf_scale_add(size_t size, double *data, double addoffset, double scalefactor)
 {
-  const bool laddoffset = IS_NOT_EQUAL(addoffset, 0);
-  const bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+  const bool haveAddoffset = IS_NOT_EQUAL(addoffset, 0.0);
+  const bool haveScalefactor = IS_NOT_EQUAL(scalefactor, 1.0);
 
-  if (laddoffset && lscalefactor)
+  if (haveAddoffset && haveScalefactor)
     {
       for (size_t i = 0; i < size; ++i) data[i] = data[i] * scalefactor + addoffset;
     }
-  else if (lscalefactor)
+  else if (haveScalefactor)
     {
       for (size_t i = 0; i < size; ++i) data[i] *= scalefactor;
     }
-  else if (laddoffset)
+  else if (haveAddoffset)
     {
       for (size_t i = 0; i < size; ++i) data[i] += addoffset;
     }
@@ -502,7 +510,7 @@ cdfCreateRecords(stream_t *streamptr, int tsID)
 
   if (tsID == 0)
     {
-      const int nvrecs = nrecs; /* use all records at first timestep */
+      const int nvrecs = nrecs; // use all records at first timestep
 
       streamptr->nrecs += nrecs;
 
@@ -709,14 +717,19 @@ init_ncvars(int nvars, ncvar_t *ncvars)
       ncvar->chunked = false;
       ncvar->chunkType = CDI_UNDEFID;
       ncvar->chunkSize = CDI_UNDEFID;
+      ncvar->chunkCacheSize = 0;
+      ncvar->chunkCacheNelems = 0;
+      ncvar->chunkCachePreemption = 0.0;
+      ncvar->gridSize = 0;
+      ncvar->numLevels = 0;
       ncvar->natts = 0;
       ncvar->atts = NULL;
       ncvar->vctsize = 0;
       ncvar->vct = NULL;
       ncvar->missval = 0;
       ncvar->fillval = 0;
-      ncvar->addoffset = 0;
-      ncvar->scalefactor = 1;
+      ncvar->addoffset = 0.0;
+      ncvar->scalefactor = 1.0;
       ncvar->ldeflate = false;
       ncvar->lszip = false;
       ncvar->lunsigned = false;
@@ -726,6 +739,7 @@ init_ncvars(int nvars, ncvar_t *ncvars)
       ncvar->typeOfEnsembleForecast = -1;
       ncvar->numberOfForecastsInEnsemble = -1;
       ncvar->perturbationNumber = -1;
+      ncvar->unitsLen = 0;
       memset(ncvar->name, 0, CDI_MAX_NAME);
       memset(ncvar->longname, 0, CDI_MAX_NAME);
       memset(ncvar->stdname, 0, CDI_MAX_NAME);
@@ -1092,6 +1106,21 @@ cdf_get_cell_varid(char *attstring, int ncid)
   return nc_cell_id;
 }
 
+static void
+set_extra_attr(char *buf, int nvdims, const size_t *chunks)
+{
+  size_t pos = strlen(buf);
+  static const char prefix[] = "chunks=";
+  memcpy(buf + pos, prefix, sizeof(prefix));
+  pos += sizeof(prefix) - 1;
+  for (int i = nvdims - 1; i >= 0; --i)
+    {
+      pos += (size_t) (sprintf(buf + pos, "%zu%s", chunks[i], i > 0 ? "x" : ""));
+    }
+  buf[pos] = ' ';
+  buf[pos + 1] = 0;
+}
+
 static void
 cdfScanVarAttr(int nvars, ncvar_t *ncvars, int ndims, ncdim_t *ncdims, int timedimid, int modelID, int format)
 {
@@ -1134,8 +1163,8 @@ cdfScanVarAttr(int nvars, ncvar_t *ncvars, int ndims, ncdim_t *ncdims, int timed
 #ifdef HAVE_NETCDF4
       if (format == NC_FORMAT_NETCDF4_CLASSIC || format == NC_FORMAT_NETCDF4)
         {
-          int shuffle = 0, deflate = 0, deflate_level = 0;
-          nc_inq_var_deflate(ncid, ncvarid, &shuffle, &deflate, &deflate_level);
+          int shuffle = 0, deflate = 0, deflateLevel = 0;
+          nc_inq_var_deflate(ncid, ncvarid, &shuffle, &deflate, &deflateLevel);
           if (deflate > 0) ncvar->ldeflate = true;
 
 #ifdef HAVE_NC_DEF_VAR_SZIP
@@ -1143,43 +1172,36 @@ cdfScanVarAttr(int nvars, ncvar_t *ncvars, int ndims, ncdim_t *ncdims, int timed
           nc_inq_var_szip(ncid, ncvarid, &options_mask, &pixels_per_block);
           if (options_mask && pixels_per_block) ncvar->lszip = true;
 #endif
-          /*
-          size_t cache_size, nelems;
-          float preemption;
-          nc_get_chunk_cache(&cache_size, &nelems, &preemption);
-          printf("cache_size %lu nelems %lu preemption %g\n", cache_size, nelems, preemption);
-          nc_get_var_chunk_cache(ncid, ncvarid, &cache_size, &nelems, &preemption);
-          printf("varid %d cache_size %lu nelems %lu preemption %g\n", ncvarid, cache_size, nelems, preemption);
-          */
           size_t chunks[nvdims];
-          int storage_in;
-          if (nc_inq_var_chunking(ncid, ncvarid, &storage_in, chunks) == NC_NOERR)
+          int storageIn;
+          if (nc_inq_var_chunking(ncid, ncvarid, &storageIn, chunks) == NC_NOERR)
             {
-              if (storage_in == NC_CHUNKED)
+              if (storageIn == NC_CHUNKED)
                 {
                   ncvar->chunked = true;
                   for (int i = 0; i < nvdims; ++i) ncvar->chunks[i] = chunks[i];
                   if (CDI_Debug)
                     {
-                      fprintf(stderr, "%s: chunking %d %d %d  chunks ", name, storage_in, NC_CONTIGUOUS, NC_CHUNKED);
+                      fprintf(stderr, "%s: chunking %d %d %d  chunks ", name, storageIn, NC_CONTIGUOUS, NC_CHUNKED);
                       for (int i = 0; i < nvdims; ++i) fprintf(stderr, "%zu ", chunks[i]);
                       fprintf(stderr, "\n");
                     }
-                  {
-                    char *buf = ncvar->extra;
-                    size_t pos = strlen(buf);
-                    static const char prefix[] = "chunks=";
-                    memcpy(buf + pos, prefix, sizeof(prefix));
-                    pos += sizeof(prefix) - 1;
-                    for (int i = nvdims - 1; i >= 0; --i)
-                      {
-                        pos += (size_t) (sprintf(buf + pos, "%zu%s", chunks[i], i > 0 ? "x" : ""));
-                      }
-                    buf[pos] = ' ';
-                    buf[pos + 1] = 0;
-                  }
+
+                  set_extra_attr(ncvar->extra, nvdims, chunks);
                 }
             }
+
+          size_t size;
+          size_t nelems;
+          float preemption;
+          if (nc_get_var_chunk_cache(ncid, ncvarid, &size, &nelems, &preemption) == NC_NOERR)
+            {
+              ncvar->chunkCacheSize = size;
+              ncvar->chunkCacheNelems = nelems;
+              ncvar->chunkCachePreemption = preemption;
+              if (CDI_Debug)
+                fprintf(stderr, "%s: chunkCacheSize=%zu nelems=%zu preemption=%g\n", name, size, nelems, preemption);
+            }
         }
 #endif
 
@@ -1233,6 +1255,7 @@ cdfScanVarAttr(int nvars, ncvar_t *ncvars, int ndims, ncdim_t *ncdims, int timed
             }
           else if (isText && strIsEqual(attname, "units"))
             {
+              ncvar->unitsLen = attstringsize;
               memcpy(ncvar->units, attstring, attstringsize);
             }
           else if (isText && strIsEqual(attname, "calendar"))
@@ -1700,7 +1723,6 @@ cdf_set_dimtype(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
           int allcdims = lcdim;
 
           if (!lxdim && ncvar->xvarid != CDI_UNDEFID && ncvars[ncvar->xvarid].ndims == 0) lxdim = true;
-
           if (!lydim && ncvar->yvarid != CDI_UNDEFID && ncvars[ncvar->yvarid].ndims == 0) lydim = true;
 
           if (lxdim && (lydim || ncvar->gridtype == GRID_UNSTRUCTURED))
@@ -2036,7 +2058,9 @@ grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
 
       if (grid->type == GRID_UNSTRUCTURED)
         {
-          ncvar->chunkType = ncvar->chunks[ndims - 1] == grid->size ? CDI_CHUNK_GRID : CDI_CHUNK_AUTO;
+          size_t chunkSize = ncvar->chunks[ndims - 1];
+          ncvar->chunkType = (chunkSize == grid->size) ? CDI_CHUNK_GRID : CDI_CHUNK_AUTO;
+          if (ncvar->chunkType == CDI_CHUNK_AUTO && ncvar->chunks[ndims - 1] > 1) ncvar->chunkSize = chunkSize;
         }
       else
         {
@@ -2224,7 +2248,7 @@ cdf_check_gridtype(int *gridtype, bool isLon, bool isLat, size_t xsize, size_t y
 {
   if (isLat && (isLon || xsize == 0))
     {
-      double yinc = 0;
+      double yinc = 0.0;
       if (isLon && ysize > 1)
         {
           yinc = fabs(grid->y.vals[0] - grid->y.vals[1]);
@@ -2241,14 +2265,14 @@ cdf_check_gridtype(int *gridtype, bool isLon, bool isLat, size_t xsize, size_t y
           grid->np = (int) (ysize / 2);
         }
       else
-        *gridtype = GRID_LONLAT;
+        {
+          *gridtype = GRID_LONLAT;
+        }
     }
-  else if (isLon && !isLat && ysize == 0)
+  else
     {
-      *gridtype = GRID_LONLAT;
+      *gridtype = (isLon && !isLat && ysize == 0) ? GRID_LONLAT : GRID_GENERIC;
     }
-  else
-    *gridtype = GRID_GENERIC;
 }
 
 static bool
@@ -2580,7 +2604,7 @@ cdf_read_coordinates(stream_t *streamptr, struct cdfLazyGrid *lazyGrid, ncvar_t
                         if (lwarn) Warning("x-bounds doesn't follow the CF-Convention, skipped!");
                         lwarn = false;
                       }
-                   }
+                  }
               }
           }
         if (yvarid != CDI_UNDEFID && CDI_Read_Cell_Corners)
@@ -2622,7 +2646,7 @@ cdf_read_coordinates(stream_t *streamptr, struct cdfLazyGrid *lazyGrid, ncvar_t
                         if (lwarn) Warning("y-bounds doesn't follow the CF-Convention, skipped!");
                         lwarn = false;
                       }
-                   }
+                  }
               }
           }
 
@@ -2861,6 +2885,7 @@ cdf_set_grid_to_similar_vars(ncvar_t *ncvar1, ncvar_t *ncvar2, int gridtype, int
               ncvar2->gridID = ncvar1->gridID;
               ncvar2->chunkType = ncvar1->chunkType;
               ncvar2->chunkSize = ncvar1->chunkSize;
+              ncvar2->gridSize = ncvar1->gridSize;
             }
         }
     }
@@ -2875,17 +2900,17 @@ cdf_define_all_grids(stream_t *streamptr, ncgrid_t *ncgrid, int vlistID, ncdim_t
       ncvar_t *ncvar = &ncvars[ncvarid];
       if (ncvar->varStatus == DataVar && ncvar->gridID == CDI_UNDEFID)
         {
-          int ndims = ncvar->ndims;
+          const int ndims = ncvar->ndims;
           int *dimtype = ncvar->dimtype;
           int vdimid = CDI_UNDEFID;
           struct addIfNewRes projAdded = { .Id = CDI_UNDEFID, .isNew = 0 }, gridAdded = { .Id = CDI_UNDEFID, .isNew = 0 };
           int xdimid = CDI_UNDEFID, ydimid = CDI_UNDEFID;
-          int nydims = cdf_get_xydimid(ndims, ncvar->dimids, dimtype, &xdimid, &ydimid);
+          const int nydims = cdf_get_xydimid(ndims, ncvar->dimids, dimtype, &xdimid, &ydimid);
 
           int xaxisid = (xdimid != CDI_UNDEFID) ? ncdims[xdimid].ncvarid : CDI_UNDEFID;
           int yaxisid = (ydimid != CDI_UNDEFID) ? ncdims[ydimid].ncvarid : CDI_UNDEFID;
-          int xvarid = (ncvar->xvarid != CDI_UNDEFID) ? ncvar->xvarid : xaxisid;
-          int yvarid = (ncvar->yvarid != CDI_UNDEFID) ? ncvar->yvarid : yaxisid;
+          const int xvarid = (ncvar->xvarid != CDI_UNDEFID) ? ncvar->xvarid : xaxisid;
+          const int yvarid = (ncvar->yvarid != CDI_UNDEFID) ? ncvar->yvarid : yaxisid;
 
           size_t xsize = (xdimid != CDI_UNDEFID) ? ncdims[xdimid].len : 0;
           size_t ysize = (ydimid != CDI_UNDEFID) ? ncdims[ydimid].len : 0;
@@ -2973,6 +2998,7 @@ cdf_define_all_grids(stream_t *streamptr, ncgrid_t *ncgrid, int vlistID, ncdim_t
 
           gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 1);
           ncvar->gridID = gridAdded.Id;
+          ncvar->gridSize = grid->size;
 
           const int gridID = ncvar->gridID;
 
@@ -3196,6 +3222,7 @@ cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvar
               return CDI_EDIMSIZE;
             }
 
+          ncvar->numLevels = zsize;
           ncvar->zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, (const char **) zcvals, zclength, with_bounds,
                                        lbounds, ubounds, (int) vctsize, vct, pname, plongname, punits, zdatatype, 1, 0, -1);
 
@@ -3393,10 +3420,60 @@ cdf_define_institut_and_model_id(int vlistID, int varID)
   if (varTableID != CDI_UNDEFID) vlistDefVarTable(vlistID, varID, varTableID);
 }
 
+static int
+cdf_xtype_to_numbytes(int xtype)
+{
+  int numBytes = 8;
+
+  // clang-format off
+  if      (xtype == NC_BYTE  )  numBytes = 1;
+  else if (xtype == NC_CHAR  )  numBytes = 1;
+  else if (xtype == NC_SHORT )  numBytes = 2;
+  else if (xtype == NC_INT   )  numBytes = 4;
+  else if (xtype == NC_FLOAT )  numBytes = 4;
+#ifdef HAVE_NETCDF4
+  else if (xtype == NC_UBYTE )  numBytes = 1;
+  else if (xtype == NC_LONG  )  numBytes = 4;
+  else if (xtype == NC_USHORT)  numBytes = 2;
+  else if (xtype == NC_UINT  )  numBytes = 4;
+#endif
+  // clang-format on
+
+  return numBytes;
+}
+
+static size_t
+calc_chunk_cache_size(int timedimid, ncvar_t *ncvar)
+{
+  size_t chunkCacheSize = ncvar->gridSize;
+
+  chunkCacheSize *= (ncvar->dimids[0] == timedimid) ? ncvar->chunks[0] : 1;
+
+  int zdimid = CDI_UNDEFID;
+  for (int i = 0; i < ncvar->ndims; i++)
+    {
+      if (ncvar->dimtype[i] == Z_AXIS) zdimid = ncvar->dimids[i];
+    }
+  if (zdimid != CDI_UNDEFID) chunkCacheSize *= ncvar->chunks[zdimid];
+
+  chunkCacheSize *= cdf_xtype_to_numbytes(ncvar->xtype);
+
+  if (CDI_Chunk_Cache_Max > 0 && chunkCacheSize > CDI_Chunk_Cache_Max) chunkCacheSize = CDI_Chunk_Cache_Max;
+
+  return chunkCacheSize;
+}
+
+static void
+cdf_set_var_chunk_cache(ncvar_t *ncvar, int ncvarid, size_t chunckCacheSize)
+{
+  if (CDI_Debug) Message("%s: chunckCacheSize=%zu", ncvar->name, chunckCacheSize);
+  nc_set_var_chunk_cache(ncvar->ncid, ncvarid, chunckCacheSize, ncvar->chunkCacheNelems, ncvar->chunkCachePreemption);
+}
+
 // define all input data variables
 static void
 cdf_define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID, int nvars, int num_ncvars, ncvar_t *ncvars,
-                    ncdim_t *ncdims)
+                    ncdim_t *ncdims, int timedimid)
 {
   int *varids = (int *) Malloc((size_t) nvars * sizeof(int));
   int n = 0;
@@ -3421,7 +3498,17 @@ cdf_define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID, i
 #ifdef HAVE_NETCDF4
       if (ncvar->ldeflate) vlistDefVarCompType(vlistID, varID, CDI_COMPRESS_ZIP);
       if (ncvar->lszip) vlistDefVarCompType(vlistID, varID, CDI_COMPRESS_SZIP);
-      if (ncvar->chunked && ncvar->chunkType != CDI_UNDEFID) cdiDefKeyInt(vlistID, varID, CDI_KEY_CHUNKTYPE, ncvar->chunkType);
+      if (ncvar->chunked)
+        {
+          if (ncvar->chunkType != CDI_UNDEFID) cdiDefKeyInt(vlistID, varID, CDI_KEY_CHUNKTYPE, ncvar->chunkType);
+          if (ncvar->chunkSize > 1) cdiDefKeyInt(vlistID, varID, CDI_KEY_CHUNKSIZE, ncvar->chunkSize);
+
+          const size_t varChunkCacheSize = calc_chunk_cache_size(timedimid, ncvar);
+          if (CDI_Chunk_Cache > 0)
+            cdf_set_var_chunk_cache(ncvar, ncvarid, CDI_Chunk_Cache);
+          else if (varChunkCacheSize > ncvar->chunkCacheSize)
+            cdf_set_var_chunk_cache(ncvar, ncvarid, varChunkCacheSize);
+        }
 #endif
 
       streamptr->vars[varID1].defmiss = false;
@@ -3433,12 +3520,12 @@ cdf_define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID, i
       if (ncvar->code != CDI_UNDEFID) vlistDefVarParam(vlistID, varID, cdiEncodeParam(ncvar->code, ncvar->tabnum, 255));
       if (ncvar->longname[0]) cdiDefKeyString(vlistID, varID, CDI_KEY_LONGNAME, ncvar->longname);
       if (ncvar->stdname[0]) cdiDefKeyString(vlistID, varID, CDI_KEY_STDNAME, ncvar->stdname);
-      if (ncvar->units[0]) cdiDefKeyString(vlistID, varID, CDI_KEY_UNITS, ncvar->units);
+      if (ncvar->unitsLen > 0) cdiDefKeyString(vlistID, varID, CDI_KEY_UNITS, ncvar->units);
 
       if (ncvar->lvalidrange) vlistDefVarValidrange(vlistID, varID, ncvar->validrange);
 
-      if (IS_NOT_EQUAL(ncvar->addoffset, 0)) vlistDefVarAddoffset(vlistID, varID, ncvar->addoffset);
-      if (IS_NOT_EQUAL(ncvar->scalefactor, 1)) vlistDefVarScalefactor(vlistID, varID, ncvar->scalefactor);
+      if (IS_NOT_EQUAL(ncvar->addoffset, 0.0)) cdiDefKeyFloat(vlistID, varID, CDI_KEY_ADDOFFSET, ncvar->addoffset);
+      if (IS_NOT_EQUAL(ncvar->scalefactor, 1.0)) cdiDefKeyFloat(vlistID, varID, CDI_KEY_SCALEFACTOR, ncvar->scalefactor);
 
       vlistDefVarDatatype(vlistID, varID, cdfInqDatatype(streamptr, ncvar->xtype, ncvar->lunsigned));
 
@@ -3505,7 +3592,7 @@ cdf_define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID, i
           cdiDefKeyInt(vlistID, varID, CDI_KEY_PERTURBATIONNUMBER, ncvar->perturbationNumber);
         }
 
-      if (ncvar->extra[0] != 0) vlistDefVarExtra(vlistID, varID, ncvar->extra);
+      if (ncvar->extra[0] != 0) cdiDefKeyString(vlistID, varID, CDI_KEY_CHUNKS, ncvar->extra);
     }
 
   for (int varID = 0; varID < nvars; varID++)
@@ -3769,7 +3856,7 @@ find_time_vars(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimid, strea
 
   if (timedimid == CDI_UNDEFID)
     {
-      char timeunits[CDI_MAX_NAME];
+      char timeUnitsStr[CDI_MAX_NAME];
 
       for (ncvarid = 0; ncvarid < nvars; ncvarid++)
         {
@@ -3778,10 +3865,10 @@ find_time_vars(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimid, strea
             {
               if (ncvar->units[0])
                 {
-                  strcpy(timeunits, ncvar->units);
-                  strToLower(timeunits);
+                  strcpy(timeUnitsStr, ncvar->units);
+                  strToLower(timeUnitsStr);
 
-                  if (is_time_units(timeunits))
+                  if (is_time_units(timeUnitsStr))
                     {
                       streamptr->basetime.ncvarid = ncvarid;
                       break;
@@ -4068,7 +4155,6 @@ cdfVerifyVars(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
 int
 cdfInqContents(stream_t *streamptr)
 {
-  int ndims, nvars, ngatts, unlimdimid;
   bool time_has_units = false;
   bool time_has_bounds = false;
   bool time_climatology = false;
@@ -4092,6 +4178,7 @@ cdfInqContents(stream_t *streamptr)
   nc_inq_format(fileID, &format);
 #endif
 
+  int ndims, nvars, ngatts, unlimdimid;
   cdf_inq(fileID, &ndims, &nvars, &ngatts, &unlimdimid);
 
   if (CDI_Debug) Message("root: ndims %d, nvars %d, ngatts %d", ndims, nvars, ngatts);
@@ -4353,7 +4440,7 @@ cdfInqContents(stream_t *streamptr)
   streamptr->ntsteps = (long) ntsteps;
 
   // define all data variables
-  cdf_define_all_vars(streamptr, vlistID, instID, modelID, nvars_data, nvars, ncvars, ncdims);
+  cdf_define_all_vars(streamptr, vlistID, instID, modelID, nvars_data, nvars, ncvars, ncdims, timedimid);
 
   cdiCreateTimesteps(streamptr);
 
@@ -4367,7 +4454,7 @@ cdfInqContents(stream_t *streamptr)
     {
       taxis_t *taxis = &streamptr->tsteps[0].taxis;
 
-      if (setBaseTime(ncvars[nctimevarid].units, taxis) == 1)
+      if (set_base_time(ncvars[nctimevarid].units, taxis) == 1)
         {
           nctimevarid = CDI_UNDEFID;
           streamptr->basetime.ncvarid = CDI_UNDEFID;
@@ -4384,7 +4471,7 @@ cdfInqContents(stream_t *streamptr)
           if (timeunit == -1) timeunit = taxis->unit;
           taxis->fc_unit = timeunit;
 
-          setForecastTime(fcreftime, taxis);
+          set_forecast_time(fcreftime, taxis);
         }
     }
 
@@ -4561,21 +4648,14 @@ cdfInqTimestep(stream_t *streamptr, int tsID)
           const int nctimeboundsid = streamptr->basetime.ncvarboundsid;
           if (nctimeboundsid != CDI_UNDEFID)
             {
-              {
-                const size_t start[2] = { tsID, 1 }, count[2] = { 0, 1 };
-                cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
-                if (timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE) timevalue = 0.0;
-
-                taxis->vdatetime_lb = cdi_decode_timeval(timevalue, taxis);
-              }
+              double values[2];
+              const size_t start[2] = { tsID, 0 }, count[2] = { 1, 2 };
+              cdf_get_vara_double(fileID, nctimeboundsid, start, count, values);
+              if (values[0] >= NC_FILL_DOUBLE || values[0] < -NC_FILL_DOUBLE) values[0] = 0.0;
+              if (values[1] >= NC_FILL_DOUBLE || values[1] < -NC_FILL_DOUBLE) values[1] = 0.0;
 
-              {
-                const size_t start[2] = { tsID, 1 }, count[2] = { 1, 1 };
-                cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
-                if (timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE) timevalue = 0.0;
-
-                taxis->vdatetime_ub = cdi_decode_timeval(timevalue, taxis);
-              }
+              taxis->vdatetime_lb = cdi_decode_timeval(values[0], taxis);
+              taxis->vdatetime_ub = cdi_decode_timeval(values[1], taxis);
             }
 
           const int leadtimeid = streamptr->basetime.leadtimeid;
diff --git a/src/stream_cdf_o.c b/src/stream_cdf_o.c
index 0ffe3cad07ff2039df8bdf1034b1a7530f109460..18c7cdb3820d9819d475238171d749aac60ac98c 100644
--- a/src/stream_cdf_o.c
+++ b/src/stream_cdf_o.c
@@ -62,45 +62,45 @@ cdfDefTimestep(stream_t *streamptr, int tsID)
       cdfEndDef(streamptr);
     }
 
-  double timevalue = cdi_encode_timeval(taxis->vdatetime, &streamptr->tsteps[0].taxis);
-  if (CDI_Debug) Message("tsID = %d  timevalue = %f", tsID, timevalue);
+  double timeValue = cdi_encode_timeval(taxis->vdatetime, &streamptr->tsteps[0].taxis);
+  if (CDI_Debug) Message("tsID = %d  timeValue = %f", tsID, timeValue);
 
   int ncvarid = streamptr->basetime.ncvarid;
   size_t index = (size_t) tsID;
-  cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
+  cdf_put_var1_double(fileID, ncvarid, &index, &timeValue);
 
   if (taxis->has_bounds)
     {
       ncvarid = streamptr->basetime.ncvarboundsid;
       if (ncvarid == CDI_UNDEFID) Error("Call to taxisWithBounds() missing!");
 
-      timevalue = cdi_encode_timeval(taxis->vdatetime_lb, &streamptr->tsteps[0].taxis);
+      timeValue = cdi_encode_timeval(taxis->vdatetime_lb, &streamptr->tsteps[0].taxis);
       size_t start[2] = { tsID, 0 }, count[2] = { 1, 1 };
-      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
+      cdf_put_vara_double(fileID, ncvarid, start, count, &timeValue);
 
-      timevalue = cdi_encode_timeval(taxis->vdatetime_ub, &streamptr->tsteps[0].taxis);
+      timeValue = cdi_encode_timeval(taxis->vdatetime_ub, &streamptr->tsteps[0].taxis);
       start[0] = (size_t) tsID;
       count[0] = 1;
       start[1] = 1;
       count[1] = 1;
-      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
+      cdf_put_vara_double(fileID, ncvarid, start, count, &timeValue);
     }
 
   ncvarid = streamptr->basetime.leadtimeid;
   if (taxis->type == TAXIS_FORECAST && ncvarid != CDI_UNDEFID)
     {
-      timevalue = taxis->fc_period;
-      cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
+      timeValue = taxis->fc_period;
+      cdf_put_var1_double(fileID, ncvarid, &index, &timeValue);
     }
 }
 
 static void
-cdfDefComplex(stream_t *streamptr, int gridID, int gridindex)
+cdfDefComplex(stream_t *streamptr, int gridID, int gridIndex)
 {
   int dimID;
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
-  for (int index = 0; index < gridindex; ++index)
+  for (int index = 0; index < gridIndex; ++index)
     {
       if (ncgrid[index].ncIDs[CDF_DIMID_X] != CDI_UNDEFID)
         {
@@ -124,9 +124,10 @@ cdfDefComplex(stream_t *streamptr, int gridID, int gridindex)
     cdf_enddef(fileID);
     streamptr->ncmode = 2;
   }
+
 dimIDEstablished:
-  ncgrid[gridindex].gridID = gridID;
-  ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
+  ncgrid[gridIndex].gridID = gridID;
+  ncgrid[gridIndex].ncIDs[CDF_DIMID_X] = dimID;
 }
 
 struct idSearch
@@ -169,14 +170,14 @@ cdfGridInqHalfSize(int gridID)
 }
 
 static void
-cdfDefSPorFC(stream_t *streamptr, int gridID, int gridindex, char *restrict axisname, int gridRefType)
+cdfDefSPorFC(stream_t *streamptr, int gridID, int gridIndex, char *restrict axisname, int gridRefType)
 {
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
   const size_t dimlen = gridInqSize(gridID) / 2;
 
   struct idSearch search
-      = cdfSearchIDBySize(0, (size_t) gridindex, ncgrid, CDF_DIMID_Y, gridRefType, (int) dimlen, gridInqType, cdfGridInqHalfSize);
+      = cdfSearchIDBySize(0, (size_t) gridIndex, ncgrid, CDF_DIMID_Y, gridRefType, (int) dimlen, gridInqType, cdfGridInqHalfSize);
   int dimID = search.foundID;
   const int iz = search.numNonMatching;
 
@@ -196,23 +197,23 @@ cdfDefSPorFC(stream_t *streamptr, int gridID, int gridindex, char *restrict axis
       streamptr->ncmode = 2;
     }
 
-  ncgrid[gridindex].gridID = gridID;
-  ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = dimID;
+  ncgrid[gridIndex].gridID = gridID;
+  ncgrid[gridIndex].ncIDs[CDF_DIMID_Y] = dimID;
 }
 
 static void
-cdfDefSP(stream_t *streamptr, int gridID, int gridindex)
+cdfDefSP(stream_t *streamptr, int gridID, int gridIndex)
 {
   // char longname[] = "Spherical harmonic coefficient";
   char axisname[5] = "nspX";
-  cdfDefSPorFC(streamptr, gridID, gridindex, axisname, GRID_SPECTRAL);
+  cdfDefSPorFC(streamptr, gridID, gridIndex, axisname, GRID_SPECTRAL);
 }
 
 static void
-cdfDefFC(stream_t *streamptr, int gridID, int gridindex)
+cdfDefFC(stream_t *streamptr, int gridID, int gridIndex)
 {
   char axisname[5] = "nfcX";
-  cdfDefSPorFC(streamptr, gridID, gridindex, axisname, GRID_FOURIER);
+  cdfDefSPorFC(streamptr, gridID, gridIndex, axisname, GRID_FOURIER);
 }
 
 static const struct cdfDefGridAxisInqs
@@ -273,7 +274,7 @@ grid_inq_xtype(int gridID)
 }
 
 static void
-cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridindex, const struct cdfDefGridAxisInqs *inqs)
+cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridIndex, const struct cdfDefGridAxisInqs *inqs)
 {
   const nc_type xtype = grid_inq_xtype(gridID);
   ncgrid_t *ncgrid = streamptr->ncgrid;
@@ -281,7 +282,7 @@ cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridindex, const struct cd
   const size_t dimlen = inqs->axisSize(gridID);
   if (dimlen != 1) Error("%c size isn't 1 for %s grid!", inqs->axisSym, gridNamePtr(gridInqType(gridID)));
 
-  int ncvarid = ncgrid[gridindex].ncIDs[inqs->dimIdx];
+  int ncvarid = ncgrid[gridIndex].ncIDs[inqs->dimIdx];
   if (ncvarid == CDI_UNDEFID)
     {
       int dimNcID = streamptr->basetime.ncvarid;
@@ -298,21 +299,21 @@ cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridindex, const struct cd
       streamptr->ncmode = 2;
     }
 
-  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridIndex].gridID = gridID;
   // var ID for trajectory !!!
-  ncgrid[gridindex].ncIDs[inqs->dimIdx] = ncvarid;
+  ncgrid[gridIndex].ncIDs[inqs->dimIdx] = ncvarid;
 }
 
 static void
-cdfDefTrajLon(stream_t *streamptr, int gridID, int gridindex)
+cdfDefTrajLon(stream_t *streamptr, int gridID, int gridIndex)
 {
-  cdfDefTrajLatLon(streamptr, gridID, gridindex, &gridInqsX);
+  cdfDefTrajLatLon(streamptr, gridID, gridIndex, &gridInqsX);
 }
 
 static void
-cdfDefTrajLat(stream_t *streamptr, int gridID, int gridindex)
+cdfDefTrajLat(stream_t *streamptr, int gridID, int gridIndex)
 {
-  cdfDefTrajLatLon(streamptr, gridID, gridindex, &gridInqsY);
+  cdfDefTrajLatLon(streamptr, gridID, gridIndex, &gridInqsY);
 }
 
 static int
@@ -418,7 +419,19 @@ checkZaxisName(char *axisname, int fileID, int vlistID, int zaxisID, int nzaxis)
 }
 
 static void
-cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims, bool addVarToGrid,
+cdfGridCompress(int fileID, int ncvarid, size_t gridsize, int filetype, int comptype, size_t *chunks)
+{
+#ifdef HAVE_NETCDF4
+  if (gridsize >= 32 && comptype == CDI_COMPRESS_ZIP && (filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C || filetype == CDI_FILETYPE_NCZARR))
+    {
+      cdf_def_var_chunking(fileID, ncvarid, NC_CHUNKED, chunks);
+      cdfDefVarDeflate(fileID, ncvarid, 1);
+    }
+#endif
+}
+
+static void
+cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridIndex, int ndims, bool addVarToGrid,
                  const struct cdfDefGridAxisInqs *gridAxisInq, int axisKey, char axisLetter,
                  void (*finishCyclicBounds)(double *pbounds, size_t dimlen, const double *pvals))
 {
@@ -435,7 +448,7 @@ cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims, bool
   int length = sizeof(dimname);
   if (ndims && pvals == NULL) cdiInqKeyString(gridID, axisKey, CDI_KEY_DIMNAME, dimname, &length);
 
-  for (int index = 0; index < gridindex; ++index)
+  for (int index = 0; index < gridIndex; ++index)
     {
       const int gridID0 = ncgrid[index].gridID;
       assert(gridID0 != CDI_UNDEFID);
@@ -454,7 +467,7 @@ cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims, bool
               if (IS_EQUAL(inqVal(gridID0, 0), inqVal(gridID, 0))
                   && IS_EQUAL(inqVal(gridID0, dimlen - 1), inqVal(gridID, dimlen - 1)))
                 {
-                  dimID = ncgrid[index].ncIDs[axisLetter == 'X' ? CDF_DIMID_X : CDF_DIMID_Y];
+                  dimID = ncgrid[index].ncIDs[(axisLetter == 'X') ? CDF_DIMID_X : CDF_DIMID_Y];
                   break;
                 }
             }
@@ -489,6 +502,17 @@ cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims, bool
         {
           cdf_def_var(fileID, axisname, xtype, ndims, &dimID, &ncvarid);
 
+          int chunkSize = 0;
+          int chunkType = CDI_CHUNK_GRID;
+          cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_CHUNKTYPE, &chunkType);
+          cdiInqKeyInt(gridID, CDI_GLOBAL, CDI_KEY_CHUNKSIZE, &chunkSize);
+          if (chunkSize > 0) chunkType = CDI_CHUNK_AUTO;
+
+          if (chunkType == CDI_CHUNK_GRID && dimlen > ChunkSizeLim) chunkType = CDI_CHUNK_LINES;
+
+          size_t chunk = calc_chunksize_x(chunkType, chunkSize, dimlen, true);
+          cdfGridCompress(fileID, ncvarid, dimlen, streamptr->filetype, streamptr->comptype, &chunk);
+
           cdfPutGridStdAtts(fileID, ncvarid, gridID, axisLetter);
           {
             char axisStr[2] = { axisLetter, '\0' };
@@ -535,11 +559,11 @@ cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims, bool
       if (ncbvarid != CDI_UNDEFID) cdf_put_var_double(fileID, ncbvarid, pbounds);
       if (gen_bounds) Free(pbounds);
 
-      if (ndims == 0 || addVarToGrid) ncgrid[gridindex].ncIDs[axisLetter == 'X' ? CDF_VARID_X : CDF_VARID_Y] = ncvarid;
+      if (ndims == 0 || addVarToGrid) ncgrid[gridIndex].ncIDs[(axisLetter == 'X') ? CDF_VARID_X : CDF_VARID_Y] = ncvarid;
     }
 
-  ncgrid[gridindex].gridID = gridID;
-  ncgrid[gridindex].ncIDs[axisLetter == 'X' ? CDF_DIMID_X : CDF_DIMID_Y] = dimID;
+  ncgrid[gridIndex].gridID = gridID;
+  ncgrid[gridIndex].ncIDs[(axisLetter == 'X') ? CDF_DIMID_X : CDF_DIMID_Y] = dimID;
 }
 
 static void
@@ -557,27 +581,15 @@ finishCyclicYBounds(double *pbounds, size_t dimlen, const double *pvals)
 }
 
 static void
-cdfDefXaxis(stream_t *streamptr, int gridID, int gridindex, int ndims, bool addVarToGrid)
+cdfDefXaxis(stream_t *streamptr, int gridID, int gridIndex, int ndims, bool addVarToGrid)
 {
-  cdfDefAxisCommon(streamptr, gridID, gridindex, ndims, addVarToGrid, &gridInqsX, CDI_XAXIS, 'X', finishCyclicXBounds);
+  cdfDefAxisCommon(streamptr, gridID, gridIndex, ndims, addVarToGrid, &gridInqsX, CDI_XAXIS, 'X', finishCyclicXBounds);
 }
 
 static void
-cdfDefYaxis(stream_t *streamptr, int gridID, int gridindex, int ndims, bool addVarToGrid)
-{
-  cdfDefAxisCommon(streamptr, gridID, gridindex, ndims, addVarToGrid, &gridInqsY, CDI_YAXIS, 'Y', finishCyclicYBounds);
-}
-
-static void
-cdfGridCompress(int fileID, int ncvarid, size_t gridsize, int filetype, int comptype, size_t *chunks)
+cdfDefYaxis(stream_t *streamptr, int gridID, int gridIndex, int ndims, bool addVarToGrid)
 {
-#ifdef HAVE_NETCDF4
-  if (gridsize > 1 && comptype == CDI_COMPRESS_ZIP && (filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C))
-    {
-      cdf_def_var_chunking(fileID, ncvarid, NC_CHUNKED, chunks);
-      cdfDefVarDeflate(fileID, ncvarid, 1);
-    }
-#endif
+  cdfDefAxisCommon(streamptr, gridID, gridIndex, ndims, addVarToGrid, &gridInqsY, CDI_YAXIS, 'Y', finishCyclicYBounds);
 }
 
 static void
@@ -687,7 +699,7 @@ cdfDefIrregularGridCommon(stream_t *streamptr, int gridID, size_t xsize, size_t
       dimIDs[0] = ydimID;
       dimIDs[1] = xdimID;
     }
-  else /* ndims == 2 */
+  else // ndims == 2
     {
       chunks[0] = calc_chunksize_x(chunkType, chunkSize, xsize, (ydimID == CDI_UNDEFID));
       dimIDs[0] = xdimID;
@@ -708,7 +720,7 @@ cdfDefIrregularGridCommon(stream_t *streamptr, int gridID, size_t xsize, size_t
       cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X');
 
       // attribute for Panoply
-      if (ndims == 3) cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon");
+      if (!CDI_CMOR_Mode && ndims == 3) cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon");
 
       if ((xboundsPtr = gridInqXboundsPtr(gridID)) && nvdimID != CDI_UNDEFID)
         {
@@ -735,7 +747,7 @@ cdfDefIrregularGridCommon(stream_t *streamptr, int gridID, size_t xsize, size_t
       cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y');
 
       // attribute for Panoply
-      if (ndims == 3) cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat");
+      if (!CDI_CMOR_Mode && ndims == 3) cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat");
 
       if ((yboundsPtr = gridInqYboundsPtr(gridID)) && nvdimID != CDI_UNDEFID)
         {
@@ -779,7 +791,7 @@ cdfDefIrregularGridCommon(stream_t *streamptr, int gridID, size_t xsize, size_t
 }
 
 static void
-cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex)
+cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridIndex)
 {
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
@@ -793,7 +805,7 @@ cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex)
   size_t ofs = 0;
   do
     {
-      struct idSearch search = cdfSearchIDBySize(ofs, (size_t) gridindex, ncgrid, CDF_DIMID_X, GRID_CURVILINEAR, (int) dimlen,
+      struct idSearch search = cdfSearchIDBySize(ofs, (size_t) gridIndex, ncgrid, CDF_DIMID_X, GRID_CURVILINEAR, (int) dimlen,
                                                  gridInqType, gridInqSize);
       const size_t index = search.foundIdx;
       if (index != SIZE_MAX)
@@ -811,7 +823,7 @@ cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex)
               break;
             }
           ofs = search.foundIdx;
-          if (ofs < (size_t) gridindex) continue;
+          if (ofs < (size_t) gridIndex) continue;
         }
     }
   while (false);
@@ -827,16 +839,16 @@ cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex)
       ncavarid = createdIDs.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;
+  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;
 }
 
 static void
-cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex)
+cdfDefUnstructured(stream_t *streamptr, int gridID, int gridIndex)
 {
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
@@ -848,7 +860,7 @@ cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex)
   size_t ofs = 0;
   do
     {
-      struct idSearch search = cdfSearchIDBySize(ofs, (size_t) gridindex, ncgrid, CDF_DIMID_X, GRID_UNSTRUCTURED, (int) dimlen,
+      struct idSearch search = cdfSearchIDBySize(ofs, (size_t) gridIndex, ncgrid, CDF_DIMID_X, GRID_UNSTRUCTURED, (int) dimlen,
                                                  gridInqType, gridInqSize);
       const size_t index = search.foundIdx;
       if (index != SIZE_MAX)
@@ -866,7 +878,7 @@ cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex)
               break;
             }
           ofs = search.foundIdx;
-          if (ofs < (size_t) gridindex) continue;
+          if (ofs < (size_t) gridIndex) continue;
         }
     }
   while (false);
@@ -882,11 +894,11 @@ cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex)
       ncavarid = createdIDs.ncavarid;
     }
 
-  ncgrid[gridindex].gridID = gridID;
-  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;
+  ncgrid[gridIndex].gridID = gridID;
+  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
@@ -1224,9 +1236,9 @@ cdf_def_zaxis_hybrid_cf(stream_t *streamptr, int type, int *ncvaridp, int zaxisI
   size_t len = 0;
   char txt[CDI_MAX_NAME];
   if (p0status == 0)
-    len = (size_t) (sprintf(txt, "%s%s %s%s", "a: a b: b p0: ", p0name, "ps: ", psname));
+    len = (size_t) (snprintf(txt, sizeof(txt), "%s%s %s%s", "a: a b: b p0: ", p0name, "ps: ", psname));
   else
-    len = (size_t) (sprintf(txt, "%s%s", "ap: ap b: b ps: ", psname));
+    len = (size_t) (snprintf(txt, sizeof(txt), "%s%s", "ap: ap b: b ps: ", psname));
   cdf_put_att_text(fileID, ncvarid, "formula_terms", len, txt);
 
   int ncbvarid = CDI_UNDEFID;
@@ -1282,9 +1294,9 @@ cdf_def_zaxis_hybrid_cf(stream_t *streamptr, int type, int *ncvaridp, int zaxisI
         }
 
         if (p0status == 0)
-          len = (size_t) (sprintf(txt, "%s%s %s%s", "a: a_bnds b: b_bnds p0: ", p0name, "ps: ", psname));
+          len = (size_t) (snprintf(txt, sizeof(txt), "%s%s %s%s", "a: a_bnds b: b_bnds p0: ", p0name, "ps: ", psname));
         else
-          len = (size_t) (sprintf(txt, "%s%s", "ap: ap_bnds b: b_bnds ps: ", psname));
+          len = (size_t) (snprintf(txt, sizeof(txt), "%s%s", "ap: ap_bnds b: b_bnds ps: ", psname));
         cdf_put_att_text(fileID, ncbvarid, "formula_terms", len, txt);
       }
   }
@@ -1621,18 +1633,18 @@ cdf_def_mapping(stream_t *streamptr, int gridID)
 }
 
 static void
-cdfDefCharacter(stream_t *streamptr, int gridID, int gridindex, int cdiAxisID, int strlen)
+cdfDefCharacter(stream_t *streamptr, int gridID, int gridIndex, int cdiAxisID, int strlen)
 {
-  if (streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID) return;
+  if (streamptr->ncgrid[gridIndex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID) return;
 
   const bool isXaxis = (cdiAxisID == CDI_XAXIS);
 
   const size_t dimlen = isXaxis ? gridInqXsize(gridID) : gridInqYsize(gridID);
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
-  // Check for all grids up to gridindex whether it already is defined
+  // Check for all grids up to gridIndex whether it already is defined
 
-  for (int index = 0; index < gridindex; index++)
+  for (int index = 0; index < gridIndex; index++)
     {
       const int gridID0 = ncgrid[index].gridID;
       const int gridtype0 = gridInqType(gridID0);
@@ -1702,24 +1714,24 @@ cdfDefCharacter(stream_t *streamptr, int gridID, int gridindex, int cdiAxisID, i
       status = nc_put_vara_text(fileID, ncaxisid, start, count, cvals[i]);
     }
 
-  ncgrid[gridindex].gridID = gridID;
-  ncgrid[gridindex].ncIDs[isXaxis ? CDF_DIMID_X : CDF_DIMID_Y] = dimID;
-  ncgrid[gridindex].ncIDs[isXaxis ? CDF_VARID_X : CDF_VARID_Y] = ncaxisid;
+  ncgrid[gridIndex].gridID = gridID;
+  ncgrid[gridIndex].ncIDs[isXaxis ? CDF_DIMID_X : CDF_DIMID_Y] = dimID;
+  ncgrid[gridIndex].ncIDs[isXaxis ? CDF_VARID_X : CDF_VARID_Y] = ncaxisid;
 
   streamptr->ncmode = 2;
 }
 
 static void
-cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex)
+cdfDefRgrid(stream_t *streamptr, int gridID, int gridIndex)
 {
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
-  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridIndex].gridID = gridID;
 
   {
     const size_t dimlen = gridInqSize(gridID);
 
-    struct idSearch search = cdfSearchIDBySize(0, (size_t) gridindex, ncgrid, CDF_DIMID_X, GRID_GAUSSIAN_REDUCED, (int) dimlen,
+    struct idSearch search = cdfSearchIDBySize(0, (size_t) gridIndex, ncgrid, CDF_DIMID_X, GRID_GAUSSIAN_REDUCED, (int) dimlen,
                                                gridInqType, gridInqSize);
     const int iz = search.numNonMatching;
     int dimID = search.foundID;
@@ -1742,13 +1754,13 @@ cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex)
         streamptr->ncmode = 2;
       }
 
-    ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
+    ncgrid[gridIndex].ncIDs[CDF_DIMID_X] = dimID;
   }
 
   {
     const size_t dimlen = gridInqYsize(gridID);
 
-    struct idSearch search = cdfSearchIDBySize(0, (size_t) gridindex, ncgrid, CDF_DIMID_RP, GRID_GAUSSIAN_REDUCED, (int) dimlen,
+    struct idSearch search = cdfSearchIDBySize(0, (size_t) gridIndex, ncgrid, CDF_DIMID_RP, GRID_GAUSSIAN_REDUCED, (int) dimlen,
                                                gridInqType, gridInqSize);
     const int iz = search.numNonMatching;
     int dimID = search.foundID;
@@ -1761,7 +1773,7 @@ cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex)
         if (iz == 0)
           axisname[14] = '\0';
         else
-          sprintf(&axisname[5], "%1d", iz + 1);
+          sprintf(&axisname[14], "%1d", iz + 1);
 
         if (streamptr->ncmode == 2) cdf_redef(fileID);
 
@@ -1781,15 +1793,15 @@ cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex)
         cdf_put_var_int(fileID, ncvarid, reducedPoints);
         Free(reducedPoints);
 
-        ncgrid[gridindex].ncIDs[CDF_VARID_RP] = ncvarid;
+        ncgrid[gridIndex].ncIDs[CDF_VARID_RP] = ncvarid;
       }
 
-    ncgrid[gridindex].ncIDs[CDF_DIMID_RP] = dimID;
+    ncgrid[gridIndex].ncIDs[CDF_DIMID_RP] = dimID;
   }
 }
 
 static void
-cdfDefGdim(stream_t *streamptr, int gridID, int gridindex)
+cdfDefGdim(stream_t *streamptr, int gridID, int gridIndex)
 {
   ncgrid_t *ncgrid = streamptr->ncgrid;
   int dimID = CDI_UNDEFID;
@@ -1799,14 +1811,14 @@ cdfDefGdim(stream_t *streamptr, int gridID, int gridindex)
   if (gridInqYsize(gridID) == 0)
     {
       struct idSearch search
-          = cdfSearchIDBySize(0, (size_t) gridindex, ncgrid, CDF_DIMID_X, GRID_GENERIC, (int) dimlen, gridInqType, gridInqSize);
+          = cdfSearchIDBySize(0, (size_t) gridIndex, ncgrid, CDF_DIMID_X, GRID_GENERIC, (int) dimlen, gridInqType, gridInqSize);
       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);
+          = cdfSearchIDBySize(0, (size_t) gridIndex, ncgrid, CDF_DIMID_Y, GRID_GENERIC, (int) dimlen, gridInqType, gridInqSize);
       dimID = search.foundID;
     }
 
@@ -1826,14 +1838,14 @@ cdfDefGdim(stream_t *streamptr, int gridID, int gridindex)
       streamptr->ncmode = 2;
     }
 
-  ncgrid[gridindex].gridID = gridID;
-  ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
+  ncgrid[gridIndex].gridID = gridID;
+  ncgrid[gridIndex].ncIDs[CDF_DIMID_X] = dimID;
 }
 
 static void
-cdfDefGrid(stream_t *streamptr, int gridID, int gridindex)
+cdfDefGrid(stream_t *streamptr, int gridID, int gridIndex)
 {
-  if (streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID) return;
+  if (streamptr->ncgrid[gridIndex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID) return;
 
   const int gridtype = gridInqType(gridID);
   const size_t size = gridInqSize(gridID);
@@ -1842,87 +1854,79 @@ cdfDefGrid(stream_t *streamptr, int gridID, int gridindex)
 
   if (CDI_Reduce_Dim && size == 1)  // no grid information
     {
-      streamptr->ncgrid[gridindex].gridID = gridID;
+      streamptr->ncgrid[gridIndex].gridID = gridID;
       return;
     }
 
-  if (gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT || gridtype == GRID_PROJECTION || gridtype == GRID_GENERIC)
+  if (gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT || gridtype == GRID_PROJECTION)
     {
-      if (gridtype == GRID_GENERIC)
-        {
-          if (size == 1 && gridInqXsize(gridID) == 0 && gridInqYsize(gridID) == 0)
-            {
-              // no grid information
-              streamptr->ncgrid[gridindex].gridID = gridID;
-            }
-          else
-            {
-              bool lx = false, ly = false;
-              if (gridInqXsize(gridID) /*&& gridInqXvals(gridID, NULL) */)
-                {
-                  cdfDefXaxis(streamptr, gridID, gridindex, 1, false);
-                  lx = true;
-                }
+      const int ndims = !(gridtype == GRID_LONLAT && size == 1 && !gridInqHasDims(gridID));
+      const size_t xsize = gridInqXsize(gridID);
+      const size_t ysize = gridInqYsize(gridID);
 
-              if (gridInqYsize(gridID) /*&& gridInqYvals(gridID, NULL) */)
-                {
-                  cdfDefYaxis(streamptr, gridID, gridindex, 1, false);
-                  ly = true;
-                }
+      if (xsize) cdfDefXaxis(streamptr, gridID, gridIndex, ndims, false);
+      if (ysize) cdfDefYaxis(streamptr, gridID, gridIndex, ndims, false);
+      if (ndims == 1 && xsize == 0 && ysize == 0 && gridtype == GRID_PROJECTION) cdfDefGdim(streamptr, gridID, gridIndex);
 
-              if (!lx && !ly) cdfDefGdim(streamptr, gridID, gridindex);
-            }
+      cdf_def_mapping(streamptr, gridID);
+    }
+  else if (gridtype == GRID_GENERIC)
+    {
+      if (size == 1 && gridInqXsize(gridID) == 0 && gridInqYsize(gridID) == 0)
+        {
+          // no grid information
+          streamptr->ncgrid[gridIndex].gridID = gridID;
         }
       else
         {
-          const int ndims = !(gridtype == GRID_LONLAT && size == 1 && !gridInqHasDims(gridID));
-
-          if (gridInqXsize(gridID)) cdfDefXaxis(streamptr, gridID, gridindex, ndims, false);
-          if (gridInqYsize(gridID)) cdfDefYaxis(streamptr, gridID, gridindex, ndims, false);
+          const size_t xsize = gridInqXsize(gridID);
+          const size_t ysize = gridInqYsize(gridID);
 
-          cdf_def_mapping(streamptr, gridID);
+          if (xsize) cdfDefXaxis(streamptr, gridID, gridIndex, 1, false);
+          if (ysize) cdfDefYaxis(streamptr, gridID, gridIndex, 1, false);
+          if (xsize == 0 && ysize == 0) cdfDefGdim(streamptr, gridID, gridIndex);
         }
     }
   else if (gridtype == GRID_CURVILINEAR)
     {
-      cdfDefCurvilinear(streamptr, gridID, gridindex);
+      cdfDefCurvilinear(streamptr, gridID, gridIndex);
     }
   else if (gridtype == GRID_UNSTRUCTURED)
     {
-      cdfDefUnstructured(streamptr, gridID, gridindex);
+      cdfDefUnstructured(streamptr, gridID, gridIndex);
     }
   else if (gridtype == GRID_GAUSSIAN_REDUCED)
     {
-      cdfDefRgrid(streamptr, gridID, gridindex);
-      if (gridInqYsize(gridID)) cdfDefYaxis(streamptr, gridID, gridindex, 1, true);
+      cdfDefRgrid(streamptr, gridID, gridIndex);
+      if (gridInqYsize(gridID)) cdfDefYaxis(streamptr, gridID, gridIndex, 1, true);
     }
   else if (gridtype == GRID_SPECTRAL)
     {
-      cdfDefComplex(streamptr, gridID, gridindex);
-      cdfDefSP(streamptr, gridID, gridindex);
+      cdfDefComplex(streamptr, gridID, gridIndex);
+      cdfDefSP(streamptr, gridID, gridIndex);
     }
   else if (gridtype == GRID_FOURIER)
     {
-      cdfDefComplex(streamptr, gridID, gridindex);
-      cdfDefFC(streamptr, gridID, gridindex);
+      cdfDefComplex(streamptr, gridID, gridIndex);
+      cdfDefFC(streamptr, gridID, gridIndex);
     }
   else if (gridtype == GRID_TRAJECTORY)
     {
-      cdfDefTrajLon(streamptr, gridID, gridindex);
-      cdfDefTrajLat(streamptr, gridID, 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, CDI_XAXIS, strlen);
+        cdfDefCharacter(streamptr, gridID, gridIndex, CDI_XAXIS, strlen);
       else if (gridInqXsize(gridID))
-        cdfDefXaxis(streamptr, gridID, gridindex, 1, false);
+        cdfDefXaxis(streamptr, gridID, gridIndex, 1, false);
 
       if ((strlen = gridInqYIsc(gridID)))
-        cdfDefCharacter(streamptr, gridID, gridindex, CDI_YAXIS, strlen);
+        cdfDefCharacter(streamptr, gridID, gridIndex, CDI_YAXIS, strlen);
       else if (gridInqYsize(gridID))
-        cdfDefYaxis(streamptr, gridID, gridindex, 1, false);
+        cdfDefYaxis(streamptr, gridID, gridIndex, 1, false);
     }
   else
     {
diff --git a/src/stream_cdf_time.c b/src/stream_cdf_time.c
index e3c6e6927472f6e93f877d471654583515ca9b8d..c7828d8f70b77d164febbec7bc06e8dc2ff7abdf 100644
--- a/src/stream_cdf_time.c
+++ b/src/stream_cdf_time.c
@@ -185,8 +185,7 @@ cdfDefTime(stream_t *streamptr)
   if (taxis->longname && taxis->longname[0])
     cdf_put_att_text(fileID, timeVarId, "long_name", strlen(taxis->longname), taxis->longname);
 
-  if (taxis->has_bounds)
-    streamptr->basetime.ncvarboundsid = cdfDefTimeBounds(fileID, timeVarId, timeDimId, taxisName, taxis);
+  if (taxis->has_bounds) streamptr->basetime.ncvarboundsid = cdfDefTimeBounds(fileID, timeVarId, timeDimId, taxisName, taxis);
 
   char unitsStr[CDI_MAX_NAME];
   cdfDefTimeUnits(unitsStr, taxis);
diff --git a/src/stream_ext.c b/src/stream_ext.c
index b3e2c91951fc816867f61c1289f3c534fe4c2d5c..e0b7c26f662e5a656f8e65f51751ba4ad6367079 100644
--- a/src/stream_ext.c
+++ b/src/stream_ext.c
@@ -606,7 +606,7 @@ extWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data
   cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
 
   int header[4];
-  header[0] = (int)cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date);
+  header[0] = (int) cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date);
   header[1] = pnum;
   header[2] = (int) lround(zaxisInqLevel(vlistInqVarZaxis(vlistID, varID), levID));
   const int gridID = vlistInqVarGrid(vlistID, varID);
diff --git a/src/stream_gribapi.c b/src/stream_gribapi.c
index d3d6cd1f7e89825ca78e0c8adb3c28c4b5b2b25c..35b71ef61ccaf98ed6d6bff3b682ddb3258e0260 100644
--- a/src/stream_gribapi.c
+++ b/src/stream_gribapi.c
@@ -190,7 +190,7 @@ gribapiGetValidityDateTime(grib_handle *gh, int *vDate, int *vTime, int *sDate,
              // significanceOfReferenceTime == 3. I would recommend replacing this condition with `if(!gribapiTimeIsFC())`.
     {
       CdiDateTime vDateTime = gribapiGetDataDateTime(gh);
-      *vDate = (int)cdiDate_get(vDateTime.date);
+      *vDate = (int) cdiDate_get(vDateTime.date);
       *vTime = cdiTime_get(vDateTime.time);
     }
   else
@@ -213,7 +213,7 @@ gribapiGetValidityDateTime(grib_handle *gh, int *vDate, int *vTime, int *sDate,
             JulianDate julianDate2 = julianDate_add_seconds(julianDate, timeUnitFactor * startStep);
             CdiDateTime sDateTime = julianDate_decode(CGRIBEX_grib_calendar, julianDate2);
             sDateTime.time.second = 0;
-            *sDate = (int)cdiDate_get(sDateTime.date);
+            *sDate = (int) cdiDate_get(sDateTime.date);
             *sTime = cdiTime_get(sDateTime.time);
           }
 
@@ -221,7 +221,7 @@ gribapiGetValidityDateTime(grib_handle *gh, int *vDate, int *vTime, int *sDate,
           rDateTime = julianDate_decode(CGRIBEX_grib_calendar, julianDate);
         }
 
-      *vDate = (int)cdiDate_get(rDateTime.date);
+      *vDate = (int) cdiDate_get(rDateTime.date);
       *vTime = cdiTime_get(rDateTime.time);
     }
 }
@@ -868,8 +868,8 @@ gribapiVarCompare(compvar2_t compVar, record_t record, int flag)
   compVar0.scanKeys = record.scanKeys;
   compVar0.tiles = record.tiles;
 
-  //printf("var1: level1=%d level2=%d\n", compVar.level1, compVar.level2);
-  //printf("var2: level1=%d level2=%d\n", compVar0.level1, compVar0.level2);
+  // printf("var1: level1=%d level2=%d\n", compVar.level1, compVar.level2);
+  // printf("var2: level1=%d level2=%d\n", compVar0.level1, compVar0.level2);
 
   return memcmp(&compVar0, &compVar, sizeof(compvar2_t));
 }
@@ -1055,7 +1055,7 @@ fdbScanTimesteps(stream_t *streamptr)
           taxis->rdatetime = gribapiGetDataDateTime(gh);
           fcast = gribapiTimeIsFC(gh);
           if (fcast) taxis->unit = gribapiGetTimeUnits(gh);
-          taxis->fdate = (int)cdiDate_get(taxis->rdatetime.date);
+          taxis->fdate = (int) cdiDate_get(taxis->rdatetime.date);
           taxis->ftime = cdiTime_get(taxis->rdatetime.time);
           taxis->sdate = sDate;
           taxis->stime = sTime;
@@ -1217,7 +1217,7 @@ gribapiScanTimestep1(stream_t *streamptr)
           taxis->rdatetime = gribapiGetDataDateTime(gh);
           fcast = gribapiTimeIsFC(gh);
           if (fcast) taxis->unit = gribapiGetTimeUnits(gh);
-          taxis->fdate = (int)cdiDate_get(taxis->rdatetime.date);
+          taxis->fdate = (int) cdiDate_get(taxis->rdatetime.date);
           taxis->ftime = cdiTime_get(taxis->rdatetime.time);
           taxis->sdate = sDate;
           taxis->stime = sTime;
@@ -1374,12 +1374,12 @@ gribapiScanTimestep2(stream_t *streamptr)
               taxis->type = TAXIS_RELATIVE;
               taxis->unit = gribapiGetTimeUnits(gh);
               taxis->rdatetime = gribapiGetDataDateTime(gh);
-           }
+            }
           else
             {
               taxis->type = TAXIS_ABSOLUTE;
             }
-          taxis->fdate = (int)cdiDate_get(taxis->rdatetime.date);
+          taxis->fdate = (int) cdiDate_get(taxis->rdatetime.date);
           taxis->ftime = cdiTime_get(taxis->rdatetime.time);
           taxis->vdatetime = cdiDateTime_set(vDate, vTime);
           taxis->sdate = sDate;
@@ -1577,7 +1577,7 @@ gribapiScanTimestep(stream_t *streamptr)
                 {
                   taxis->type = TAXIS_ABSOLUTE;
                 }
-              taxis->fdate = (int)cdiDate_get(taxis->rdatetime.date);
+              taxis->fdate = (int) cdiDate_get(taxis->rdatetime.date);
               taxis->ftime = cdiTime_get(taxis->rdatetime.time);
               taxis->vdatetime = cdiDateTime_set(vDate, vTime);
               taxis->sdate = sDate;
@@ -1960,8 +1960,10 @@ gribapiDefSteptype(int editionNumber, grib_handle *gh, int productDefinitionTemp
       proDefTempNum = cdiGribAPI_ts_str_map[tsteptype].productionTemplate;
     }
 
-  if (productDefinitionTemplate != -1) proDefTempNum = productDefinitionTemplate;
-  else if (typeOfGeneratingProcess == 4) proDefTempNum = (proDefTempNum == 8) ? 11 : 1;
+  if (productDefinitionTemplate != -1)
+    proDefTempNum = productDefinitionTemplate;
+  else if (typeOfGeneratingProcess == 4)
+    proDefTempNum = (proDefTempNum == 8) ? 11 : 1;
 
   if (!gcinit)
     {
@@ -1988,9 +1990,9 @@ gribapiDefDateTimeAbs(int editionNumber, grib_handle *gh, int date, int time, in
 }
 
 static int
-gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, int fdate, int ftime, int vdate, int vtime, int sdate,
-                      int stime, int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int timeunit,
-                      int calendar, int gcinit)
+gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, int fdate, int ftime, int vdate, int vtime, int sdate, int stime,
+                      int productDefinitionTemplate, int typeOfGeneratingProcess, int tsteptype, int timeunit, int calendar,
+                      int gcinit)
 {
   int status = -1;
 
@@ -2069,8 +2071,8 @@ gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, int fdate, int ftime,
 }
 
 static void
-gribapiDefTime(int editionNumber, int productDefinitionTemplate, int typeOfGeneratingProcess, grib_handle *gh, int vdate,
-               int vtime, int tsteptype, int numavg, int taxisID, int gcinit)
+gribapiDefTime(int editionNumber, int productDefinitionTemplate, int typeOfGeneratingProcess, grib_handle *gh, int vdate, int vtime,
+               int tsteptype, int numavg, int taxisID, int gcinit)
 {
   UNUSED(numavg);
 
diff --git a/src/stream_gribapi.h b/src/stream_gribapi.h
index c1e5554af3167e74e82ecb9802a3001904721e23..cd7f6f71b71820895fd5e2e68852dd41333212c9 100644
--- a/src/stream_gribapi.h
+++ b/src/stream_gribapi.h
@@ -13,9 +13,9 @@ int gribapiScanTimestep(stream_t *streamptr);
 
 int gribapiDecode(void *gribbuffer, size_t gribsize, void *data, size_t datasize, int unreduced, size_t *nmiss, double missval);
 
-size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID, int vdate, int vtime, int tsteptype,
-                     int numavg, size_t datasize, const void *data, size_t nmiss, void **gribbuffer, size_t *gribbuffersize,
-                     int ljpeg, void *gribContainer);
+size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID, int vdate, int vtime, int tsteptype, int numavg,
+                     size_t datasize, const void *data, size_t nmiss, void **gribbuffer, size_t *gribbuffersize, int ljpeg,
+                     void *gribContainer);
 
 int gribapiGetScanningMode(grib_handle *gh);
 void gribapiSetScanningMode(grib_handle *gh, int scanningMode);
diff --git a/src/stream_record.c b/src/stream_record.c
index 8a5808078fa8f8153ec61d50ef10b0271d2cf358..b3029c6b1748450499cff4052b7973a8cede4308 100644
--- a/src/stream_record.c
+++ b/src/stream_record.c
@@ -183,7 +183,7 @@ streamDefRecord(int streamID, int varID, int levelID)
   record->levelID = levelID;
   record->param = param;
   record->ilevel = ilevel;
-  record->vdate = (int)cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date);
+  record->vdate = (int) cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date);
   record->vtime = cdiTime_get(streamptr->tsteps[tsID].taxis.vdatetime.time);
   record->gridID = gridID;
   record->prec = vlistInqVarDatatype(vlistID, varID);
diff --git a/src/stream_srv.c b/src/stream_srv.c
index a35e9f196bc90efd0543b7b354ed975c51f27cba..b78b96108348ec72261d8a30473fc277acee4585 100644
--- a/src/stream_srv.c
+++ b/src/stream_srv.c
@@ -617,7 +617,7 @@ srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data
   int header[8];
   header[0] = pnum;
   header[1] = (int) lround(zaxisInqLevel(vlistInqVarZaxis(vlistID, varID), levID));
-  header[2] = (int)cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date);
+  header[2] = (int) cdiDate_get(streamptr->tsteps[tsID].taxis.vdatetime.date);
   header[3] = cdiTime_get(streamptr->tsteps[tsID].taxis.vdatetime.time);
 
   size_t xsize = gridInqXsize(gridID);
diff --git a/src/table.c b/src/table.c
index 2178d5722bd2a473a5b97564b8e56c67c352671d..48c4d0310fb10fbcd1d7aea5a949f91fc9b09f71 100644
--- a/src/table.c
+++ b/src/table.c
@@ -107,7 +107,7 @@ parTableFinalize(void)
   for (int tableID = 0; tableID < MAX_TABLE; ++tableID)
     if (parTable[tableID].used)
       {
-        int npars = parTable[tableID].npars;
+        const int npars = parTable[tableID].npars;
         for (int item = 0; item < npars; ++item)
           {
             if (parTable[tableID].pars[item].dupflags & TABLE_DUP_NAME) Free((void *) parTable[tableID].pars[item].name);
@@ -161,7 +161,7 @@ decodeForm1(char *pline, char *name, char *longname, char *units)
 {
   char *pstart, *pend;
 
-  /* FIXME: parse success isn't verified */
+  // FIXME: parse success isn't verified
   /* long level =  */ strtol(pline, &pline, 10);
   while (isspace((int) *pline)) pline++;
 
@@ -178,10 +178,10 @@ decodeForm1(char *pline, char *name, char *longname, char *units)
 
   if (pline[0] == 0) return 0;
 
-  /* Format 1 : code name add mult longname [units] */
-  /* FIXME: successful parse isn't verified */
+  // Format 1 : code name add mult longname [units]
+  // FIXME: successful parse isn't verified
   /* double add  =  */ strtod(pline, &pline);
-  /* FIXME: successful parse isn't verified */
+  // FIXME: successful parse isn't verified
   /* double mult =  */ strtod(pline, &pline);
 
   while (isspace((int) *pline)) pline++;
@@ -276,7 +276,7 @@ decodeForm2(char *pline, char *name, char *longname, char *units)
   pend--;
   while (isspace((int) *pend)) pend--;
   {
-    size_t len = (size_t) (pend - pline + 1);
+    const size_t len = (size_t) (pend - pline + 1);
     if (len > 0)
       {
         memcpy(longname, pline, len);
@@ -366,7 +366,7 @@ tableRead(const char *tablefile)
 
       if (err) continue;
 
-      if (name[0] == 0) sprintf(name, "var%d", id);
+      if (name[0] == 0) snprintf(name, sizeof(name), "var%d", id);
 
       tableDefEntry(tableID, id, ltype, name, longname, units);
     }
@@ -396,8 +396,8 @@ tableFromEnv(int modelID, int tablenum)
   if (tablenum) tablenameLen += (size_t) (sprintf(tablename + tablenameLen, "_%03d", tablenum));
   size_t lenp = 0, lenf = tablenameLen;
   if (tablePath) lenp = strlen(tablePath);
-  /* if (tablePath) printf("tablePath = %s\n", tablePath); */
-  /* if (tablename) printf("tableName = %s\n", tablename); */
+  // if (tablePath) printf("tablePath = %s\n", tablePath);
+  // if (tablename) printf("tableName = %s\n", tablename);
   char *tablefile = (char *) Malloc(lenp + lenf + 3);
   if (tablePath)
     {
@@ -407,15 +407,15 @@ tableFromEnv(int modelID, int tablenum)
   else
     tablefile[0] = '\0';
   strcat(tablefile, tablename);
-  /* if (tablefile) printf("tableFile = %s\n", tablefile); */
+  // if (tablefile) printf("tableFile = %s\n", tablefile);
 
-  int tableID = tableRead(tablefile);
+  const int tableID = tableRead(tablefile);
   if (tableID != CDI_UNDEFID)
     {
       tableDefModelID(tableID, modelID);
       tableDefNum(tableID, tablenum);
     }
-  /* printf("tableID = %d %s\n", tableID, tablefile); */
+  // printf("tableID = %d %s\n", tableID, tablefile);
   Free(tablefile);
 
   return tableID;
@@ -469,7 +469,7 @@ tableInq(int modelID, int tablenum, const char *tablename)
               if ((modelName = modelInqNamePtr(modelID)))
                 {
                   strcpy(tablefile, modelName);
-                  size_t len = strlen(tablefile);
+                  const size_t len = strlen(tablefile);
                   for (size_t i = 0; i < len; i++)
                     if (tablefile[i] == '.') tablefile[i] = '\0';
                   modelID2 = modelInq(-1, 0, tablefile);
@@ -502,10 +502,7 @@ tableDef(int modelID, int tablenum, const char *tablename)
   int tableID = CDI_UNDEFID;
 
   if (!ParTableInit) parTableInit();
-  /*
-  if ( ! (modelID == CDI_UNDEFID && tablenum == 0) )
-    tableID = tableInq(modelID, tablenum, tablename);
-    */
+  // if (!(modelID == CDI_UNDEFID && tablenum == 0)) tableID = tableInq(modelID, tablenum, tablename);
   if (tableID == CDI_UNDEFID)
     {
       tableID = tableNewEntry();
@@ -575,6 +572,17 @@ tableInqNamePtr(int tableID)
   return tablename;
 }
 
+static size_t
+max_length(size_t maxlen, const char *cstring)
+{
+  if (cstring)
+    {
+      const size_t len = strlen(cstring);
+      if (len > maxlen) maxlen = len;
+    }
+  return maxlen;
+}
+
 void
 tableWrite(const char *ptfile, int tableID)
 {
@@ -595,31 +603,16 @@ tableWrite(const char *ptfile, int tableID)
 
   FILE *ptfp = fopen(ptfile, "w");
 
-  int npars = parTable[tableID].npars;
-
+  const int npars = parTable[tableID].npars;
   for (int item = 0; item < npars; item++)
     {
-      if (parTable[tableID].pars[item].name)
-        {
-          size_t lenname = strlen(parTable[tableID].pars[item].name);
-          if (lenname > maxname) maxname = lenname;
-        }
-
-      if (parTable[tableID].pars[item].longname)
-        {
-          size_t lenlname = strlen(parTable[tableID].pars[item].longname);
-          if (lenlname > maxlname) maxlname = lenlname;
-        }
-
-      if (parTable[tableID].pars[item].units)
-        {
-          size_t lenunits = strlen(parTable[tableID].pars[item].units);
-          if (lenunits > maxunits) maxunits = lenunits;
-        }
+      maxname = max_length(maxname, parTable[tableID].pars[item].name);
+      maxlname = max_length(maxlname, parTable[tableID].pars[item].longname);
+      maxunits = max_length(maxunits, parTable[tableID].pars[item].units);
     }
 
-  int tablenum = tableInqNum(tableID);
-  int modelID = parTable[tableID].modelID;
+  const int tablenum = tableInqNum(tableID);
+  const int modelID = parTable[tableID].modelID;
   if (modelID != CDI_UNDEFID)
     {
       modelnameptr = modelInqNamePtr(modelID);
@@ -680,33 +673,18 @@ tableFWriteC(FILE *ptfp, int tableID)
 
   partabCheckID(tableID);
 
-  int npars = parTable[tableID].npars;
-
+  const int npars = parTable[tableID].npars;
   for (int item = 0; item < npars; item++)
     {
-      if (parTable[tableID].pars[item].name)
-        {
-          size_t lenname = strlen(parTable[tableID].pars[item].name);
-          if (lenname > maxname) maxname = lenname;
-        }
-
-      if (parTable[tableID].pars[item].longname)
-        {
-          size_t lenlname = strlen(parTable[tableID].pars[item].longname);
-          if (lenlname > maxlname) maxlname = lenlname;
-        }
-
-      if (parTable[tableID].pars[item].units)
-        {
-          size_t lenunits = strlen(parTable[tableID].pars[item].units);
-          if (lenunits > maxunits) maxunits = lenunits;
-        }
+      maxname = max_length(maxname, parTable[tableID].pars[item].name);
+      maxlname = max_length(maxlname, parTable[tableID].pars[item].longname);
+      maxunits = max_length(maxunits, parTable[tableID].pars[item].units);
     }
 
   strncpy(tablename, parTable[tableID].name, sizeof(tablename));
   tablename[sizeof(tablename) - 1] = '\0';
   {
-    size_t len = strlen(tablename);
+    const size_t len = strlen(tablename);
     for (size_t i = 0; i < len; i++)
       if (tablename[i] == '.') tablename[i] = '_';
   }
@@ -738,7 +716,7 @@ tableInqEntry(int tableID, int id, int ltype, char *name, char *longname, char *
 
   if (tableID != CDI_UNDEFID)
     {
-      int npars = parTable[tableID].npars;
+      const int npars = parTable[tableID].npars;
       for (int item = 0; item < npars; item++)
         {
           if (parTable[tableID].pars[item].id == id
@@ -761,7 +739,7 @@ tableInqParCode(int tableID, char *varname, int *code)
 
   if (tableID != CDI_UNDEFID && varname != NULL)
     {
-      int npars = parTable[tableID].npars;
+      const int npars = parTable[tableID].npars;
       for (int item = 0; item < npars; item++)
         {
           if (parTable[tableID].pars[item].name && strcmp(parTable[tableID].pars[item].name, varname) == 0)
diff --git a/src/taxis.c b/src/taxis.c
index 835923438d2b1ed3d56a07a3edf385a031cbde2d..811e48b367a8ab2252bb76c4e653be20f5d3d070 100644
--- a/src/taxis.c
+++ b/src/taxis.c
@@ -81,7 +81,8 @@ tunitNamePtr(int unitID)
 {
   int size = sizeof(Timeunits) / sizeof(*Timeunits);
   return (unitID > 0 && unitID < size) ? Timeunits[unitID] : Timeunits[0];
-}static void
+}
+static void
 taxisDefaultValue(taxis_t *taxisptr)
 {
   taxisptr->self = CDI_UNDEFID;
@@ -272,7 +273,7 @@ taxisDefVdate(int taxisID, int vdate)
 {
   taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
 
-  if ((int)cdiDate_get(taxisptr->vdatetime.date) != vdate)
+  if ((int) cdiDate_get(taxisptr->vdatetime.date) != vdate)
     {
       taxisptr->vdatetime.date = cdiDate_set(vdate);
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
@@ -354,7 +355,7 @@ taxisDefRdate(int taxisID, int rdate)
 {
   taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
 
-  if ((int)cdiDate_get(taxisptr->rdatetime.date) != rdate)
+  if ((int) cdiDate_get(taxisptr->rdatetime.date) != rdate)
     {
       taxisptr->rdatetime.date = cdiDate_set(rdate);
 
@@ -591,7 +592,7 @@ taxisCopyTimestep(int taxisID2, int taxisID1)
     {
       taxisptr2->vdatetime_lb = taxisptr1->vdatetime_lb;
       taxisptr2->vdatetime_ub = taxisptr1->vdatetime_ub;
-   }
+    }
 
   taxisptr2->fdate = taxisptr1->fdate;
   taxisptr2->ftime = taxisptr1->ftime;
@@ -624,7 +625,6 @@ taxisInqRdatetime(int taxisID)
   return taxisptr->rdatetime;
 }
 
-
 /*
 @Function  taxisInqVdate
 @Title     Get the verification date
@@ -645,7 +645,7 @@ int
 taxisInqVdate(int taxisID)
 {
   const taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
-  return (int)cdiDate_get(taxisptr->vdatetime.date);
+  return (int) cdiDate_get(taxisptr->vdatetime.date);
 }
 
 int
@@ -659,8 +659,8 @@ void
 taxisInqVdateBounds(int taxisID, int *vdate_lb, int *vdate_ub)
 {
   const taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
-  *vdate_lb = (int)cdiDate_get(taxisptr->vdatetime_lb.date);
-  *vdate_ub = (int)cdiDate_get(taxisptr->vdatetime_ub.date);
+  *vdate_lb = (int) cdiDate_get(taxisptr->vdatetime_lb.date);
+  *vdate_ub = (int) cdiDate_get(taxisptr->vdatetime_ub.date);
 }
 
 void
@@ -676,7 +676,8 @@ taxisDefVdateBounds(int taxisID, int vdate_lb, int vdate_ub)
 {
   taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
 
-  if (taxisptr->has_bounds == false || (int)cdiDate_get(taxisptr->vdatetime_lb.date) != vdate_lb || (int)cdiDate_get(taxisptr->vdatetime_ub.date) != vdate_ub)
+  if (taxisptr->has_bounds == false || (int) cdiDate_get(taxisptr->vdatetime_lb.date) != vdate_lb
+      || (int) cdiDate_get(taxisptr->vdatetime_ub.date) != vdate_ub)
     {
       taxisptr->vdatetime_lb.date = cdiDate_set(vdate_lb);
       taxisptr->vdatetime_ub.date = cdiDate_set(vdate_ub);
@@ -690,7 +691,8 @@ taxisDefVdatetimeBounds(int taxisID, CdiDateTime vdatetime_lb, CdiDateTime vdate
 {
   taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
 
-  if (taxisptr->has_bounds == false || cdiDateTime_isNE(taxisptr->vdatetime_lb, vdatetime_lb) || cdiDateTime_isNE(taxisptr->vdatetime_ub, vdatetime_ub))
+  if (taxisptr->has_bounds == false || cdiDateTime_isNE(taxisptr->vdatetime_lb, vdatetime_lb)
+      || cdiDateTime_isNE(taxisptr->vdatetime_ub, vdatetime_ub))
     {
       taxisptr->vdatetime_lb = vdatetime_lb;
       taxisptr->vdatetime_ub = vdatetime_ub;
@@ -719,7 +721,7 @@ int
 taxisInqVtime(int taxisID)
 {
   const taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
-  //return taxisptr->vtime;
+  // return taxisptr->vtime;
   return cdiTime_get(taxisptr->vdatetime.time);
 }
 
@@ -743,7 +745,8 @@ taxisDefVtimeBounds(int taxisID, int vtime_lb, int vtime_ub)
 {
   taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
 
-  if (taxisptr->has_bounds == false || cdiTime_get(taxisptr->vdatetime_lb.time) != vtime_lb || cdiTime_get(taxisptr->vdatetime_ub.time) != vtime_ub)
+  if (taxisptr->has_bounds == false || cdiTime_get(taxisptr->vdatetime_lb.time) != vtime_lb
+      || cdiTime_get(taxisptr->vdatetime_ub.time) != vtime_ub)
     {
       taxisptr->vdatetime_lb.time = cdiTime_set(vtime_lb);
       taxisptr->vdatetime_ub.time = cdiTime_set(vtime_ub);
@@ -779,7 +782,7 @@ taxisInqRdate(int taxisID)
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 
-  return (int)cdiDate_get(taxisptr->rdatetime.date);
+  return (int) cdiDate_get(taxisptr->rdatetime.date);
 }
 
 /*
@@ -1008,7 +1011,8 @@ timevalue_decode(int timeunits, double timevalue)
       /*
       {
         double cval = julianDate.julianDay * 86400.0 + julianDate.secondOfDay;
-        if (cval != timevalue) printf("TUNIT_SECOND error: %g %g %d %d\n", timevalue, cval, julianDate.julianDay, julianDate.secondOfDay);
+        if (cval != timevalue) printf("TUNIT_SECOND error: %g %g %d %d\n", timevalue, cval, julianDate.julianDay,
+      julianDate.secondOfDay);
       }
       */
     }
@@ -1025,7 +1029,8 @@ timevalue_decode(int timeunits, double timevalue)
       /*
       {
         double cval = julianDate.julianDay + julianDate.secondOfDay / 86400.0;
-        if (cval != timevalue) printf("TUNIT_DAY error: %g %g %d %d\n", timevalue, cval, julianDate.julianDay, julianDate.secondOfDay);
+        if (cval != timevalue) printf("TUNIT_DAY error: %g %g %d %d\n", timevalue, cval, julianDate.julianDay,
+      julianDate.secondOfDay);
       }
       */
     }
@@ -1354,8 +1359,8 @@ cdiSetForecastPeriod(double timevalue, taxis_t *taxis)
 
   const CdiDateTime dt = julianDate_decode(calendar, julianDate_sub(julianDate, julianDate2));
 
-  (*taxis).fdate = (int)cdiDate_get(dt.date);
-  (*taxis).ftime = (int)cdiTime_get(dt.time);
+  (*taxis).fdate = (int) cdiDate_get(dt.date);
+  (*taxis).ftime = (int) cdiTime_get(dt.time);
 }
 
 CdiDateTime
@@ -1367,31 +1372,37 @@ cdi_decode_timeval(double timevalue, taxis_t *taxis)
 double
 cdi_encode_timeval(CdiDateTime datetime, taxis_t *taxis)
 {
-  double timevalue;
+  double timeValue = 0.0;
 
   if (taxis->type == TAXIS_ABSOLUTE)
     {
       if (taxis->unit == TUNIT_YEAR)
         {
-          timevalue = datetime.date.year;
+          timeValue = datetime.date.year;
         }
       else if (taxis->unit == TUNIT_MONTH)
         {
-          int64_t xdate = cdiDate_get(datetime.date);
-          timevalue = xdate / 100 + copysign((double) (datetime.date.day != 0) * 0.5, (double) xdate);
+          const int64_t xdate = cdiDate_get(datetime.date);
+          timeValue = xdate / 100 + copysign((double) (datetime.date.day != 0) * 0.5, (double) xdate);
+        }
+      else if (taxis->unit == TUNIT_SECOND)
+        {
+          int hour, minute, second, ms;
+          cdiTime_decode(datetime.time, &hour, &minute, &second, &ms);
+          timeValue = hour * 3600 + minute * 60 + second;
         }
       else
         {
           int hour, minute, second, ms;
           cdiTime_decode(datetime.time, &hour, &minute, &second, &ms);
-          int64_t xdate = cdiDate_get(datetime.date);
-          timevalue = copysign(1.0, (double) xdate) * (fabs((double) xdate) + (hour * 3600 + minute * 60 + second) / 86400.0);
+          const int64_t xdate = cdiDate_get(datetime.date);
+          timeValue = copysign(1.0, (double) xdate) * (fabs((double) xdate) + (hour * 3600 + minute * 60 + second) / 86400.0);
         }
     }
   else
-    timevalue = datetime2rtimeval(datetime, taxis);
+    timeValue = datetime2rtimeval(datetime, taxis);
 
-  return timevalue;
+  return timeValue;
 }
 
 void
@@ -1471,12 +1482,10 @@ taxisPrintKernel(taxis_t *taxisptr, FILE *fp)
           "fc_unit     = %d\n"
           "fc_period   = %g\n"
           "\n",
-          taxisptr->self, taxisptr->self, (int) taxisptr->used, taxisptr->type,
-          (int)cdiDate_get(taxisptr->vdatetime.date), cdiTime_get(taxisptr->vdatetime.time),
-          (int)cdiDate_get(taxisptr->rdatetime.date), cdiTime_get(taxisptr->rdatetime.time),
-          taxisptr->fdate, taxisptr->ftime, taxisptr->calendar, taxisptr->unit, taxisptr->numavg,
-          (int) taxisptr->climatology, (int) taxisptr->has_bounds, vdate_lb, vtime_lb, vdate_ub, vtime_ub,
-          taxisptr->fc_unit, taxisptr->fc_period);
+          taxisptr->self, taxisptr->self, (int) taxisptr->used, taxisptr->type, (int) cdiDate_get(taxisptr->vdatetime.date),
+          cdiTime_get(taxisptr->vdatetime.time), (int) cdiDate_get(taxisptr->rdatetime.date), cdiTime_get(taxisptr->rdatetime.time),
+          taxisptr->fdate, taxisptr->ftime, taxisptr->calendar, taxisptr->unit, taxisptr->numavg, (int) taxisptr->climatology,
+          (int) taxisptr->has_bounds, vdate_lb, vtime_lb, vdate_ub, vtime_ub, taxisptr->fc_unit, taxisptr->fc_period);
 }
 
 static int
@@ -1486,7 +1495,7 @@ taxisCompareP(void *taxisptr1, void *taxisptr2)
 
   xassert(t1 && t2);
 
-  return !(t1->used == t2->used && t1->type == t2->type && cdiDateTime_isEQ(t1->vdatetime,  t2->vdatetime)
+  return !(t1->used == t2->used && t1->type == t2->type && cdiDateTime_isEQ(t1->vdatetime, t2->vdatetime)
            && cdiDateTime_isEQ(t1->rdatetime, t2->rdatetime) && t1->fdate == t2->fdate && t1->ftime == t2->ftime
            && t1->calendar == t2->calendar && t1->unit == t2->unit && t1->fc_unit == t2->fc_unit && t1->numavg == t2->numavg
            && t1->climatology == t2->climatology && t1->has_bounds == t2->has_bounds
@@ -1595,9 +1604,9 @@ taxisPack(void *voidP, void *packBuffer, int packBufferSize, int *packBufferPos,
   intBuffer[idx++] = taxisP->self;
   intBuffer[idx++] = taxisP->used;
   intBuffer[idx++] = taxisP->type;
-  intBuffer[idx++] = (int)cdiDate_get(taxisP->vdatetime.date);
+  intBuffer[idx++] = (int) cdiDate_get(taxisP->vdatetime.date);
   intBuffer[idx++] = cdiTime_get(taxisP->vdatetime.time);
-  intBuffer[idx++] = (int)cdiDate_get(taxisP->rdatetime.date);
+  intBuffer[idx++] = (int) cdiDate_get(taxisP->rdatetime.date);
   intBuffer[idx++] = cdiTime_get(taxisP->rdatetime.time);
   intBuffer[idx++] = taxisP->fdate;
   intBuffer[idx++] = taxisP->ftime;
@@ -1607,9 +1616,9 @@ taxisPack(void *voidP, void *packBuffer, int packBufferSize, int *packBufferPos,
   intBuffer[idx++] = taxisP->numavg;
   intBuffer[idx++] = taxisP->climatology;
   intBuffer[idx++] = taxisP->has_bounds;
-  intBuffer[idx++] = (int)cdiDate_get(taxisP->vdatetime_lb.date);
+  intBuffer[idx++] = (int) cdiDate_get(taxisP->vdatetime_lb.date);
   intBuffer[idx++] = cdiTime_get(taxisP->vdatetime_lb.time);
-  intBuffer[idx++] = (int)cdiDate_get(taxisP->vdatetime_ub.date);
+  intBuffer[idx++] = (int) cdiDate_get(taxisP->vdatetime_ub.date);
   intBuffer[idx++] = cdiTime_get(taxisP->vdatetime_ub.time);
   intBuffer[idx++] = taxisP->name ? (int) strlen(taxisP->name) : 0;
   intBuffer[idx++] = taxisP->longname ? (int) strlen(taxisP->longname) : 0;
diff --git a/src/taxis.h b/src/taxis.h
index 7089eaac729c4dfe4c1fc8fe01edad13c37272b1..c9f3526bf9f4aa9f96cfc596ae99363be5ba9dec 100644
--- a/src/taxis.h
+++ b/src/taxis.h
@@ -15,28 +15,27 @@ typedef struct
   int self;
   bool used;
   short has_bounds;
-  int datatype;             // datatype
-  int type;                 // time type
-  int sdate;                // start date
-  int stime;                // start time
-  CdiDateTime vdatetime;    // verification date/time
-  CdiDateTime rdatetime;    // reference date/time
-  int fdate;                // forecast reference date
-  int ftime;                // forecast reference time
+  int datatype;           // datatype
+  int type;               // time type
+  int sdate;              // start date
+  int stime;              // start time
+  CdiDateTime vdatetime;  // verification date/time
+  CdiDateTime rdatetime;  // reference date/time
+  int fdate;              // forecast reference date
+  int ftime;              // forecast reference time
   int calendar;
-  int unit;                 // time unit
+  int unit;  // time unit
   int numavg;
   bool climatology;
-  CdiDateTime vdatetime_lb; // lower bounds of verification date/time
-  CdiDateTime vdatetime_ub; // upper bounds of verification date/time
-  int fc_unit;              // forecast time unit
-  double fc_period;         // forecast time period
+  CdiDateTime vdatetime_lb;  // lower bounds of verification date/time
+  CdiDateTime vdatetime_ub;  // upper bounds of verification date/time
+  int fc_unit;               // forecast time unit
+  double fc_period;          // forecast time period
   char *name;
   char *longname;
   char *units;
 } taxis_t;
 
-
 //      taxisInqSdate: Get the start date
 int taxisInqSdate(int taxisID);
 
diff --git a/src/varscan.c b/src/varscan.c
index 84c4e0e9de92a4b5d6620399c57a7a3084f230fb..ab32359b8bbaf02f1df596dd262ba06d1e16a8ea 100644
--- a/src/varscan.c
+++ b/src/varscan.c
@@ -374,8 +374,8 @@ varAddRecord(int recID, int param, int gridID, int zaxistype, int hasBounds, int
              const VarScanKeys *scanKeys, const var_tile_t *tiles, int *tile_index)
 {
   int varID = (CDI_Split_Ltype105 != 1 || zaxistype != ZAXIS_HEIGHT)
-                       ? varGetEntry(param, gridID, zaxistype, ltype1, tsteptype, name, scanKeys, tiles)
-                       : CDI_UNDEFID;
+                  ? varGetEntry(param, gridID, zaxistype, ltype1, tsteptype, name, scanKeys, tiles)
+                  : CDI_UNDEFID;
 
   if (varID == CDI_UNDEFID)
     {
@@ -776,8 +776,8 @@ varDefZAxisReference(int nhlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZE])
 }
 
 bool
-zaxis_compare(int zaxisID, int zaxistype, int nlevels, const double *levels, const double *lbounds,
-              const double *ubounds, const char *longname, const char *units, int ltype1, int ltype2)
+zaxis_compare(int zaxisID, int zaxistype, int nlevels, const double *levels, const double *lbounds, const double *ubounds,
+              const char *longname, const char *units, int ltype1, int ltype2)
 {
   bool differ = true;
 
@@ -812,7 +812,7 @@ zaxis_compare(int zaxisID, int zaxistype, int nlevels, const double *levels, con
               for (int levelID = 0; levelID < nlevels; levelID++)
                 {
                   if (fabs(lbounds[levelID] - bounds[levelID]) > 1.e-9
-                   || fabs(ubounds[levelID] - bounds[levelID + nlevels]) > 1.e-9)
+                      || fabs(ubounds[levelID] - bounds[levelID + nlevels]) > 1.e-9)
                     {
                       differ = true;
                       break;
@@ -863,8 +863,8 @@ varDefZAxisSearch(int id, void *res, void *data)
 {
   struct varDefZAxisSearchState *state = (struct varDefZAxisSearchState *) data;
   (void) res;
-  if (zaxis_compare(id, state->zaxistype, state->nlevels, state->levels, state->lbounds, state->ubounds,
-                    state->longname, state->units, state->ltype1, state->ltype2)
+  if (zaxis_compare(id, state->zaxistype, state->nlevels, state->levels, state->lbounds, state->ubounds, state->longname,
+                    state->units, state->ltype1, state->ltype2)
       == false)
     {
       state->resIDValue = id;
diff --git a/src/varscan.h b/src/varscan.h
index 93561f2511328a0b67aa29dc8dbc03b11cc617c9..e2ff1469b0aaf2df8ccdb9f43678efebbdfcf69e 100644
--- a/src/varscan.h
+++ b/src/varscan.h
@@ -34,8 +34,8 @@ void varDefOptGribInt(int varID, int tile_index, long lval, const char *keyword)
 void varDefOptGribDbl(int varID, int tile_index, double dval, const char *keyword);
 int varOptGribNentries(int varID);
 
-bool zaxis_compare(int zaxisID, int zaxistype, int nlevels, const double *levels, const double *lbounds,
-                   const double *ubounds, const char *longname, const char *units, int ltype1, int ltype2);
+bool zaxis_compare(int zaxisID, int zaxistype, int nlevels, const double *levels, const double *lbounds, const double *ubounds,
+                   const char *longname, const char *units, int ltype1, int ltype2);
 
 #endif
 /*
diff --git a/src/vlist.c b/src/vlist.c
index 18ef76e918c1e3d4802a129424f369914a3ab0a2..68f13bd8b4ed5115b51de096431e53cbbddb1da6 100644
--- a/src/vlist.c
+++ b/src/vlist.c
@@ -153,7 +153,7 @@ vlist_copy(vlist_t *vlistptr2, vlist_t *vlistptr1)
   memcpy(vlistptr2, vlistptr1, sizeof(vlist_t));
   vlistptr2->internal = vlist2internal;  // the question who's responsible to destroy the vlist is tied to its containing memory
                                          // region, so we retain this flag
-  vlistptr2->immutable = 0;  // this is a copy, so it's mutable, independent of whether the original is mutable or not
+  vlistptr2->immutable = 0;              // this is a copy, so it's mutable, independent of whether the original is mutable or not
   vlistptr2->keys.nelems = 0;
   vlistptr2->atts.nelems = 0;
   vlistptr2->self = vlistID2;
@@ -425,7 +425,8 @@ vgzZAxisSearch(int id, void *res, void *data)
 {
   struct vgzSearchState *state = (struct vgzSearchState *) data;
   (void) res;
-  if (zaxis_compare(id, state->zaxistype, state->nlevels, state->levels, state->lbounds, state->ubounds, NULL, NULL, 0, -1) == false)
+  if (zaxis_compare(id, state->zaxistype, state->nlevels, state->levels, state->lbounds, state->ubounds, NULL, NULL, 0, -1)
+      == false)
     {
       state->resIDValue = id;
       return CDI_APPLY_STOP;
diff --git a/src/vlist.h b/src/vlist.h
index 109fa1e0e07297d2652ebb62bcc167edffce7f27..c57a2cffb74c581fbf692f065d4008c4dc679fd3 100644
--- a/src/vlist.h
+++ b/src/vlist.h
@@ -58,14 +58,11 @@ typedef struct
   int modelID;
   int tableID;
   int timave;
-  int nsb; // Number of significant bits
+  int nsb;  // Number of significant bits
   int xyz;
   bool missvalused;  // true if missval is defined
   bool lvalidrange;
-  char *extra;
   double missval;
-  double scalefactor;
-  double addoffset;
   double validrange[2];
   levinfo_t *levinfo;
   int comptype;   // compression type
@@ -88,10 +85,10 @@ typedef struct
   // set if this vlist has been created by CDI itself, and must not be destroyed by the user, consequently
   bool internal;
   int self;
-  int nvars; // number of variables
+  int nvars;  // number of variables
   int ngrids;
   int nzaxis;
-  int nsubtypes; // no. of variable subtypes (e.g. sets of tiles)
+  int nsubtypes;  // no. of variable subtypes (e.g. sets of tiles)
   long ntsteps;
   int taxisID;
   int tableID;
diff --git a/src/vlist_var.c b/src/vlist_var.c
index a1797d735342ef7189f8b1f2ea1e02f8561cf743..7a86e99bbfdd27bd3b39dfd7501a5ddd7c3e6c9a 100644
--- a/src/vlist_var.c
+++ b/src/vlist_var.c
@@ -31,9 +31,6 @@ vlistvarInitEntry(int vlistID, int varID)
   vlistptr->vars[varID].tableID = CDI_UNDEFID;
   vlistptr->vars[varID].missvalused = false;
   vlistptr->vars[varID].missval = CDI_Default_Missval;
-  vlistptr->vars[varID].addoffset = 0.0;
-  vlistptr->vars[varID].scalefactor = 1.0;
-  vlistptr->vars[varID].extra = NULL;
   vlistptr->vars[varID].levinfo = NULL;
   vlistptr->vars[varID].comptype = CDI_COMPRESS_NONE;
   vlistptr->vars[varID].complevel = 1;
@@ -133,7 +130,6 @@ vlistDefVarTiles(int vlistID, int gridID, int zaxisID, int timetype, int tileset
           fprintf(stdout, "CDI info:       vlistDefVarTsteptype(vlistID, varID, tsteptype)\n");
           fprintf(stdout, "CDI info:          with: timetype = TIME_CONSTANT | TIME_VARYING\n");
           fprintf(stdout, "CDI info:                tsteptype = TSTEP_AVG .... TSTEP_SUM\n");
-
         }
     }
 
@@ -442,21 +438,19 @@ void
 vlistInqVarName(int vlistID, int varID, char *name)
 {
   int length = CDI_MAX_NAME;
-  (void) cdiInqKeyString(vlistID, varID, CDI_KEY_NAME, name, &length);
-
-  if (!name[0])
+  if (CDI_NOERR != cdiInqKeyString(vlistID, varID, CDI_KEY_NAME, name, &length))
     {
       vlistCheckVarID(__func__, vlistID, varID);
 
       vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-      int param = vlistptr->vars[varID].param;
+      const int param = vlistptr->vars[varID].param;
       int pdis, pcat, pnum;
       cdiDecodeParam(param, &pnum, &pcat, &pdis);
       if (pdis == 255)
         {
-          int code = pnum;
-          int tableID = vlistptr->vars[varID].tableID;
+          const int code = pnum;
+          const int tableID = vlistptr->vars[varID].tableID;
           tableInqEntry(tableID, code, -1, name, NULL, NULL);
           if (!name[0]) sprintf(name, "var%d", code);
         }
@@ -497,13 +491,13 @@ vlistCopyVarName(int vlistID, int varID)
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   // Otherwise we check if we should use the table of parameter descriptions.
-  int param = vlistptr->vars[varID].param;
+  const int param = vlistptr->vars[varID].param;
   int discipline, category, number;
   cdiDecodeParam(param, &number, &category, &discipline);
   char *result = NULL;
   if (discipline == 255)
     {
-      int tableID = vlistptr->vars[varID].tableID;
+      const int tableID = vlistptr->vars[varID].tableID;
       tableInqEntry(tableID, number, -1, name, NULL, NULL);
       if (name[0])
         result = strdup(name);
@@ -548,21 +542,19 @@ void
 vlistInqVarLongname(int vlistID, int varID, char *longname)
 {
   int length = CDI_MAX_NAME;
-  (void) cdiInqKeyString(vlistID, varID, CDI_KEY_LONGNAME, longname, &length);
-
-  if (!longname[0])
+  if (CDI_NOERR != cdiInqKeyString(vlistID, varID, CDI_KEY_LONGNAME, longname, &length))
     {
       vlistCheckVarID(__func__, vlistID, varID);
 
       vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-      int param = vlistptr->vars[varID].param;
+      const int param = vlistptr->vars[varID].param;
       int pdis, pcat, pnum;
       cdiDecodeParam(param, &pnum, &pcat, &pdis);
       if (pdis == 255)
         {
-          int code = pnum;
-          int tableID = vlistptr->vars[varID].tableID;
+          const int code = pnum;
+          const int tableID = vlistptr->vars[varID].tableID;
           tableInqEntry(tableID, code, -1, NULL, longname, NULL);
         }
     }
@@ -650,21 +642,19 @@ void
 vlistInqVarUnits(int vlistID, int varID, char *units)
 {
   int length = CDI_MAX_NAME;
-  (void) cdiInqKeyString(vlistID, varID, CDI_KEY_UNITS, units, &length);
-
-  if (!units[0])
+  if (CDI_NOERR != cdiInqKeyString(vlistID, varID, CDI_KEY_UNITS, units, &length))
     {
       vlistCheckVarID(__func__, vlistID, varID);
 
       vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-      int param = vlistptr->vars[varID].param;
+      const int param = vlistptr->vars[varID].param;
       int pdis, pcat, pnum;
       cdiDecodeParam(param, &pnum, &pcat, &pdis);
       if (pdis == 255)
         {
-          int code = pnum;
-          int tableID = vlistptr->vars[varID].tableID;
+          const int code = pnum;
+          const int tableID = vlistptr->vars[varID].tableID;
           tableInqEntry(tableID, code, -1, NULL, NULL, units);
         }
     }
@@ -986,74 +976,6 @@ vlistDefVarMissval(int vlistID, int varID, double missval)
   vlistptr->vars[varID].missvalused = true;
 }
 
-/*
-@Function  vlistDefVarExtra
-@Title     Define extra information of a Variable
-
-@Prototype void vlistDefVarExtra(int vlistID, int varID, const char *extra)
-@Parameter
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
-    @Item  varID    Variable identifier.
-    @Item  extra    Extra information.
-
-@Description
-The function @func{vlistDefVarExtra} defines the extra information of a variable.
-
-@EndFunction
-*/
-void
-vlistDefVarExtra(int vlistID, int varID, const char *extra)
-{
-  vlistCheckVarID(__func__, vlistID, varID);
-
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  if (extra)
-    {
-      if (vlistptr->vars[varID].extra)
-        {
-          Free(vlistptr->vars[varID].extra);
-          vlistptr->vars[varID].extra = NULL;
-        }
-
-      vlistptr->vars[varID].extra = strdupx(extra);
-      reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
-    }
-}
-
-/*
-@Function  vlistInqVarExtra
-@Title     Get extra information of a Variable
-
-@Prototype void vlistInqVarExtra(int vlistID, int varID, char *extra)
-@Parameter
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
-    @Item  varID    Variable identifier.
-    @Item  extra    Returned variable extra information. The caller must allocate space for the
-                    returned string. The maximum possible length, in characters, of
-                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
-
-@Description
-The function @func{vlistInqVarExtra} returns the extra information of a variable.
-
-@Result
-@func{vlistInqVarExtra} returns the extra information of the variable to the parameter extra if available,
-otherwise the result is an empty string.
-
-@EndFunction
-*/
-void
-vlistInqVarExtra(int vlistID, int varID, char *extra)
-{
-  vlistCheckVarID(__func__, vlistID, varID);
-
-  const vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  if (vlistptr->vars[varID].extra == NULL)
-    sprintf(extra, "-");
-  else
-    strcpy(extra, vlistptr->vars[varID].extra);
-}
-
 int
 vlistInqVarValidrange(int vlistID, int varID, double *validrange)
 {
@@ -1083,50 +1005,6 @@ vlistDefVarValidrange(int vlistID, int varID, const double *validrange)
   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
 }
 
-double
-vlistInqVarScalefactor(int vlistID, int varID)
-{
-  vlistCheckVarID(__func__, vlistID, varID);
-
-  const vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return vlistptr->vars[varID].scalefactor;
-}
-
-double
-vlistInqVarAddoffset(int vlistID, int varID)
-{
-  vlistCheckVarID(__func__, vlistID, varID);
-
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return vlistptr->vars[varID].addoffset;
-}
-
-void
-vlistDefVarScalefactor(int vlistID, int varID, double scalefactor)
-{
-  vlistCheckVarID(__func__, vlistID, varID);
-
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  if (IS_NOT_EQUAL(vlistptr->vars[varID].scalefactor, scalefactor))
-    {
-      vlistptr->vars[varID].scalefactor = scalefactor;
-      reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
-    }
-}
-
-void
-vlistDefVarAddoffset(int vlistID, int varID, double addoffset)
-{
-  vlistCheckVarID(__func__, vlistID, varID);
-
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  if (IS_NOT_EQUAL(vlistptr->vars[varID].addoffset, addoffset))
-    {
-      vlistptr->vars[varID].addoffset = addoffset;
-      reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
-    }
-}
-
 void
 vlistDefVarTimetype(int vlistID, int varID, int timetype)
 {
@@ -1559,10 +1437,10 @@ vlistVarCompare(vlist_t *a, int varIDA, vlist_t *b, int varIDB)
 #define FCMPFLT(f) (IS_NOT_EQUAL((pva->f), (pvb->f)))
 #define FCMPSTR(fs) ((pva->fs) != (pvb->fs) && strcmp((pva->fs), (pvb->fs)))
 #define FCMP2(f) (namespaceResHDecode(pva->f).idx != namespaceResHDecode(pvb->f).idx)
-  int diff = FCMP(fvarID) | FCMP(mvarID) | FCMP(flag) | FCMP(param) | FCMP(datatype) | FCMP(timetype) | FCMP(tsteptype)
-             | FCMP(xyz) | FCMP2(gridID) | FCMP2(zaxisID) | FCMP2(instID) | FCMP2(modelID) | FCMP2(tableID)
-             | FCMP(missvalused) | FCMPFLT(missval) | FCMPFLT(addoffset) | FCMPFLT(scalefactor) | FCMPSTR(extra) | FCMP(comptype)
-             | FCMP(complevel) | FCMP(lvalidrange) | FCMPFLT(validrange[0]) | FCMPFLT(validrange[1]);
+  int diff = (int) FCMP(fvarID) | FCMP(mvarID) | FCMP(flag) | FCMP(param) | FCMP(datatype) | FCMP(timetype) | FCMP(tsteptype)
+             | FCMP(xyz) | FCMP2(gridID) | FCMP2(zaxisID) | FCMP2(instID) | FCMP2(modelID) | FCMP2(tableID) | FCMP(missvalused)
+             | FCMPFLT(missval) | FCMP(comptype) | FCMP(complevel)
+             | FCMP(lvalidrange) | FCMPFLT(validrange[0]) | FCMPFLT(validrange[1]);
 #undef FCMP
 #undef FCMPFLT
 #undef FCMPSTR
diff --git a/src/vlist_var_pack.c b/src/vlist_var_pack.c
index a3e4d550e2799ce5ec59945f1a6e93177b757f7f..31fe22e911f7f19762cc4498cd252d030a8a6f56 100644
--- a/src/vlist_var_pack.c
+++ b/src/vlist_var_pack.c
@@ -22,13 +22,12 @@ enum
   VLISTVAR_PACK_INT_IDX_COMPLEVEL,
   VLISTVAR_PACK_INT_IDX_NLEVS,
   VLISTVAR_PACK_INT_IDX_IORANK,
-  VLISTVAR_PACK_INT_IDX_EXTRALEN,
   vlistvarNint
 };
 
 enum
 {
-  vlistvar_ndbls = 3,
+  vlistvar_ndbls = 1,
 };
 
 int
@@ -37,11 +36,9 @@ vlistVarGetPackSize(vlist_t *p, int varID, void *context)
   var_t *var = p->vars + varID;
   int varsize
       = serializeGetSize(vlistvarNint, CDI_DATATYPE_INT, context) + serializeGetSize(vlistvar_ndbls, CDI_DATATYPE_FLT64, context);
-  if (var->extra) varsize += serializeGetSize((int) strlen(var->extra), CDI_DATATYPE_TXT, context);
-  varsize += serializeGetSize(4 * zaxisInqSize(var->zaxisID), CDI_DATATYPE_INT, context);
 
+  varsize += serializeGetSize(4 * zaxisInqSize(var->zaxisID), CDI_DATATYPE_INT, context);
   varsize += serializeKeysGetPackSize(&var->keys, context);
-
   varsize += cdiAttsGetSize(p, varID, context);
 
   return varsize;
@@ -52,7 +49,7 @@ vlistVarPack(vlist_t *p, int varID, char *buf, int size, int *position, void *co
 {
   double dtempbuf[vlistvar_ndbls];
   var_t *var = p->vars + varID;
-  int tempbuf[vlistvarNint], extralen;
+  int tempbuf[vlistvarNint];
 
   tempbuf[VLISTVAR_PACK_INT_IDX_FLAG] = var->flag;
   tempbuf[VLISTVAR_PACK_INT_IDX_GRIDID] = var->gridID;
@@ -69,13 +66,9 @@ vlistVarPack(vlist_t *p, int varID, char *buf, int size, int *position, void *co
   int nlevs = var->levinfo ? zaxisInqSize(var->zaxisID) : 0;
   tempbuf[VLISTVAR_PACK_INT_IDX_NLEVS] = nlevs;
   tempbuf[VLISTVAR_PACK_INT_IDX_IORANK] = var->iorank;
-  tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN] = extralen = var->extra ? (int) strlen(var->extra) : 0;
   dtempbuf[0] = var->missval;
-  dtempbuf[1] = var->scalefactor;
-  dtempbuf[2] = var->addoffset;
   serializePack(tempbuf, vlistvarNint, CDI_DATATYPE_INT, buf, size, position, context);
   serializePack(dtempbuf, vlistvar_ndbls, CDI_DATATYPE_FLT64, buf, size, position, context);
-  if (extralen) serializePack(var->extra, extralen, CDI_DATATYPE_TXT, buf, size, position, context);
   if (nlevs)
     {
       int *levbuf = (int *) malloc(nlevs * sizeof(int));
@@ -99,7 +92,6 @@ vlistVarUnpack(int vlistID, char *buf, int size, int *position, int originNamesp
 {
   double dtempbuf[vlistvar_ndbls];
   int tempbuf[vlistvarNint];
-  char *varname = NULL;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
   serializeUnpack(buf, size, position, tempbuf, vlistvarNint, CDI_DATATYPE_INT, context);
   serializeUnpack(buf, size, position, dtempbuf, vlistvar_ndbls, CDI_DATATYPE_FLT64, context);
@@ -111,14 +103,6 @@ vlistVarUnpack(int vlistID, char *buf, int size, int *position, int originNamesp
   int newvar = vlistDefVar(vlistID, namespaceAdaptKey(tempbuf[VLISTVAR_PACK_INT_IDX_GRIDID], originNamespace),
                            namespaceAdaptKey(tempbuf[VLISTVAR_PACK_INT_IDX_ZAXISID], originNamespace),
                            tempbuf[VLISTVAR_PACK_INT_IDX_TIMETYPE]);
-  if (tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN]) varname = (char *) Malloc((size_t) tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN] + 1);
-  if (tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN])
-    {
-      serializeUnpack(buf, size, position, varname, tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN], CDI_DATATYPE_TXT, context);
-      varname[tempbuf[VLISTVAR_PACK_INT_IDX_EXTRALEN]] = '\0';
-      vlistDefVarExtra(vlistID, newvar, varname);
-    }
-  Free(varname);
   vlistDefVarDatatype(vlistID, newvar, tempbuf[VLISTVAR_PACK_INT_IDX_DATATYPE]);
   vlistDefVarInstitut(vlistID, newvar, namespaceAdaptKey(tempbuf[VLISTVAR_PACK_INT_IDX_INSTID], originNamespace));
   vlistDefVarModel(vlistID, newvar, namespaceAdaptKey(tempbuf[VLISTVAR_PACK_INT_IDX_MODELID], originNamespace));
@@ -126,8 +110,6 @@ vlistVarUnpack(int vlistID, char *buf, int size, int *position, int originNamesp
   // FIXME: changing the table might change the param code
   vlistDefVarParam(vlistID, newvar, tempbuf[VLISTVAR_PACK_INT_IDX_PARAM]);
   if (tempbuf[VLISTVAR_PACK_INT_IDX_MISSVALUSED]) vlistDefVarMissval(vlistID, newvar, dtempbuf[0]);
-  vlistDefVarScalefactor(vlistID, newvar, dtempbuf[1]);
-  vlistDefVarAddoffset(vlistID, newvar, dtempbuf[2]);
   vlistDefVarCompType(vlistID, newvar, tempbuf[VLISTVAR_PACK_INT_IDX_COMPTYPE]);
   vlistDefVarCompLevel(vlistID, newvar, tempbuf[VLISTVAR_PACK_INT_IDX_COMPLEVEL]);
   const int nlevs = tempbuf[VLISTVAR_PACK_INT_IDX_NLEVS];
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6839dda3748b97c125f272fdcdd4d13bd901ebdc..bdcc8138ba45edf110a4e60f62b9e657a7340051 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -47,11 +47,11 @@ test_byteswap_SOURCES = test_byteswap.c
 #
 AM_CFLAGS = $(PPM_CORE_CFLAGS) $(YAXT_CFLAGS) $(MPI_C_INCLUDE)
 if USE_MPI
-pio_write_LDADD = ../src/libcdipio.la $(LIBRT) $(MPI_C_LIB)
-pio_write_deco2d_LDADD = ../src/libcdipio.la $(LIBRT) $(MPI_C_LIB)
+pio_write_LDADD = ../src/libcdipio.la ../src/libcdi.la $(PPM_CORE_LIBS) $(YAXT_LIBS) $(MPI_C_LIB)
+pio_write_deco2d_LDADD = ../src/libcdipio.la ../src/libcdi.la $(PPM_CORE_LIBS) $(YAXT_LIBS) $(MPI_C_LIB)
 TESTS +=  test_resource_copy_mpi_run
 check_PROGRAMS += test_resource_copy_mpi
-test_resource_copy_mpi_LDADD = ../src/libcdipio.la 
+test_resource_copy_mpi_LDADD = ../src/libcdipio.la ../src/libcdi.la
 test_resource_copy_mpi_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \
 	-DMPI_MARSHALLING
 else